--- a/net/minecraft/world/level/block/DropperBlock.java
+++ b/net/minecraft/world/level/block/DropperBlock.java
@@ -8,6 +8,7 @@
 import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
 import net.minecraft.core.dispenser.DispenseItemBehavior;
 import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.CompoundContainer;
 import net.minecraft.world.Container;
 import net.minecraft.world.item.ItemStack;
 import net.minecraft.world.level.Level;
@@ -19,15 +20,19 @@
 import net.minecraft.world.level.block.state.BlockBehaviour;
 import net.minecraft.world.level.block.state.BlockState;
 import org.slf4j.Logger;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.event.inventory.InventoryMoveItemEvent;
+// CraftBukkit end
 
 public class DropperBlock extends DispenserBlock {
+
     private static final Logger LOGGER = LogUtils.getLogger();
     public static final MapCodec<DropperBlock> CODEC = simpleCodec(DropperBlock::new);
-    private static final DispenseItemBehavior DISPENSE_BEHAVIOUR = new DefaultDispenseItemBehavior();
+    private static final DispenseItemBehavior DISPENSE_BEHAVIOUR = new DefaultDispenseItemBehavior(true); // CraftBukkit
 
     @Override
     public MapCodec<DropperBlock> codec() {
-        return CODEC;
+        return DropperBlock.CODEC;
     }
 
     public DropperBlock(BlockBehaviour.Properties settings) {
@@ -36,7 +41,7 @@
 
     @Override
     protected DispenseItemBehavior getDispenseMethod(Level world, ItemStack stack) {
-        return DISPENSE_BEHAVIOUR;
+        return DropperBlock.DISPENSE_BEHAVIOUR;
     }
 
     @Override
@@ -46,33 +51,56 @@
 
     @Override
     public void dispenseFrom(ServerLevel world, BlockState state, BlockPos pos) {
-        DispenserBlockEntity dispenserBlockEntity = world.getBlockEntity(pos, BlockEntityType.DROPPER).orElse(null);
-        if (dispenserBlockEntity == null) {
-            LOGGER.warn("Ignoring dispensing attempt for Dropper without matching block entity at {}", pos);
+        DispenserBlockEntity tileentitydispenser = (DispenserBlockEntity) world.getBlockEntity(pos, BlockEntityType.DROPPER).orElse(null); // CraftBukkit - decompile error
+
+        if (tileentitydispenser == null) {
+            DropperBlock.LOGGER.warn("Ignoring dispensing attempt for Dropper without matching block entity at {}", pos);
         } else {
-            BlockSource blockSource = new BlockSource(world, pos, state, dispenserBlockEntity);
-            int i = dispenserBlockEntity.getRandomSlot(world.random);
+            BlockSource sourceblock = new BlockSource(world, pos, state, tileentitydispenser);
+            int i = tileentitydispenser.getRandomSlot(world.random);
+
             if (i < 0) {
+                if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFailedDispenseEvent(world, pos)) // Paper - Add BlockFailedDispenseEvent
                 world.levelEvent(1001, pos, 0);
             } else {
-                ItemStack itemStack = dispenserBlockEntity.getItem(i);
-                if (!itemStack.isEmpty()) {
-                    Direction direction = world.getBlockState(pos).getValue(FACING);
-                    Container container = HopperBlockEntity.getContainerAt(world, pos.relative(direction));
-                    ItemStack itemStack2;
-                    if (container == null) {
-                        itemStack2 = DISPENSE_BEHAVIOUR.dispense(blockSource, itemStack);
+                ItemStack itemstack = tileentitydispenser.getItem(i);
+
+                if (!itemstack.isEmpty()) {
+                    Direction enumdirection = (Direction) world.getBlockState(pos).getValue(DropperBlock.FACING);
+                    Container iinventory = HopperBlockEntity.getContainerAt(world, pos.relative(enumdirection));
+                    ItemStack itemstack1;
+
+                    if (iinventory == null) {
+                        if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(world, pos, itemstack, i)) return; // Paper - Add BlockPreDispenseEvent
+                        itemstack1 = DropperBlock.DISPENSE_BEHAVIOUR.dispense(sourceblock, itemstack);
                     } else {
-                        itemStack2 = HopperBlockEntity.addItem(dispenserBlockEntity, container, itemStack.copyWithCount(1), direction.getOpposite());
-                        if (itemStack2.isEmpty()) {
-                            itemStack2 = itemStack.copy();
-                            itemStack2.shrink(1);
+                        // CraftBukkit start - Fire event when pushing items into other inventories
+                        CraftItemStack oitemstack = CraftItemStack.asCraftMirror(itemstack.copyWithCount(1));
+
+                        org.bukkit.inventory.Inventory destinationInventory;
+                        // Have to special case large chests as they work oddly
+                        if (iinventory instanceof CompoundContainer) {
+                            destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory);
                         } else {
-                            itemStack2 = itemStack.copy();
+                            destinationInventory = iinventory.getOwner().getInventory();
+                        }
+
+                        InventoryMoveItemEvent event = new InventoryMoveItemEvent(tileentitydispenser.getOwner().getInventory(), oitemstack.clone(), destinationInventory, true);
+                        world.getCraftServer().getPluginManager().callEvent(event);
+                        if (event.isCancelled()) {
+                            return;
+                        }
+                        itemstack1 = HopperBlockEntity.addItem(tileentitydispenser, iinventory, CraftItemStack.asNMSCopy(event.getItem()), enumdirection.getOpposite());
+                        if (event.getItem().equals(oitemstack) && itemstack1.isEmpty()) {
+                            // CraftBukkit end
+                            itemstack1 = itemstack.copy();
+                            itemstack1.shrink(1);
+                        } else {
+                            itemstack1 = itemstack.copy();
                         }
                     }
 
-                    dispenserBlockEntity.setItem(i, itemStack2);
+                    tileentitydispenser.setItem(i, itemstack1);
                 }
             }
         }
