From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Alphaesia Date: Fri, 23 Apr 2021 09:57:56 +1200 Subject: [PATCH] Fix duplicating /give items on item drop cancel Fixes SPIGOT-2942 (Give command fires PlayerDropItemEvent, cancelling it causes item duplication). For every stack of items to give, /give puts the item stack straight into the player's inventory. However, it also summons a "fake item" at the player's location. When the PlayerDropItemEvent for this fake item is cancelled, the server attempts to put the item back into the player's inventory. The result is that the fake item, which is never meant to be obtained, is combined with the real items injected directly into the player's inventory. This means more items than the amount specified in /give are given to the player - one for every stack of items given. (e.g. /give @s dirt 1 gives you 2 dirt). While this isn't a big issue for general building usage, it can affect e.g. adventure maps where the number of items the player receives is important (and you want to restrict the player from throwing items). If there are any overflow items that didn't make it into the inventory (insufficient space), those items are dropped as a real item instead of a fake one. While cancelling this drop would also result in the server attempting to put those items into the inventory, since it is full this has no effect. Just ignoring cancellation of the PlayerDropItemEvent seems like the cleanest and least intrusive way to fix it. diff --git a/src/main/java/net/minecraft/server/commands/CommandGive.java b/src/main/java/net/minecraft/server/commands/CommandGive.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/commands/CommandGive.java +++ b/src/main/java/net/minecraft/server/commands/CommandGive.java @@ -0,0 +0,0 @@ public class CommandGive { if (flag && itemstack.isEmpty()) { itemstack.setCount(1); - entityitem = entityplayer.drop(itemstack, false); + entityitem = entityplayer.drop(itemstack, false, false, true); // Paper - Fix duplicating /give items on item drop cancel if (entityitem != null) { entityitem.s(); } diff --git a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/player/EntityHuman.java +++ b/src/main/java/net/minecraft/world/entity/player/EntityHuman.java @@ -0,0 +0,0 @@ public abstract class EntityHuman extends EntityLiving { @Nullable public EntityItem a(ItemStack itemstack, boolean flag, boolean flag1) { + // Paper start - Fix duplicating /give items on item drop cancel + return this.drop(itemstack, flag, flag1, false); + } + + @Nullable + public EntityItem drop(ItemStack itemstack, boolean flag, boolean flag1, boolean alwaysSucceed) { + // Paper end if (itemstack.isEmpty()) { return null; } else { @@ -0,0 +0,0 @@ public abstract class EntityHuman extends EntityLiving { PlayerDropItemEvent event = new PlayerDropItemEvent(player, drop); this.world.getServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { + if (event.isCancelled() && !alwaysSucceed) { // Paper - Fix duplicating /give items on item drop cancel org.bukkit.inventory.ItemStack cur = player.getInventory().getItemInHand(); if (flag1 && (cur == null || cur.getAmount() == 0)) { // The complete stack was dropped