--- a/net/minecraft/world/level/block/DispenserBlock.java
+++ b/net/minecraft/world/level/block/DispenserBlock.java
@@ -14,6 +14,7 @@
 import net.minecraft.server.level.ServerLevel;
 import net.minecraft.stats.Stats;
 import net.minecraft.util.RandomSource;
+import net.minecraft.world.Container;
 import net.minecraft.world.Containers;
 import net.minecraft.world.InteractionHand;
 import net.minecraft.world.InteractionResult;
@@ -39,20 +40,22 @@
 import net.minecraft.world.phys.BlockHitResult;
 
 public class DispenserBlock extends BaseEntityBlock {
+
     public static final DirectionProperty FACING = DirectionalBlock.FACING;
     public static final BooleanProperty TRIGGERED = BlockStateProperties.TRIGGERED;
-    public static final Map<Item, DispenseItemBehavior> DISPENSER_REGISTRY = Util.make(new Object2ObjectOpenHashMap<>(), (map) -> {
-        map.defaultReturnValue(new DefaultDispenseItemBehavior());
+    public static final Map<Item, DispenseItemBehavior> DISPENSER_REGISTRY = (Map) Util.make(new Object2ObjectOpenHashMap(), (object2objectopenhashmap) -> {
+        object2objectopenhashmap.defaultReturnValue(new DefaultDispenseItemBehavior());
     });
     private static final int TRIGGER_DURATION = 4;
+    public static boolean eventFired = false; // CraftBukkit
 
     public static void registerBehavior(ItemLike provider, DispenseItemBehavior behavior) {
-        DISPENSER_REGISTRY.put(provider.asItem(), behavior);
+        DispenserBlock.DISPENSER_REGISTRY.put(provider.asItem(), behavior);
     }
 
     protected DispenserBlock(BlockBehaviour.Properties settings) {
         super(settings);
-        this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(TRIGGERED, Boolean.valueOf(false)));
+        this.registerDefaultState((BlockState) ((BlockState) ((BlockState) this.stateDefinition.any()).setValue(DispenserBlock.FACING, Direction.NORTH)).setValue(DispenserBlock.TRIGGERED, false));
     }
 
     @Override
@@ -60,10 +63,11 @@
         if (world.isClientSide) {
             return InteractionResult.SUCCESS;
         } else {
-            BlockEntity blockEntity = world.getBlockEntity(pos);
-            if (blockEntity instanceof DispenserBlockEntity) {
-                player.openMenu((DispenserBlockEntity)blockEntity);
-                if (blockEntity instanceof DropperBlockEntity) {
+            BlockEntity tileentity = world.getBlockEntity(pos);
+
+            if (tileentity instanceof DispenserBlockEntity) {
+                player.openMenu((DispenserBlockEntity) tileentity);
+                if (tileentity instanceof DropperBlockEntity) {
                     player.awardStat(Stats.INSPECT_DROPPER);
                 } else {
                     player.awardStat(Stats.INSPECT_DISPENSER);
@@ -75,35 +79,42 @@
     }
 
     public void dispenseFrom(ServerLevel world, BlockPos pos) {
-        BlockSourceImpl blockSourceImpl = new BlockSourceImpl(world, pos);
-        DispenserBlockEntity dispenserBlockEntity = blockSourceImpl.getEntity();
-        int i = dispenserBlockEntity.getRandomSlot(world.random);
+        BlockSourceImpl sourceblock = new BlockSourceImpl(world, pos);
+        DispenserBlockEntity tileentitydispenser = (DispenserBlockEntity) sourceblock.getEntity();
+        int i = tileentitydispenser.getRandomSlot(world.random);
+
         if (i < 0) {
+            if (org.bukkit.craftbukkit.v1_19_R2.event.CraftEventFactory.handleBlockFailedDispenseEvent(world, pos)) {// Paper - BlockFailedDispenseEvent is called here
             world.levelEvent(1001, pos, 0);
-            world.gameEvent((Entity)null, GameEvent.DISPENSE_FAIL, pos);
+            world.gameEvent((Entity) null, GameEvent.DISPENSE_FAIL, pos);
+            } // Paper
         } else {
-            ItemStack itemStack = dispenserBlockEntity.getItem(i);
-            DispenseItemBehavior dispenseItemBehavior = this.getDispenseMethod(itemStack);
-            if (dispenseItemBehavior != DispenseItemBehavior.NOOP) {
-                dispenserBlockEntity.setItem(i, dispenseItemBehavior.dispense(blockSourceImpl, itemStack));
+            ItemStack itemstack = tileentitydispenser.getItem(i);
+            DispenseItemBehavior idispensebehavior = this.getDispenseMethod(itemstack);
+
+            if (idispensebehavior != DispenseItemBehavior.NOOP) {
+                if (!org.bukkit.craftbukkit.v1_19_R2.event.CraftEventFactory.handleBlockPreDispenseEvent(world, pos, itemstack, i)) return; // Paper - BlockPreDispenseEvent is called here
+                DispenserBlock.eventFired = false; // CraftBukkit - reset event status
+                tileentitydispenser.setItem(i, idispensebehavior.dispense(sourceblock, itemstack));
             }
 
         }
     }
 
     protected DispenseItemBehavior getDispenseMethod(ItemStack stack) {
-        return DISPENSER_REGISTRY.get(stack.getItem());
+        return (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(stack.getItem());
     }
 
     @Override
     public void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) {
-        boolean bl = world.hasNeighborSignal(pos) || world.hasNeighborSignal(pos.above());
-        boolean bl2 = state.getValue(TRIGGERED);
-        if (bl && !bl2) {
-            world.scheduleTick(pos, this, 4);
-            world.setBlock(pos, state.setValue(TRIGGERED, Boolean.valueOf(true)), 4);
-        } else if (!bl && bl2) {
-            world.setBlock(pos, state.setValue(TRIGGERED, Boolean.valueOf(false)), 4);
+        boolean flag1 = world.hasNeighborSignal(pos) || world.hasNeighborSignal(pos.above());
+        boolean flag2 = (Boolean) state.getValue(DispenserBlock.TRIGGERED);
+
+        if (flag1 && !flag2) {
+            world.scheduleTick(pos, (Block) this, 4);
+            world.setBlock(pos, (BlockState) state.setValue(DispenserBlock.TRIGGERED, true), 4);
+        } else if (!flag1 && flag2) {
+            world.setBlock(pos, (BlockState) state.setValue(DispenserBlock.TRIGGERED, false), 4);
         }
 
     }
@@ -120,15 +131,16 @@
 
     @Override
     public BlockState getStateForPlacement(BlockPlaceContext ctx) {
-        return this.defaultBlockState().setValue(FACING, ctx.getNearestLookingDirection().getOpposite());
+        return (BlockState) this.defaultBlockState().setValue(DispenserBlock.FACING, ctx.getNearestLookingDirection().getOpposite());
     }
 
     @Override
     public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack itemStack) {
         if (itemStack.hasCustomHoverName()) {
-            BlockEntity blockEntity = world.getBlockEntity(pos);
-            if (blockEntity instanceof DispenserBlockEntity) {
-                ((DispenserBlockEntity)blockEntity).setCustomName(itemStack.getHoverName());
+            BlockEntity tileentity = world.getBlockEntity(pos);
+
+            if (tileentity instanceof DispenserBlockEntity) {
+                ((DispenserBlockEntity) tileentity).setCustomName(itemStack.getHoverName());
             }
         }
 
@@ -137,9 +149,10 @@
     @Override
     public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean moved) {
         if (!state.is(newState.getBlock())) {
-            BlockEntity blockEntity = world.getBlockEntity(pos);
-            if (blockEntity instanceof DispenserBlockEntity) {
-                Containers.dropContents(world, pos, (DispenserBlockEntity)blockEntity);
+            BlockEntity tileentity = world.getBlockEntity(pos);
+
+            if (tileentity instanceof DispenserBlockEntity) {
+                Containers.dropContents(world, pos, (Container) ((DispenserBlockEntity) tileentity));
                 world.updateNeighbourForOutputSignal(pos, this);
             }
 
@@ -148,11 +161,12 @@
     }
 
     public static Position getDispensePosition(BlockSource pointer) {
-        Direction direction = pointer.getBlockState().getValue(FACING);
-        double d = pointer.x() + 0.7D * (double)direction.getStepX();
-        double e = pointer.y() + 0.7D * (double)direction.getStepY();
-        double f = pointer.z() + 0.7D * (double)direction.getStepZ();
-        return new PositionImpl(d, e, f);
+        Direction enumdirection = (Direction) pointer.getBlockState().getValue(DispenserBlock.FACING);
+        double d0 = pointer.x() + 0.7D * (double) enumdirection.getStepX();
+        double d1 = pointer.y() + 0.7D * (double) enumdirection.getStepY();
+        double d2 = pointer.z() + 0.7D * (double) enumdirection.getStepZ();
+
+        return new PositionImpl(d0, d1, d2);
     }
 
     @Override
@@ -172,16 +186,16 @@
 
     @Override
     public BlockState rotate(BlockState state, Rotation rotation) {
-        return state.setValue(FACING, rotation.rotate(state.getValue(FACING)));
+        return (BlockState) state.setValue(DispenserBlock.FACING, rotation.rotate((Direction) state.getValue(DispenserBlock.FACING)));
     }
 
     @Override
     public BlockState mirror(BlockState state, Mirror mirror) {
-        return state.rotate(mirror.getRotation(state.getValue(FACING)));
+        return state.rotate(mirror.getRotation((Direction) state.getValue(DispenserBlock.FACING)));
     }
 
     @Override
     protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
-        builder.add(FACING, TRIGGERED);
+        builder.add(DispenserBlock.FACING, DispenserBlock.TRIGGERED);
     }
 }
