aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/0404-Fix-numerous-item-duplication-issues-and-teleport-is.patch
diff options
context:
space:
mode:
authorNassim Jahnke <[email protected]>2022-09-12 13:31:45 +0200
committerNassim Jahnke <[email protected]>2022-09-12 13:31:45 +0200
commitef0e5a642d33ac62f070c45a61cb42647b2744cd (patch)
tree70dff1b36e6d4306f059b3c8e335527af00adf73 /patches/server/0404-Fix-numerous-item-duplication-issues-and-teleport-is.patch
parent51183af967aafb3d57dc19421da1bcb0aea9d3d2 (diff)
downloadPaper-ef0e5a642d33ac62f070c45a61cb42647b2744cd.tar.gz
Paper-ef0e5a642d33ac62f070c45a61cb42647b2744cd.zip
Updated Upstream (Bukkit/CraftBukkit/Spigot)
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: 9ae3f10f SPIGOT-3842: Add Player#fireworkBoost() and expand Firework API 48c0c547 PR-786: Add methods to get sounds from entities CraftBukkit Changes: 5cc9c022a SPIGOT-7152: Handle hand item changing during air interact event 4ffa1acf6 SPIGOT-7154: Players get kicked when interacting with a conversation 4daa21123 SPIGOT-3842: Add Player#fireworkBoost() and expand Firework API e5d6a9bbf PR-1100: Add methods to get sounds from entities b7e9f1c8b SPIGOT-7146: Reduce use of Material switch in ItemMeta Spigot Changes: 4c157bb4 Rebuild patches
Diffstat (limited to 'patches/server/0404-Fix-numerous-item-duplication-issues-and-teleport-is.patch')
-rw-r--r--patches/server/0404-Fix-numerous-item-duplication-issues-and-teleport-is.patch167
1 files changed, 167 insertions, 0 deletions
diff --git a/patches/server/0404-Fix-numerous-item-duplication-issues-and-teleport-is.patch b/patches/server/0404-Fix-numerous-item-duplication-issues-and-teleport-is.patch
new file mode 100644
index 0000000000..2cb660b24c
--- /dev/null
+++ b/patches/server/0404-Fix-numerous-item-duplication-issues-and-teleport-is.patch
@@ -0,0 +1,167 @@
+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 numerous item duplication issues 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 69aef07129201308ae275434b754977c6ece5dd7..8bdcf56a5a1c29f78e10f66de5adf5a3786ac092 100644
+--- a/src/main/java/net/minecraft/world/entity/Entity.java
++++ b/src/main/java/net/minecraft/world/entity/Entity.java
+@@ -2240,11 +2240,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
+ } 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(this.level, this.getX(), this.getY() + (double) yOffset, this.getZ(), stack);
++ ItemEntity entityitem = new ItemEntity(this.level, this.getX(), this.getY() + (double) yOffset, this.getZ(), stack.copy()); // Paper - clone 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();
+ // CraftBukkit start
+@@ -3008,6 +3009,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
+ @Nullable
+ public Entity teleportTo(ServerLevel worldserver, PositionImpl location) {
+ // CraftBukkit end
++ // Paper start - fix bad state entities causing dupes
++ if (!isAlive() || !valid) {
++ LOGGER.warn("Illegal Entity Teleport " + this + " to " + worldserver + ":" + location, new Throwable());
++ return null;
++ }
++ // Paper end
+ if (this.level instanceof ServerLevel && !this.isRemoved()) {
+ this.level.getProfiler().push("changeDimension");
+ // CraftBukkit start
+@@ -3034,6 +3041,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
+ // CraftBukkit end
+
+ this.level.getProfiler().popPush("reloading");
++ // Paper start - Change lead drop timing to prevent dupe
++ if (this instanceof Mob) {
++ ((Mob) this).dropLeash(true, true); // Paper drop lead
++ }
++ // Paper end
+ Entity entity = this.getType().create(worldserver);
+
+ if (entity != null) {
+@@ -3047,10 +3059,6 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
+ // CraftBukkit start - Forward the CraftEntity to the new entity
+ this.getBukkitEntity().setHandle(entity);
+ entity.bukkitEntity = this.getBukkitEntity();
+-
+- if (this instanceof Mob) {
+- ((Mob) this).dropLeash(true, false); // Unleash to prevent duping of leads.
+- }
+ // CraftBukkit end
+ }
+
+@@ -3171,7 +3179,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
+ }
+
+ public boolean canChangeDimensions() {
+- return true;
++ return isAlive() && valid; // Paper
+ }
+
+ public float getBlockExplosionResistance(Explosion explosion, BlockGetter world, BlockPos pos, BlockState blockState, FluidState fluidState, float max) {
+diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
+index e3d686ea473c1bd38af9ed181020110ee3d94f64..37d51104a7d38c2d16ae38a9adcbe37597c94fe2 100644
+--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
+@@ -1643,9 +1643,9 @@ public abstract class LivingEntity extends Entity {
+ // Paper start
+ org.bukkit.event.entity.EntityDeathEvent deathEvent = this.dropAllDeathLoot(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 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) {
+@@ -1743,8 +1743,13 @@ public abstract class LivingEntity extends Entity {
+ this.dropCustomDeathLoot(source, i, flag);
+ this.clearEquipmentSlots = prev; // Paper
+ }
+- // CraftBukkit start - Call death event
+- org.bukkit.event.entity.EntityDeathEvent deathEvent = CraftEventFactory.callEntityDeathEvent(this, 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, this.drops, () -> {
++ final LivingEntity entityliving = this.getKillCredit();
++ if (this.deathScore >= 0 && entityliving != null) {
++ entityliving.awardKillScore(this, this.deathScore, source);
++ }
++ }); // 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 cd54fa8f7bbcb6036e90f4ef7cdc01d7af835a13..808e564789d826c1778c053ab91038e3d4d81b7f 100644
+--- a/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
++++ b/src/main/java/net/minecraft/world/entity/decoration/ArmorStand.java
+@@ -608,7 +608,7 @@ public class ArmorStand extends LivingEntity {
+ for (i = 0; i < this.handItems.size(); ++i) {
+ itemstack = (ItemStack) this.handItems.get(i);
+ if (!itemstack.isEmpty()) {
+- drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops
++ 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);
+ }
+ }
+@@ -616,7 +616,7 @@ public class ArmorStand extends LivingEntity {
+ for (i = 0; i < this.armorItems.size(); ++i) {
+ itemstack = (ItemStack) this.armorItems.get(i);
+ if (!itemstack.isEmpty()) {
+- drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack)); // CraftBukkit - add to drops
++ 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 3aa82c7d26ef9fed3d4b670ac330204b55609396..22da112f45ddb20d113550eae67ac08eb2fcb727 100644
+--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+@@ -819,6 +819,11 @@ public class CraftEventFactory {
+ }
+
+ public static EntityDeathEvent callEntityDeathEvent(net.minecraft.world.entity.LivingEntity victim, List<org.bukkit.inventory.ItemStack> drops) {
++ // 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) {
++ // Paper end
+ CraftLivingEntity entity = (CraftLivingEntity) victim.getBukkitEntity();
+ EntityDeathEvent event = new EntityDeathEvent(entity, drops, victim.getExpReward());
+ populateFields(victim, event); // Paper - make cancellable
+@@ -832,11 +837,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;