--- a/net/minecraft/world/level/block/DispenserBlock.java
+++ b/net/minecraft/world/level/block/DispenserBlock.java
@@ -7,6 +7,7 @@
 import net.minecraft.Util;
 import net.minecraft.core.BlockPos;
 import net.minecraft.core.Direction;
+import net.minecraft.core.Holder;
 import net.minecraft.core.Position;
 import net.minecraft.core.dispenser.BlockSource;
 import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
@@ -40,32 +41,34 @@
 import org.slf4j.Logger;
 
 public class DispenserBlock extends BaseEntityBlock {
+
     private static final Logger LOGGER = LogUtils.getLogger();
     public static final MapCodec<DispenserBlock> CODEC = simpleCodec(DispenserBlock::new);
     public static final DirectionProperty FACING = DirectionalBlock.FACING;
     public static final BooleanProperty TRIGGERED = BlockStateProperties.TRIGGERED;
     private static final DefaultDispenseItemBehavior DEFAULT_BEHAVIOR = new DefaultDispenseItemBehavior();
-    public static final Map<Item, DispenseItemBehavior> DISPENSER_REGISTRY = Util.make(
-        new Object2ObjectOpenHashMap<>(), map -> map.defaultReturnValue(DEFAULT_BEHAVIOR)
-    );
+    public static final Map<Item, DispenseItemBehavior> DISPENSER_REGISTRY = (Map) Util.make(new Object2ObjectOpenHashMap(), (object2objectopenhashmap) -> {
+        object2objectopenhashmap.defaultReturnValue(DispenserBlock.DEFAULT_BEHAVIOR);
+    });
     private static final int TRIGGER_DURATION = 4;
+    public static boolean eventFired = false; // CraftBukkit
 
     @Override
     public MapCodec<? extends DispenserBlock> codec() {
-        return CODEC;
+        return DispenserBlock.CODEC;
     }
 
     public static void registerBehavior(ItemLike provider, DispenseItemBehavior behavior) {
-        DISPENSER_REGISTRY.put(provider.asItem(), behavior);
+        DispenserBlock.DISPENSER_REGISTRY.put(provider.asItem(), behavior);
     }
 
     public static void registerProjectileBehavior(ItemLike projectile) {
-        DISPENSER_REGISTRY.put(projectile.asItem(), new ProjectileDispenseBehavior(projectile.asItem()));
+        DispenserBlock.DISPENSER_REGISTRY.put(projectile.asItem(), new ProjectileDispenseBehavior(projectile.asItem()));
     }
 
     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
@@ -73,10 +76,10 @@
         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).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation
+                if (tileentity instanceof DropperBlockEntity) {
                     player.awardStat(Stats.INSPECT_DROPPER);
                 } else {
                     player.awardStat(Stats.INSPECT_DISPENSER);
@@ -88,39 +91,49 @@
     }
 
     public void dispenseFrom(ServerLevel world, BlockState state, BlockPos pos) {
-        DispenserBlockEntity dispenserBlockEntity = world.getBlockEntity(pos, BlockEntityType.DISPENSER).orElse(null);
-        if (dispenserBlockEntity == null) {
-            LOGGER.warn("Ignoring dispensing attempt for Dispenser without matching block entity at {}", pos);
+        DispenserBlockEntity tileentitydispenser = (DispenserBlockEntity) world.getBlockEntity(pos, BlockEntityType.DISPENSER).orElse(null); // CraftBukkit - decompile error
+
+        if (tileentitydispenser == null) {
+            DispenserBlock.LOGGER.warn("Ignoring dispensing attempt for Dispenser 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);
-                world.gameEvent(GameEvent.BLOCK_ACTIVATE, pos, GameEvent.Context.of(dispenserBlockEntity.getBlockState()));
+                world.gameEvent((Holder) GameEvent.BLOCK_ACTIVATE, pos, GameEvent.Context.of(tileentitydispenser.getBlockState()));
+                } // Paper - Add BlockFailedDispenseEvent
             } else {
-                ItemStack itemStack = dispenserBlockEntity.getItem(i);
-                DispenseItemBehavior dispenseItemBehavior = this.getDispenseMethod(world, itemStack);
-                if (dispenseItemBehavior != DispenseItemBehavior.NOOP) {
-                    dispenserBlockEntity.setItem(i, dispenseItemBehavior.dispense(blockSource, itemStack));
+                ItemStack itemstack = tileentitydispenser.getItem(i);
+                DispenseItemBehavior idispensebehavior = this.getDispenseMethod(world, itemstack);
+
+                if (idispensebehavior != DispenseItemBehavior.NOOP) {
+                    if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(world, pos, itemstack, i)) return; // Paper - Add BlockPreDispenseEvent
+                    DispenserBlock.eventFired = false; // CraftBukkit - reset event status
+                    tileentitydispenser.setItem(i, idispensebehavior.dispense(sourceblock, itemstack));
                 }
+
             }
         }
     }
 
     protected DispenseItemBehavior getDispenseMethod(Level world, ItemStack stack) {
-        return (DispenseItemBehavior)(!stack.isItemEnabled(world.enabledFeatures()) ? DEFAULT_BEHAVIOR : DISPENSER_REGISTRY.get(stack.getItem()));
+        return (DispenseItemBehavior) (!stack.isItemEnabled(world.enabledFeatures()) ? DispenserBlock.DEFAULT_BEHAVIOR : (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(stack.getItem()));
     }
 
     @Override
     protected 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)), 2);
-        } else if (!bl && bl2) {
-            world.setBlock(pos, state.setValue(TRIGGERED, Boolean.valueOf(false)), 2);
+        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), 2);
+        } else if (!flag1 && flag2) {
+            world.setBlock(pos, (BlockState) state.setValue(DispenserBlock.TRIGGERED, false), 2);
         }
+
     }
 
     @Override
@@ -135,7 +148,7 @@
 
     @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
@@ -145,17 +158,13 @@
     }
 
     public static Position getDispensePosition(BlockSource pointer) {
-        return getDispensePosition(pointer, 0.7, Vec3.ZERO);
+        return DispenserBlock.getDispensePosition(pointer, 0.7D, Vec3.ZERO);
     }
 
     public static Position getDispensePosition(BlockSource pointer, double facingOffset, Vec3 constantOffset) {
-        Direction direction = pointer.state().getValue(FACING);
-        return pointer.center()
-            .add(
-                facingOffset * (double)direction.getStepX() + constantOffset.x(),
-                facingOffset * (double)direction.getStepY() + constantOffset.y(),
-                facingOffset * (double)direction.getStepZ() + constantOffset.z()
-            );
+        Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING);
+
+        return pointer.center().add(facingOffset * (double) enumdirection.getStepX() + constantOffset.x(), facingOffset * (double) enumdirection.getStepY() + constantOffset.y(), facingOffset * (double) enumdirection.getStepZ() + constantOffset.z());
     }
 
     @Override
@@ -175,16 +184,16 @@
 
     @Override
     protected 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
     protected 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);
     }
 }
