2023-12-03 01:35:10 +00:00
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
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
2024-01-21 18:37:09 +00:00
index 575681586667933e7f26bb16f7d2aa7c73188cde..38df47d282713522b3c5784a562ff09e3151fb27 100644
2023-12-03 01:35:10 +00:00
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
2023-12-06 18:18:53 +00:00
@@ -944,22 +944,20 @@ public class ServerPlayer extends Player {
2023-12-03 01:35:10 +00:00
if (this.isRemoved()) {
return;
}
- java.util.List<org.bukkit.inventory.ItemStack> loot = new java.util.ArrayList<org.bukkit.inventory.ItemStack>(this.getInventory().getContainerSize());
2024-01-13 15:35:59 +00:00
+ List<DefaultDrop> loot = new java.util.ArrayList<>(this.getInventory().getContainerSize()); // Paper - Restore vanilla drops behavior
2023-12-03 01:35:10 +00:00
boolean keepInventory = this.level().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) || this.isSpectator();
if (!keepInventory) {
for (ItemStack item : this.getInventory().getContents()) {
if (!item.isEmpty() && !EnchantmentHelper.hasVanishingCurse(item)) {
- loot.add(CraftItemStack.asCraftMirror(item));
2024-01-13 15:35:59 +00:00
+ 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)
2023-12-03 01:35:10 +00:00
}
}
}
2024-01-18 17:52:00 +00:00
if (this.shouldDropLoot() && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { // Paper - fix player loottables running when mob loot gamerule is false
2023-12-03 01:35:10 +00:00
// SPIGOT-5071: manually add player loot tables (SPIGOT-5195 - ignores keepInventory rule)
this.dropFromLootTable(damageSource, this.lastHurtByPlayerTime > 0);
- for (org.bukkit.inventory.ItemStack item : this.drops) {
- loot.add(item);
- }
+ loot.addAll(this.drops); // Paper
this.drops.clear(); // SPIGOT-5188: make sure to clear
2024-01-18 17:52:00 +00:00
} // Paper - fix player loottables running when mob loot gamerule is false
2023-12-03 01:35:10 +00:00
2023-12-29 19:57:32 +00:00
@@ -2442,8 +2440,8 @@ public class ServerPlayer extends Player {
2023-12-19 04:57:49 +00:00
}
@Override
- public ItemEntity drop(ItemStack stack, boolean throwRandomly, boolean retainOwnership) {
- ItemEntity entityitem = super.drop(stack, throwRandomly, retainOwnership);
2024-01-13 15:35:59 +00:00
+ public ItemEntity drop(ItemStack stack, boolean throwRandomly, boolean retainOwnership, boolean callDropEvent) { // Paper - Restore vanilla drops behavior; override method with most params
+ ItemEntity entityitem = super.drop(stack, throwRandomly, retainOwnership, callDropEvent); // Paper - Restore vanilla drops behavior; override method with most params
2023-12-19 04:57:49 +00:00
if (entityitem == null) {
return null;
2023-12-03 01:35:10 +00:00
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
2024-01-21 18:37:09 +00:00
index 4fdc55b78c4212603bd57a292c72d89c73d28871..1a19f18b5d4c42ac07e7e4f305e140954dea481b 100644
2023-12-03 01:35:10 +00:00
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
2024-01-21 16:39:05 +00:00
@@ -2702,6 +2702,25 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
2023-12-03 01:35:10 +00:00
@Nullable
public ItemEntity spawnAtLocation(ItemStack stack, float yOffset) {
2024-01-13 15:35:59 +00:00
+ // Paper start - Restore vanilla drops behavior
2023-12-03 01:35:10 +00:00
+ 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.util.CraftMagicNumbers.getItem(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) {
2024-01-13 15:35:59 +00:00
+ // Paper end - Restore vanilla drops behavior
2023-12-03 01:35:10 +00:00
if (stack.isEmpty()) {
return null;
} else if (this.level().isClientSide) {
2024-01-21 16:39:05 +00:00
@@ -2709,14 +2728,21 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
2023-12-03 01:35:10 +00:00
} 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
2024-01-13 15:35:59 +00:00
+ // Paper start - Restore vanilla drops behavior
2023-12-03 01:35:10 +00:00
+ ((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);
+ }));
2024-01-13 15:35:59 +00:00
+ // Paper end - Restore vanilla drops behavior
2023-12-03 01:35:10 +00:00
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)
2024-01-18 14:56:25 +00:00
// Paper start - Call EntityDropItemEvent
2023-12-03 01:35:10 +00:00
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
2024-01-21 18:37:09 +00:00
index 68e1ef67e58ef348d35dfc3b3e890336d4cb2108..5d27e1d3f15839663d89d198babe3be94cfd3f07 100644
2023-12-03 01:35:10 +00:00
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
2023-12-06 18:18:53 +00:00
@@ -254,7 +254,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
2023-12-03 01:35:10 +00:00
// CraftBukkit start
public int expToDrop;
public boolean forceDrops;
- public ArrayList<org.bukkit.inventory.ItemStack> drops = new ArrayList<org.bukkit.inventory.ItemStack>();
2024-01-13 15:35:59 +00:00
+ public ArrayList<DefaultDrop> drops = new ArrayList<>(); // Paper - Restore vanilla drops behavior
2023-12-03 01:35:10 +00:00
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
2024-01-19 16:54:05 +00:00
index 45906d273e6d6ec20cf44b4d07efdac68752ee9b..ac9eaeaf7df1e84ee588f371628c0a10784d50bc 100644
2023-12-03 01:35:10 +00:00
--- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
+++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java
2023-12-28 00:33:05 +00:00
@@ -534,10 +534,10 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob
2023-12-03 01:35:10 +00:00
@Override
protected void dropCustomDeathLoot(DamageSource source, int lootingMultiplier, boolean allowDrops) {
super.dropCustomDeathLoot(source, lootingMultiplier, allowDrops);
- ItemEntity entityitem = this.spawnAtLocation((ItemLike) Items.NETHER_STAR);
2024-01-13 15:35:59 +00:00
+ 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
2023-12-03 01:35:10 +00:00
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
2024-01-21 18:37:09 +00:00
index 92b4eecf7b8ce07334256a216d9caf241fa5363b..94a30a0c1266bf919d1dc4ca2b19489edd54a7fa 100644
2023-12-03 01:35:10 +00:00
--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
+++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
2023-12-06 18:18:53 +00:00
@@ -610,7 +610,7 @@ public class ArmorStand extends LivingEntity {
2023-12-03 01:35:10 +00:00
itemstack.setHoverName(this.getCustomName());
}
- this.drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops
2024-01-13 15:35:59 +00:00
+ this.drops.add(new DefaultDrop(itemstack, stack -> Block.popResource(this.level(), this.blockPosition(), stack))); // CraftBukkit - add to drops // Paper - Restore vanilla drops behavior
2023-12-03 01:35:10 +00:00
return this.brokenByAnything(damageSource); // Paper
}
2023-12-06 18:18:53 +00:00
@@ -624,7 +624,7 @@ public class ArmorStand extends LivingEntity {
2023-12-03 01:35:10 +00:00
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
2024-01-13 15:35:59 +00:00
+ 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
2023-12-03 01:35:10 +00:00
this.handItems.set(i, ItemStack.EMPTY);
}
}
2023-12-06 18:18:53 +00:00
@@ -632,7 +632,7 @@ public class ArmorStand extends LivingEntity {
2023-12-03 01:35:10 +00:00
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
2024-01-13 15:35:59 +00:00
+ 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
2023-12-03 01:35:10 +00:00
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
2024-01-21 18:37:09 +00:00
index b3b1211d20c6d28a14c656159a1e345f8406a093..4f4d76065edff508ff996d507e955f5d270450ac 100644
2023-12-03 01:35:10 +00:00
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
2024-01-21 11:11:43 +00:00
@@ -937,17 +937,21 @@ public class CraftEventFactory {
2023-12-03 01:35:10 +00:00
}
public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim) {
- return CraftEventFactory.callEntityDeathEvent(victim, new ArrayList<org.bukkit.inventory.ItemStack>(0));
2024-01-13 15:35:59 +00:00
+ return CraftEventFactory.callEntityDeathEvent(victim, new ArrayList<>(0)); // Paper - Restore vanilla drops behavior
2023-12-03 01:35:10 +00:00
}
- public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, List<org.bukkit.inventory.ItemStack> drops) {
2024-01-13 15:35:59 +00:00
+ public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, List<Entity.DefaultDrop> drops) { // Paper - Restore vanilla drops behavior
2023-12-03 01:35:10 +00:00
// Paper start
return CraftEventFactory.callEntityDeathEvent(victim, drops, com.google.common.util.concurrent.Runnables.doNothing());
}
- public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, List<org.bukkit.inventory.ItemStack> drops, Runnable lootCheck) {
+ private static java.util.function.Function<org.bukkit.inventory.ItemStack, Entity.DefaultDrop> FROM_FUNCTION = stack -> {
+ if (stack == null) return null;
2024-01-14 09:46:04 +00:00
+ return new Entity.DefaultDrop(CraftItemType.bukkitToMinecraft(stack.getType()), stack, null);
2023-12-03 01:35:10 +00:00
+ };
+ public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, List<Entity.DefaultDrop> drops, Runnable lootCheck) { // Paper
// Paper end
CraftLivingEntity entity = (CraftLivingEntity) victim.getBukkitEntity();
- EntityDeathEvent event = new EntityDeathEvent(entity, drops, victim.getExpReward());
2024-01-13 15:35:59 +00:00
+ EntityDeathEvent event = new EntityDeathEvent(entity, new io.papermc.paper.util.TransformingRandomAccessList<>(drops, Entity.DefaultDrop::stack, FROM_FUNCTION), victim.getExpReward()); // Paper - Restore vanilla drops behavior
2023-12-03 01:35:10 +00:00
populateFields(victim, event); // Paper - make cancellable
CraftWorld world = (CraftWorld) entity.getWorld();
Bukkit.getServer().getPluginManager().callEvent(event);
2024-01-21 11:11:43 +00:00
@@ -961,19 +965,23 @@ public class CraftEventFactory {
2023-12-03 01:35:10 +00:00
victim.expToDrop = event.getDroppedExp();
lootCheck.run(); // Paper - advancement triggers before destroying items
- for (org.bukkit.inventory.ItemStack stack : event.getDrops()) {
2024-01-13 15:35:59 +00:00
+ // Paper start - Restore vanilla drops behavior
2023-12-03 01:35:10 +00:00
+ for (Entity.DefaultDrop drop : drops) {
2023-12-10 18:33:36 +00:00
+ if (drop == null) continue;;
2023-12-03 01:35:10 +00:00
+ final org.bukkit.inventory.ItemStack stack = drop.stack();
2024-01-13 15:35:59 +00:00
+ // Paper end - Restore vanilla drops behavior
2023-12-10 18:33:36 +00:00
if (stack == null || stack.getType() == Material.AIR || stack.getAmount() == 0) continue;
2023-12-03 01:35:10 +00:00
- world.dropItem(entity.getLocation(), stack); // Paper - note: dropItem already clones due to this being bukkit -> NMS
2024-01-13 15:35:59 +00:00
+ drop.runConsumer(world, entity.getLocation()); // Paper - Restore vanilla drops behavior
2023-12-03 01:35:10 +00:00
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;
}
2023-12-29 20:28:58 +00:00
- public static PlayerDeathEvent callPlayerDeathEvent(ServerPlayer victim, List<org.bukkit.inventory.ItemStack> drops, net.kyori.adventure.text.Component deathMessage, boolean keepInventory) { // Paper - Adventure
2024-01-13 15:35:59 +00:00
+ public static PlayerDeathEvent callPlayerDeathEvent(ServerPlayer victim, List<Entity.DefaultDrop> drops, net.kyori.adventure.text.Component deathMessage, boolean keepInventory) { // Paper - Adventure & Restore vanilla drops behavior
2023-12-03 01:35:10 +00:00
CraftPlayer entity = victim.getBukkitEntity();
2023-12-29 20:28:58 +00:00
- PlayerDeathEvent event = new PlayerDeathEvent(entity, drops, victim.getExpReward(), 0, deathMessage);
2024-01-13 15:35:59 +00:00
+ PlayerDeathEvent event = new PlayerDeathEvent(entity, new io.papermc.paper.util.TransformingRandomAccessList<>(drops, Entity.DefaultDrop::stack, FROM_FUNCTION), victim.getExpReward(), 0, deathMessage); // Paper - Restore vanilla drops behavior
2023-12-03 01:35:10 +00:00
event.setKeepInventory(keepInventory);
event.setKeepLevel(victim.keepLevel); // SPIGOT-2222: pre-set keepLevel
populateFields(victim, event); // Paper - make cancellable
2024-01-21 11:11:43 +00:00
@@ -992,10 +1000,14 @@ public class CraftEventFactory {
2023-12-03 01:35:10 +00:00
victim.expToDrop = event.getDroppedExp();
victim.newExp = event.getNewExp();
- for (org.bukkit.inventory.ItemStack stack : event.getDrops()) {
2024-01-13 15:35:59 +00:00
+ // Paper start - Restore vanilla drops behavior
2023-12-03 01:35:10 +00:00
+ for (Entity.DefaultDrop drop : drops) {
2023-12-10 18:33:36 +00:00
+ if (drop == null) continue;
2023-12-03 01:35:10 +00:00
+ final org.bukkit.inventory.ItemStack stack = drop.stack();
2024-01-13 15:35:59 +00:00
+ // Paper end - Restore vanilla drops behavior
2023-12-10 18:33:36 +00:00
if (stack == null || stack.getType() == Material.AIR) continue;
2023-12-03 01:35:10 +00:00
- world.dropItem(entity.getLocation(), stack);
2024-01-13 15:35:59 +00:00
+ drop.runConsumer(world, entity.getLocation()); // Paper - Restore vanilla drops behavior
2023-12-03 01:35:10 +00:00
}
return event;