summaryrefslogtreecommitdiffhomepage
path: root/patches/unapplied/server/0933-Fix-inconsistencies-in-dispense-events-regarding-sta.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/unapplied/server/0933-Fix-inconsistencies-in-dispense-events-regarding-sta.patch')
-rw-r--r--patches/unapplied/server/0933-Fix-inconsistencies-in-dispense-events-regarding-sta.patch525
1 files changed, 525 insertions, 0 deletions
diff --git a/patches/unapplied/server/0933-Fix-inconsistencies-in-dispense-events-regarding-sta.patch b/patches/unapplied/server/0933-Fix-inconsistencies-in-dispense-events-regarding-sta.patch
new file mode 100644
index 0000000000..01f0b970d7
--- /dev/null
+++ b/patches/unapplied/server/0933-Fix-inconsistencies-in-dispense-events-regarding-sta.patch
@@ -0,0 +1,525 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jake Potrebic <[email protected]>
+Date: Sun, 11 Dec 2022 23:47:22 -0800
+Subject: [PATCH] Fix inconsistencies in dispense events regarding stack size
+
+The javadocs for BlockDispenseEvent suggest the ItemStack is a single
+item which is being dispensed. Before this fix, sometimes it was the whole
+stack before a single item had been taken. This fixes that so the stack size
+is always 1.
+
+diff --git a/src/main/java/net/minecraft/core/dispenser/AbstractProjectileDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/AbstractProjectileDispenseBehavior.java
+index 2542cf94ac76871f4ff02c3524e8606c96f50cc7..309ad5a1da6b3a297d5526cd9247359ac5f49406 100644
+--- a/src/main/java/net/minecraft/core/dispenser/AbstractProjectileDispenseBehavior.java
++++ b/src/main/java/net/minecraft/core/dispenser/AbstractProjectileDispenseBehavior.java
+@@ -28,7 +28,7 @@ public abstract class AbstractProjectileDispenseBehavior extends DefaultDispense
+
+ // CraftBukkit start
+ // iprojectile.shoot((double) enumdirection.getStepX(), (double) ((float) enumdirection.getStepY() + 0.1F), (double) enumdirection.getStepZ(), this.getPower(), this.getUncertainty());
+- ItemStack itemstack1 = stack.split(1);
++ ItemStack itemstack1 = stack.copyWithCount(1); // Paper - shrink below and single item in event
+ org.bukkit.block.Block block = worldserver.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+@@ -38,12 +38,13 @@ public abstract class AbstractProjectileDispenseBehavior extends DefaultDispense
+ }
+
+ if (event.isCancelled()) {
+- stack.grow(1);
++ // stack.grow(1); // Paper - shrink below
+ return stack;
+ }
+
++ boolean shrink = true; // Paper
+ if (!event.getItem().equals(craftItem)) {
+- stack.grow(1);
++ shrink = false; // Paper - shrink below
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+@@ -57,7 +58,7 @@ public abstract class AbstractProjectileDispenseBehavior extends DefaultDispense
+ ((Entity) iprojectile).projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource((DispenserBlockEntity) pointer.getEntity());
+ // CraftBukkit end
+ worldserver.addFreshEntity(iprojectile);
+- // itemstack.shrink(1); // CraftBukkit - Handled during event processing
++ if (shrink) stack.shrink(1); // Paper - actually handle here
+ return stack;
+ }
+
+diff --git a/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
+index eb55015f4c867fbf08430288744f58a3b9d86e89..958134519befadc27a5b647caf64acf272ee2db4 100644
+--- a/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
++++ b/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
+@@ -53,7 +53,7 @@ public class BoatDispenseItemBehavior extends DefaultDispenseItemBehavior {
+
+ // EntityBoat entityboat = new EntityBoat(worldserver, d0, d1 + d3, d2);
+ // CraftBukkit start
+- ItemStack itemstack1 = stack.split(1);
++ ItemStack itemstack1 = stack.copyWithCount(1); // Paper - shrink at end and single item in event
+ org.bukkit.block.Block block = worldserver.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+@@ -63,12 +63,13 @@ public class BoatDispenseItemBehavior extends DefaultDispenseItemBehavior {
+ }
+
+ if (event.isCancelled()) {
+- stack.grow(1);
++ // stack.grow(1); // Paper - shrink below
+ return stack;
+ }
+
++ boolean shrink = true; // Paper
+ if (!event.getItem().equals(craftItem)) {
+- stack.grow(1);
++ shrink = false; // Paper - shrink below
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+@@ -83,8 +84,7 @@ public class BoatDispenseItemBehavior extends DefaultDispenseItemBehavior {
+
+ ((Boat) object).setVariant(this.type);
+ ((Boat) object).setYRot(enumdirection.toYRot());
+- if (!worldserver.addFreshEntity((Entity) object)) stack.grow(1); // CraftBukkit
+- // itemstack.shrink(1); // CraftBukkit - handled during event processing
++ if (worldserver.addFreshEntity((Entity) object) && shrink) stack.shrink(1); // Paper - if entity add was successful and supposed to shrink
+ return stack;
+ }
+
+diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
+index 46accf082b5e440ec743583bb0609c013234cb06..88d18d18d69876c98e199acb647c6cca9448d55d 100644
+--- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
++++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
+@@ -218,7 +218,7 @@ public interface DispenseItemBehavior {
+
+ // CraftBukkit start
+ ServerLevel worldserver = pointer.getLevel();
+- ItemStack itemstack1 = stack.split(1);
++ ItemStack itemstack1 = stack.copyWithCount(1); // Paper - shrink below and single item in event
+ org.bukkit.block.Block block = worldserver.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+@@ -228,12 +228,13 @@ public interface DispenseItemBehavior {
+ }
+
+ if (event.isCancelled()) {
+- stack.grow(1);
++ // stack.grow(1); // Paper - shrink below
+ return stack;
+ }
+
++ boolean shrink = true; // Paper
+ if (!event.getItem().equals(craftItem)) {
+- stack.grow(1);
++ shrink = false; // Paper - shrink below
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+@@ -250,7 +251,7 @@ public interface DispenseItemBehavior {
+ return ItemStack.EMPTY;
+ }
+
+- // itemstack.shrink(1); // Handled during event processing
++ if (shrink) stack.shrink(1); // Paper - actually handle here
+ // CraftBukkit end
+ pointer.getLevel().gameEvent((Entity) null, GameEvent.ENTITY_PLACE, pointer.getPos());
+ return stack;
+@@ -272,7 +273,7 @@ public interface DispenseItemBehavior {
+ ServerLevel worldserver = pointer.getLevel();
+
+ // CraftBukkit start
+- ItemStack itemstack1 = stack.split(1);
++ ItemStack itemstack1 = stack.copyWithCount(1); // Paper - shrink below and single item in event
+ org.bukkit.block.Block block = worldserver.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+@@ -282,12 +283,13 @@ public interface DispenseItemBehavior {
+ }
+
+ if (event.isCancelled()) {
+- stack.grow(1);
++ // stack.grow(1); // Paper - shrink below
+ return stack;
+ }
+
++ boolean shrink = true; // Paper
+ if (!event.getItem().equals(craftItem)) {
+- stack.grow(1);
++ shrink = false; // Paper - shrink below
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+@@ -304,7 +306,7 @@ public interface DispenseItemBehavior {
+ ArmorStand entityarmorstand = (ArmorStand) EntityType.ARMOR_STAND.spawn(worldserver, stack.getTag(), consumer, blockposition, MobSpawnType.DISPENSER, false, false);
+
+ if (entityarmorstand != null) {
+- // itemstack.shrink(1); // CraftBukkit - Handled during event processing
++ if (shrink) stack.shrink(1); // Paper - actually handle here
+ }
+
+ return stack;
+@@ -326,7 +328,7 @@ public interface DispenseItemBehavior {
+
+ if (!list.isEmpty()) {
+ // CraftBukkit start
+- ItemStack itemstack1 = stack.split(1);
++ ItemStack itemstack1 = stack.copyWithCount(1); // Paper - shrink below and single item in event
+ Level world = pointer.getLevel();
+ org.bukkit.block.Block block = world.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+@@ -337,12 +339,13 @@ public interface DispenseItemBehavior {
+ }
+
+ if (event.isCancelled()) {
+- stack.grow(1);
++ // stack.grow(1); // Paper - shrink below
+ return stack;
+ }
+
++ boolean shrink = true; // Paper
+ if (!event.getItem().equals(craftItem)) {
+- stack.grow(1);
++ shrink = false; // Paper - shrink below
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+@@ -353,7 +356,7 @@ public interface DispenseItemBehavior {
+ }
+ // CraftBukkit end
+ ((Saddleable) list.get(0)).equipSaddle(SoundSource.BLOCKS, CraftItemStack.asNMSCopy(event.getItem())); // Paper - Fix saddles losing nbt data - MC-191591
+- // itemstack.shrink(1); // CraftBukkit - handled above
++ if (shrink) stack.shrink(1); // Paper - actually handle here
+ this.setSuccess(true);
+ return stack;
+ } else {
+@@ -381,7 +384,7 @@ public interface DispenseItemBehavior {
+ } while (!entityhorseabstract.isArmor(stack) || entityhorseabstract.isWearingArmor() || !entityhorseabstract.isTamed());
+
+ // CraftBukkit start
+- ItemStack itemstack1 = stack.split(1);
++ ItemStack itemstack1 = stack.copyWithCount(1); // Paper - shrink below and single item in event
+ Level world = pointer.getLevel();
+ org.bukkit.block.Block block = world.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+@@ -392,12 +395,13 @@ public interface DispenseItemBehavior {
+ }
+
+ if (event.isCancelled()) {
+- stack.grow(1);
++ // stack.grow(1); // Paper - shrink below
+ return stack;
+ }
+
++ boolean shrink = true; // Paper
+ if (!event.getItem().equals(craftItem)) {
+- stack.grow(1);
++ shrink = false; // Paper - shrink below
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+@@ -407,6 +411,7 @@ public interface DispenseItemBehavior {
+ }
+ }
+
++ if (shrink) stack.shrink(1); // Paper - shrink here
+ entityhorseabstract.getSlot(401).set(CraftItemStack.asNMSCopy(event.getItem()));
+ // CraftBukkit end
+ this.setSuccess(true);
+@@ -453,7 +458,7 @@ public interface DispenseItemBehavior {
+ entityhorsechestedabstract = (AbstractChestedHorse) iterator1.next();
+ // CraftBukkit start
+ } while (!entityhorsechestedabstract.isTamed());
+- ItemStack itemstack1 = stack.split(1);
++ ItemStack itemstack1 = stack.copyWithCount(1); // Paper - shrink below
+ Level world = pointer.getLevel();
+ org.bukkit.block.Block block = world.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+@@ -464,10 +469,13 @@ public interface DispenseItemBehavior {
+ }
+
+ if (event.isCancelled()) {
++ // stack.grow(1); // Paper - shrink below (this was actually missing and should be here, added it commented out just for less confusion)
+ return stack;
+ }
+
++ boolean shrink = true; // Paper
+ if (!event.getItem().equals(craftItem)) {
++ shrink = false; // Paper - shrink below (this was actually missing and should be here, added it commented out just for less confusion)
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+@@ -479,7 +487,7 @@ public interface DispenseItemBehavior {
+ entityhorsechestedabstract.getSlot(499).set(CraftItemStack.asNMSCopy(event.getItem()));
+ // CraftBukkit end
+
+- // itemstack.shrink(1); // CraftBukkit - handled above
++ if (shrink) stack.shrink(1); // Paper - actually handle here
+ this.setSuccess(true);
+ return stack;
+ }
+@@ -490,7 +498,7 @@ public interface DispenseItemBehavior {
+ Direction enumdirection = (Direction) pointer.getBlockState().getValue(DispenserBlock.FACING);
+ // CraftBukkit start
+ ServerLevel worldserver = pointer.getLevel();
+- ItemStack itemstack1 = stack.split(1);
++ ItemStack itemstack1 = stack.copyWithCount(1); // Paper - shrink below and single item in event
+ org.bukkit.block.Block block = worldserver.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+@@ -500,12 +508,13 @@ public interface DispenseItemBehavior {
+ }
+
+ if (event.isCancelled()) {
+- stack.grow(1);
++ // stack.grow(1); // Paper - shrink below
+ return stack;
+ }
+
++ boolean shrink = true; // Paper
+ if (!event.getItem().equals(craftItem)) {
+- stack.grow(1);
++ shrink = false; // Paper - shrink below
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+@@ -522,7 +531,7 @@ public interface DispenseItemBehavior {
+ DispenseItemBehavior.setEntityPokingOutOfBlock(pointer, entityfireworks, enumdirection);
+ entityfireworks.shoot((double) enumdirection.getStepX(), (double) enumdirection.getStepY(), (double) enumdirection.getStepZ(), 0.5F, 1.0F);
+ pointer.getLevel().addFreshEntity(entityfireworks);
+- // itemstack.shrink(1); // Handled during event processing
++ if (shrink) stack.shrink(1); // Paper - actually handle here
+ // CraftBukkit end
+ return stack;
+ }
+@@ -547,7 +556,7 @@ public interface DispenseItemBehavior {
+ double d5 = randomsource.triangle((double) enumdirection.getStepZ(), 0.11485000000000001D);
+
+ // CraftBukkit start
+- ItemStack itemstack1 = stack.split(1);
++ ItemStack itemstack1 = stack.copyWithCount(1); // Paper - shrink below and single item in event
+ org.bukkit.block.Block block = worldserver.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+@@ -557,12 +566,13 @@ public interface DispenseItemBehavior {
+ }
+
+ if (event.isCancelled()) {
+- stack.grow(1);
++ // stack.grow(1); // Paper - shrink at end
+ return stack;
+ }
+
++ boolean shrink = true; // Paper
+ if (!event.getItem().equals(craftItem)) {
+- stack.grow(1);
++ shrink = false; // Paper - shrink at end
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+@@ -577,7 +587,7 @@ public interface DispenseItemBehavior {
+ entitysmallfireball.projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource((DispenserBlockEntity) pointer.getEntity());
+
+ worldserver.addFreshEntity(entitysmallfireball);
+- // itemstack.shrink(1); // Handled during event processing
++ if (shrink) stack.shrink(1); // Paper - actually handle here
+ // CraftBukkit end
+ return stack;
+ }
+@@ -622,7 +632,7 @@ public interface DispenseItemBehavior {
+ Material material = iblockdata.getMaterial();
+ if (worldserver.isEmptyBlock(blockposition) || !material.isSolid() || material.isReplaceable() || (dispensiblecontaineritem instanceof BucketItem && iblockdata.getBlock() instanceof LiquidBlockContainer && ((LiquidBlockContainer) iblockdata.getBlock()).canPlaceLiquid(worldserver, blockposition, iblockdata, ((BucketItem) dispensiblecontaineritem).content))) {
+ org.bukkit.block.Block block = worldserver.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+- CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack);
++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event
+
+ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(x, y, z));
+ if (!DispenserBlock.eventFired) {
+@@ -695,7 +705,7 @@ public interface DispenseItemBehavior {
+
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = worldserver.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+- CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack);
++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event
+
+ BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ()));
+ if (!DispenserBlock.eventFired) {
+@@ -742,7 +752,7 @@ public interface DispenseItemBehavior {
+
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = worldserver.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+- CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack);
++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack); // Paper - ignore stack size on damageable items
+
+ BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
+ if (!DispenserBlock.eventFired) {
+@@ -803,7 +813,7 @@ public interface DispenseItemBehavior {
+ BlockPos blockposition = pointer.getPos().relative((Direction) pointer.getBlockState().getValue(DispenserBlock.FACING));
+ // CraftBukkit start
+ org.bukkit.block.Block block = worldserver.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+- CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack);
++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event
+
+ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
+ if (!DispenserBlock.eventFired) {
+@@ -869,7 +879,7 @@ public interface DispenseItemBehavior {
+ // CraftBukkit start
+ // EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(worldserver, (double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D, (EntityLiving) null);
+
+- ItemStack itemstack1 = stack.split(1);
++ ItemStack itemstack1 = stack.copyWithCount(1); // Paper - shrink at end and single item in event
+ org.bukkit.block.Block block = worldserver.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+@@ -879,12 +889,13 @@ public interface DispenseItemBehavior {
+ }
+
+ if (event.isCancelled()) {
+- stack.grow(1);
++ // stack.grow(1); // Paper - shrink below
+ return stack;
+ }
+
++ boolean shrink = true; // Paper
+ if (!event.getItem().equals(craftItem)) {
+- stack.grow(1);
++ shrink = false; // Paper - shrink below
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+@@ -900,7 +911,7 @@ public interface DispenseItemBehavior {
+ worldserver.addFreshEntity(entitytntprimed);
+ worldserver.playSound((Player) null, entitytntprimed.getX(), entitytntprimed.getY(), entitytntprimed.getZ(), SoundEvents.TNT_PRIMED, SoundSource.BLOCKS, 1.0F, 1.0F);
+ worldserver.gameEvent((Entity) null, GameEvent.ENTITY_PLACE, blockposition);
+- // itemstack.shrink(1); // CraftBukkit - handled above
++ if (shrink) stack.shrink(1); // Paper - actually handle here
+ return stack;
+ }
+ });
+@@ -927,7 +938,7 @@ public interface DispenseItemBehavior {
+
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = worldserver.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+- CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack);
++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event
+
+ BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ()));
+ if (!DispenserBlock.eventFired) {
+@@ -976,7 +987,7 @@ public interface DispenseItemBehavior {
+
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = worldserver.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+- CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack);
++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event
+
+ BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ()));
+ if (!DispenserBlock.eventFired) {
+@@ -1049,7 +1060,7 @@ public interface DispenseItemBehavior {
+
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = worldserver.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+- CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack);
++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - only single item in event
+
+ BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ()));
+ if (!DispenserBlock.eventFired) {
+diff --git a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java
+index 2366d411bf64f88c7296e888cd3bf584825ae4a9..d1127d93a85a837933d0d73c24cacac4adc3a5b9 100644
+--- a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java
++++ b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java
+@@ -37,7 +37,7 @@ public class ShearsDispenseItemBehavior extends OptionalDispenseItemBehavior {
+ ServerLevel worldserver = pointer.getLevel();
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = worldserver.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+- CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack);
++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack); // Paper - ignore stack size on damageable items
+
+ BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
+ if (!DispenserBlock.eventFired) {
+diff --git a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
+index 38b5d8f7b66f5130dbd126957a4a1e59ec543e4a..0159ed9cbc644c39fa79e62327f13375193fdc98 100644
+--- a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
++++ b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
+@@ -34,7 +34,7 @@ public class ShulkerBoxDispenseBehavior extends OptionalDispenseItemBehavior {
+
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = pointer.getLevel().getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+- CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack);
++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event
+
+ BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ()));
+ if (!DispenserBlock.eventFired) {
+diff --git a/src/main/java/net/minecraft/world/item/ArmorItem.java b/src/main/java/net/minecraft/world/item/ArmorItem.java
+index 98aae5bb3cff07fcc081ad4d6c2be8728f3d1637..d7a0cbde8f8c99276307502674c71463fbe7e89c 100644
+--- a/src/main/java/net/minecraft/world/item/ArmorItem.java
++++ b/src/main/java/net/minecraft/world/item/ArmorItem.java
+@@ -61,7 +61,7 @@ public class ArmorItem extends Item implements Equipable {
+ } else {
+ LivingEntity entityliving = (LivingEntity) list.get(0);
+ EquipmentSlot enumitemslot = Mob.getEquipmentSlotForItem(armor);
+- ItemStack itemstack1 = armor.split(1);
++ ItemStack itemstack1 = armor.copyWithCount(1); // Paper - shrink below and single item in event
+ // CraftBukkit start
+ Level world = pointer.getLevel();
+ org.bukkit.block.Block block = world.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+@@ -73,12 +73,13 @@ public class ArmorItem extends Item implements Equipable {
+ }
+
+ if (event.isCancelled()) {
+- armor.grow(1);
++ // armor.grow(1); // Paper - shrink below
+ return false;
+ }
+
++ boolean shrink = true; // Paper
+ if (!event.getItem().equals(craftItem)) {
+- armor.grow(1);
++ shrink = false; // Paper - shrink below
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+@@ -95,6 +96,7 @@ public class ArmorItem extends Item implements Equipable {
+ ((Mob) entityliving).setPersistenceRequired();
+ }
+
++ if (shrink) armor.shrink(1); // Paper
+ return true;
+ }
+ }
+diff --git a/src/main/java/net/minecraft/world/item/MinecartItem.java b/src/main/java/net/minecraft/world/item/MinecartItem.java
+index 127a799f7848b32664b77bf67847ca6b8ac9a90d..c6d2f764efa9b8bec730bbe757d480e365b25ccc 100644
+--- a/src/main/java/net/minecraft/world/item/MinecartItem.java
++++ b/src/main/java/net/minecraft/world/item/MinecartItem.java
+@@ -62,7 +62,7 @@ public class MinecartItem extends Item {
+
+ // CraftBukkit start
+ // EntityMinecartAbstract entityminecartabstract = EntityMinecartAbstract.createMinecart(worldserver, d0, d1 + d3, d2, ((ItemMinecart) itemstack.getItem()).type);
+- ItemStack itemstack1 = stack.split(1);
++ ItemStack itemstack1 = stack.copyWithCount(1); // Paper - shrink below and single item in event
+ org.bukkit.block.Block block2 = worldserver.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+@@ -72,12 +72,13 @@ public class MinecartItem extends Item {
+ }
+
+ if (event.isCancelled()) {
+- stack.grow(1);
++ // stack.grow(1); // Paper - shrink below
+ return stack;
+ }
+
++ boolean shrink = true; // Paper
+ if (!event.getItem().equals(craftItem)) {
+- stack.grow(1);
++ shrink = false; // Paper - shrink below
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+@@ -94,8 +95,7 @@ public class MinecartItem extends Item {
+ entityminecartabstract.setCustomName(stack.getHoverName());
+ }
+
+- if (!worldserver.addFreshEntity(entityminecartabstract)) stack.grow(1);
+- // itemstack.shrink(1); // CraftBukkit - handled during event processing
++ if (worldserver.addFreshEntity(entityminecartabstract) && shrink) stack.shrink(1); // Paper - actually handle here
+ // CraftBukkit end
+ return stack;
+ }