--- a/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
+++ b/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
@@ -22,10 +_,38 @@
             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)); // Paper - single item in event
+
+            org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockPos.getX(), blockPos.getY(), blockPos.getZ()));
+            if (!DispenserBlock.eventFired) {
+                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); // Paper - Fix NPE with equippable and items without behavior
+                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);
             }
