--- a/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
@@ -3,15 +3,21 @@
 import net.minecraft.core.BlockPos;
 import net.minecraft.core.BlockSource;
 import net.minecraft.core.Direction;
+import net.minecraft.server.level.ServerLevel;
 import net.minecraft.tags.FluidTags;
+import net.minecraft.world.entity.Entity;
 import net.minecraft.world.entity.vehicle.Boat;
 import net.minecraft.world.entity.vehicle.ChestBoat;
 import net.minecraft.world.item.ItemStack;
-import net.minecraft.world.level.Level;
 import net.minecraft.world.level.block.DispenserBlock;
+// CraftBukkit start
+import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack;
+import org.bukkit.event.block.BlockDispenseEvent;
+// CraftBukkit end
 
 public class BoatDispenseItemBehavior extends DefaultDispenseItemBehavior {
-    private final DefaultDispenseItemBehavior defaultDispenseItemBehavior = new DefaultDispenseItemBehavior();
+
+    private final DefaultDispenseItemBehavior defaultDispenseItemBehavior;
     private final Boat.Type type;
     private final boolean isChestBoat;
 
@@ -20,34 +26,65 @@
     }
 
     public BoatDispenseItemBehavior(Boat.Type boatType, boolean chest) {
+        this.defaultDispenseItemBehavior = new DefaultDispenseItemBehavior();
         this.type = boatType;
         this.isChestBoat = chest;
     }
 
     @Override
     public ItemStack execute(BlockSource pointer, ItemStack stack) {
-        Direction direction = pointer.getBlockState().getValue(DispenserBlock.FACING);
-        Level level = pointer.getLevel();
-        double d = pointer.x() + (double)((float)direction.getStepX() * 1.125F);
-        double e = pointer.y() + (double)((float)direction.getStepY() * 1.125F);
-        double f = pointer.z() + (double)((float)direction.getStepZ() * 1.125F);
-        BlockPos blockPos = pointer.getPos().relative(direction);
-        double g;
-        if (level.getFluidState(blockPos).is(FluidTags.WATER)) {
-            g = 1.0D;
+        Direction enumdirection = (Direction) pointer.getBlockState().getValue(DispenserBlock.FACING);
+        ServerLevel worldserver = pointer.getLevel();
+        double d0 = pointer.x() + (double) ((float) enumdirection.getStepX() * 1.125F);
+        double d1 = pointer.y() + (double) ((float) enumdirection.getStepY() * 1.125F);
+        double d2 = pointer.z() + (double) ((float) enumdirection.getStepZ() * 1.125F);
+        BlockPos blockposition = pointer.getPos().relative(enumdirection);
+        double d3;
+
+        if (worldserver.getFluidState(blockposition).is(FluidTags.WATER)) {
+            d3 = 1.0D;
         } else {
-            if (!level.getBlockState(blockPos).isAir() || !level.getFluidState(blockPos.below()).is(FluidTags.WATER)) {
+            if (!worldserver.getBlockState(blockposition).isAir() || !worldserver.getFluidState(blockposition.below()).is(FluidTags.WATER)) {
                 return this.defaultDispenseItemBehavior.dispense(pointer, stack);
             }
 
-            g = 0.0D;
+            d3 = 0.0D;
         }
 
-        Boat boat = (Boat)(this.isChestBoat ? new ChestBoat(level, d, e + g, f) : new Boat(level, d, e + g, f));
-        boat.setType(this.type);
-        boat.setYRot(direction.toYRot());
-        level.addFreshEntity(boat);
-        stack.shrink(1);
+        // EntityBoat entityboat = new EntityBoat(worldserver, d0, d1 + d3, d2);
+        // CraftBukkit start
+        ItemStack itemstack1 = stack.split(1);
+        org.bukkit.block.Block block = worldserver.getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+        CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+        BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d0, d1 + d3, d2));
+        if (!DispenserBlock.eventFired) {
+            worldserver.getCraftServer().getPluginManager().callEvent(event);
+        }
+
+        if (event.isCancelled()) {
+            stack.grow(1);
+            return stack;
+        }
+
+        if (!event.getItem().equals(craftItem)) {
+            stack.grow(1);
+            // Chain to handler for new item
+            ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+            DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+            if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+                idispensebehavior.dispense(pointer, eventStack);
+                return stack;
+            }
+        }
+
+        Object object = this.isChestBoat ? new ChestBoat(worldserver, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ()) : new Boat(worldserver, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ());
+        // CraftBukkit end
+
+        ((Boat) object).setType(this.type);
+        ((Boat) object).setYRot(enumdirection.toYRot());
+        if (!worldserver.addFreshEntity((Entity) object)) stack.grow(1); // CraftBukkit
+        // itemstack.shrink(1); // CraftBukkit - handled during event processing
         return stack;
     }
 
