aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/0344-Fix-item-duplication-and-teleport-issues.patch
diff options
context:
space:
mode:
authorOwen1212055 <[email protected]>2024-10-23 10:04:01 -0400
committerOwen1212055 <[email protected]>2024-10-23 10:04:01 -0400
commitaf125d26a94147ff40555819d5a9687d24b65d50 (patch)
tree12c00f31e82906203d1d1885b6023f7142f02ed4 /patches/server/0344-Fix-item-duplication-and-teleport-issues.patch
parentaa37f7250d168e94318e975d3c6d1002e7b82c29 (diff)
downloadPaper-af125d26a94147ff40555819d5a9687d24b65d50.tar.gz
Paper-af125d26a94147ff40555819d5a9687d24b65d50.zip
Patch
Diffstat (limited to 'patches/server/0344-Fix-item-duplication-and-teleport-issues.patch')
-rw-r--r--patches/server/0344-Fix-item-duplication-and-teleport-issues.patch154
1 files changed, 154 insertions, 0 deletions
diff --git a/patches/server/0344-Fix-item-duplication-and-teleport-issues.patch b/patches/server/0344-Fix-item-duplication-and-teleport-issues.patch
new file mode 100644
index 0000000000..1e7965da69
--- /dev/null
+++ b/patches/server/0344-Fix-item-duplication-and-teleport-issues.patch
@@ -0,0 +1,154 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Aikar <[email protected]>
+Date: Sat, 25 Apr 2020 06:46:35 -0400
+Subject: [PATCH] Fix item duplication and teleport issues
+
+This notably fixes the newest "Donkey Dupe", but also fixes a lot
+of dupe bugs in general around nether portals and entity world transfer
+
+We also fix item duplication generically by anytime we clone an item
+to drop it on the ground, destroy the source item.
+
+This avoid an itemstack ever existing twice in the world state pre
+clean up stage.
+
+So even if something NEW comes up, it would be impossible to drop the
+same item twice because the source was destroyed.
+
+diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
+index 5b8e264098f1b713de15f714bae59d3efda365cf..4faba83eb73e0d313e9131794962b727f7628a50 100644
+--- a/src/main/java/net/minecraft/world/entity/Entity.java
++++ b/src/main/java/net/minecraft/world/entity/Entity.java
+@@ -2630,11 +2630,12 @@ 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.asBukkitCopy(stack));
++ ((net.minecraft.world.entity.LivingEntity) this).drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack)); // Paper - mirror so we can destroy it later
+ return null;
+ }
+ // CraftBukkit end
+ ItemEntity entityitem = new ItemEntity(world, this.getX(), this.getY() + (double) yOffset, this.getZ(), stack);
++ stack.setCount(0); // Paper - destroy this item - if this ever leaks due to game bugs, ensure it doesn't dupe
+
+ entityitem.setDefaultPickUpDelay();
+ // CraftBukkit start
+@@ -3462,6 +3463,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
+ public Entity teleport(TeleportTransition teleportTarget) {
+ Level world = this.level();
+
++ // Paper start - Fix item duplication and teleport issues
++ if (!this.isAlive() || !this.valid) {
++ LOGGER.warn("Illegal Entity Teleport " + this + " to " + teleportTarget.newLevel() + ":" + teleportTarget.pos(), new Throwable());
++ return null;
++ }
++ // Paper end - Fix item duplication and teleport issues
+ if (world instanceof ServerLevel worldserver) {
+ if (!this.isRemoved()) {
+ // CraftBukkit start
+@@ -3550,6 +3557,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
+ gameprofilerfiller.pop();
+ return null;
+ } else {
++ // Paper start - Fix item duplication and teleport issues
++ if (this instanceof Leashable leashable) {
++ leashable.dropLeash(true, true); // Paper drop lead
++ }
++ // Paper end - Fix item duplication and teleport issues
+ entity.restoreFrom(this);
+ this.removeAfterChangingDimensions();
+ // CraftBukkit start - Forward the CraftEntity to the new entity
+@@ -3662,6 +3674,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
+ }
+
+ public boolean canTeleport(Level from, Level to) {
++ if (!this.isAlive() || !this.valid) return false; // Paper - Fix item duplication and teleport issues
+ if (from.dimension() == Level.END && to.dimension() == Level.OVERWORLD) {
+ Iterator iterator = this.getPassengers().iterator();
+
+diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
+index 68e5f6f7013d6a014b9014d945cf3f7dc7a37cb2..65909e0a8f8b68f9a4dacefda9069c8263a96ada 100644
+--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
+@@ -1767,9 +1767,9 @@ public abstract class LivingEntity extends Entity implements Attackable {
+ // Paper start
+ org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(worldserver, damageSource);
+ if (deathEvent == null || !deathEvent.isCancelled()) {
+- if (this.deathScore >= 0 && entityliving != null) {
+- entityliving.awardKillScore(this, this.deathScore, damageSource);
+- }
++ // if (this.deathScore >= 0 && entityliving != null) { // Paper - Fix item duplication and teleport issues; moved to be run earlier in #dropAllDeathLoot before destroying the drop items in CraftEventFactory#callEntityDeathEvent
++ // entityliving.awardKillScore(this, this.deathScore, damageSource);
++ // }
+ // Paper start - clear equipment if event is not cancelled
+ if (this instanceof Mob) {
+ for (EquipmentSlot slot : this.clearedEquipmentSlots) {
+@@ -1863,8 +1863,13 @@ public abstract class LivingEntity extends Entity implements Attackable {
+ this.dropCustomDeathLoot(world, damageSource, flag);
+ this.clearEquipmentSlots = prev; // Paper
+ }
+- // CraftBukkit start - Call death event
+- org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, damageSource, this.drops); // Paper
++ // CraftBukkit start - Call death event // Paper start - call advancement triggers with correct entity equipment
++ org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, damageSource, this.drops, () -> {
++ final LivingEntity entityliving = this.getKillCredit();
++ if (this.deathScore >= 0 && entityliving != null) {
++ entityliving.awardKillScore(this, this.deathScore, damageSource);
++ }
++ }); // Paper end
+ this.postDeathDropItems(deathEvent); // Paper
+ this.drops = new ArrayList<>();
+ // CraftBukkit end
+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 e20565cf256aacd012a1722c5ebbf9016bc82e42..59fbfe8de2dc5ec020dd61a5e446b0b6f67d76e4 100644
+--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
++++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
+@@ -633,7 +633,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.asBukkitCopy(itemstack)); // CraftBukkit - add to drops
++ 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.handItems.set(i, ItemStack.EMPTY);
+ }
+ }
+@@ -641,7 +641,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.asBukkitCopy(itemstack)); // CraftBukkit - add to drops
++ 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.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 41f23ce732b6e90828b1bbda7f4b3470cd462c4a..0b9c96105bea9a0d1af17b7ecf4479d3596faa80 100644
+--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+@@ -903,6 +903,11 @@ public class CraftEventFactory {
+ }
+
+ public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, DamageSource damageSource, List<org.bukkit.inventory.ItemStack> drops) {
++ // 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) {
++ // Paper end
+ CraftLivingEntity entity = (CraftLivingEntity) victim.getBukkitEntity();
+ CraftDamageSource bukkitDamageSource = new CraftDamageSource(damageSource);
+ CraftWorld world = (CraftWorld) entity.getWorld();
+@@ -917,11 +922,13 @@ public class CraftEventFactory {
+ playDeathSound(victim, event);
+ // Paper end
+ victim.expToDrop = event.getDroppedExp();
++ lootCheck.run(); // Paper - advancement triggers before destroying items
+
+ for (org.bukkit.inventory.ItemStack stack : event.getDrops()) {
+ if (stack == null || stack.getType() == Material.AIR || stack.getAmount() == 0) continue;
+
+- world.dropItem(entity.getLocation(), stack);
++ world.dropItem(entity.getLocation(), stack); // Paper - note: dropItem already clones due to this being bukkit -> NMS
++ 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;