--- a/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
+++ b/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
@@ -22,10 +_,36 @@
             BlockPos blockPos = blockSource.pos().relative(direction);
             Direction direction1 = blockSource.level().isEmptyBlock(blockPos.below()) ? direction : Direction.UP;
 
+            // CraftBukkit start
+            org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(blockSource.level(), blockSource.pos());
+            org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1));
+
+            org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos));
+            blockSource.level().getCraftServer().getPluginManager().callEvent(event);
+
+            if (event.isCancelled()) {
+                return item;
+            }
+
+            if (!event.getItem().equals(craftItem)) {
+                // Chain to handler for new item
+                ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+                DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(blockSource, eventStack);
+                if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) {
+                    dispenseBehavior.dispense(blockSource, eventStack);
+                    return item;
+                }
+            }
+            // CraftBukkit end
             try {
+                // Paper start - track changed items in the dispense event
                 this.setSuccess(
-                    ((BlockItem)item1).place(new DirectionalPlaceContext(blockSource.level(), blockPos, direction, item, direction1)).consumesAction()
+                    ((BlockItem) item1).place(new DirectionalPlaceContext(blockSource.level(), blockPos, direction, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), direction1)).consumesAction()
                 );
+                if (this.isSuccess()) {
+                    item.shrink(1); // vanilla shrink is in the place function above, manually handle it here
+                }
+                // Paper end - track changed items in the dispense event
             } catch (Exception var8) {
                 LOGGER.error("Error trying to place shulker box at {}", blockPos, var8);
             }
