--- a/net/minecraft/core/dispenser/DispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/DispenseItemBehavior.java
@@ -1,18 +1,22 @@
 package net.minecraft.core.dispenser;
 
 import com.mojang.logging.LogUtils;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Optional;
 import java.util.function.Consumer;
 import net.minecraft.core.BlockPos;
 import net.minecraft.core.Direction;
+import net.minecraft.core.Holder;
 import net.minecraft.core.component.DataComponents;
 import net.minecraft.core.particles.ParticleTypes;
 import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
 import net.minecraft.sounds.SoundEvents;
 import net.minecraft.sounds.SoundSource;
 import net.minecraft.tags.BlockTags;
 import net.minecraft.tags.FluidTags;
+import net.minecraft.world.entity.Entity;
 import net.minecraft.world.entity.EntitySelector;
 import net.minecraft.world.entity.EntityType;
 import net.minecraft.world.entity.EquipmentSlot;
@@ -24,9 +28,11 @@
 import net.minecraft.world.entity.animal.horse.AbstractHorse;
 import net.minecraft.world.entity.decoration.ArmorStand;
 import net.minecraft.world.entity.item.PrimedTnt;
+import net.minecraft.world.entity.player.Player;
 import net.minecraft.world.entity.vehicle.Boat;
 import net.minecraft.world.item.ArmorItem;
 import net.minecraft.world.item.BoneMealItem;
+import net.minecraft.world.item.BucketItem;
 import net.minecraft.world.item.DispensibleContainerItem;
 import net.minecraft.world.item.DyeColor;
 import net.minecraft.world.item.HoneycombItem;
@@ -36,10 +42,9 @@
 import net.minecraft.world.item.SpawnEggItem;
 import net.minecraft.world.item.alchemy.PotionContents;
 import net.minecraft.world.item.alchemy.Potions;
-import net.minecraft.world.level.Level;
-import net.minecraft.world.level.LevelAccessor;
 import net.minecraft.world.level.block.BaseFireBlock;
 import net.minecraft.world.level.block.BeehiveBlock;
+import net.minecraft.world.level.block.Block;
 import net.minecraft.world.level.block.Blocks;
 import net.minecraft.world.level.block.BucketPickup;
 import net.minecraft.world.level.block.CampfireBlock;
@@ -47,7 +52,9 @@
 import net.minecraft.world.level.block.CandleCakeBlock;
 import net.minecraft.world.level.block.CarvedPumpkinBlock;
 import net.minecraft.world.level.block.DispenserBlock;
+import net.minecraft.world.level.block.LiquidBlockContainer;
 import net.minecraft.world.level.block.RespawnAnchorBlock;
+import net.minecraft.world.level.block.SaplingBlock;
 import net.minecraft.world.level.block.ShulkerBoxBlock;
 import net.minecraft.world.level.block.SkullBlock;
 import net.minecraft.world.level.block.TntBlock;
@@ -60,11 +67,26 @@
 import net.minecraft.world.level.block.state.properties.RotationSegment;
 import net.minecraft.world.level.gameevent.GameEvent;
 import net.minecraft.world.phys.AABB;
+import net.minecraft.world.phys.BlockHitResult;
 import org.slf4j.Logger;
+import org.bukkit.Location;
+import org.bukkit.TreeType;
+import org.bukkit.craftbukkit.block.CraftBlock;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.craftbukkit.util.CraftLocation;
+import org.bukkit.craftbukkit.util.DummyGeneratorAccess;
+import org.bukkit.event.block.BlockDispenseArmorEvent;
+import org.bukkit.event.block.BlockDispenseEvent;
+import org.bukkit.event.block.BlockFertilizeEvent;
+import org.bukkit.event.world.StructureGrowEvent;
+// CraftBukkit end
 
 public interface DispenseItemBehavior {
+
     Logger LOGGER = LogUtils.getLogger();
-    DispenseItemBehavior NOOP = (pointer, stack) -> stack;
+    DispenseItemBehavior NOOP = (sourceblock, itemstack) -> {
+        return itemstack;
+    };
 
     ItemStack dispense(BlockSource pointer, ItemStack stack);
 
@@ -80,128 +102,291 @@
         DispenserBlock.registerProjectileBehavior(Items.FIREWORK_ROCKET);
         DispenserBlock.registerProjectileBehavior(Items.FIRE_CHARGE);
         DispenserBlock.registerProjectileBehavior(Items.WIND_CHARGE);
-        DefaultDispenseItemBehavior defaultDispenseItemBehavior = new DefaultDispenseItemBehavior() {
+        DefaultDispenseItemBehavior dispensebehavioritem = new DefaultDispenseItemBehavior() {
             @Override
             public ItemStack execute(BlockSource pointer, ItemStack stack) {
-                Direction direction = pointer.state().getValue(DispenserBlock.FACING);
-                EntityType<?> entityType = ((SpawnEggItem)stack.getItem()).getType(stack);
+                Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING);
+                EntityType<?> entitytypes = ((SpawnEggItem) stack.getItem()).getType(stack);
+
+                // CraftBukkit start
+                ServerLevel worldserver = pointer.level();
+                ItemStack itemstack1 = stack.copyWithCount(1); // Paper - shrink below and single item in event
+                org.bukkit.block.Block block = CraftBlock.at(worldserver, pointer.pos());
+                CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+                BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
+                if (!DispenserBlock.eventFired) {
+                    worldserver.getCraftServer().getPluginManager().callEvent(event);
+                }
+
+                if (event.isCancelled()) {
+                    // stack.grow(1); // Paper - shrink below
+                    return stack;
+                }
+
+                boolean shrink = true; // Paper
+                if (!event.getItem().equals(craftItem)) {
+                    shrink = false; // Paper - shrink below
+                    // 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;
+                    }
+                    // Paper start - track changed items in the dispense event
+                    itemstack1 = CraftItemStack.unwrap(event.getItem()); // unwrap is safe because the stack won't be modified
+                    entitytypes = ((SpawnEggItem) itemstack1.getItem()).getType(itemstack1);
+                    // Paper end - track changed item from dispense event
+                }
 
                 try {
-                    entityType.spawn(pointer.level(), stack, null, pointer.pos().relative(direction), MobSpawnType.DISPENSER, direction != Direction.UP, false);
-                } catch (Exception var6) {
-                    LOGGER.error("Error while dispensing spawn egg from dispenser at {}", pointer.pos(), var6);
+                    entitytypes.spawn(pointer.level(), itemstack1, (Player) null, pointer.pos().relative(enumdirection), MobSpawnType.DISPENSER, enumdirection != Direction.UP, false); // Paper - track changed item in dispense event
+                } catch (Exception exception) {
+                    DispenseItemBehavior.LOGGER.error("Error while dispensing spawn egg from dispenser at {}", pointer.pos(), exception); // CraftBukkit - decompile error
                     return ItemStack.EMPTY;
                 }
 
-                stack.shrink(1);
-                pointer.level().gameEvent(null, GameEvent.ENTITY_PLACE, pointer.pos());
+                if (shrink) stack.shrink(1); // Paper - actually handle here
+                // CraftBukkit end
+                pointer.level().gameEvent((Entity) null, (Holder) GameEvent.ENTITY_PLACE, pointer.pos());
                 return stack;
             }
         };
+        Iterator iterator = SpawnEggItem.eggs().iterator();
 
-        for (SpawnEggItem spawnEggItem : SpawnEggItem.eggs()) {
-            DispenserBlock.registerBehavior(spawnEggItem, defaultDispenseItemBehavior);
+        while (iterator.hasNext()) {
+            SpawnEggItem itemmonsteregg = (SpawnEggItem) iterator.next();
+
+            DispenserBlock.registerBehavior(itemmonsteregg, dispensebehavioritem);
         }
 
-        DispenserBlock.registerBehavior(
-            Items.ARMOR_STAND,
-            new DefaultDispenseItemBehavior() {
-                @Override
-                public ItemStack execute(BlockSource pointer, ItemStack stack) {
-                    Direction direction = pointer.state().getValue(DispenserBlock.FACING);
-                    BlockPos blockPos = pointer.pos().relative(direction);
-                    ServerLevel serverLevel = pointer.level();
-                    Consumer<ArmorStand> consumer = EntityType.appendDefaultStackConfig(
-                        armorStandx -> armorStandx.setYRot(direction.toYRot()), serverLevel, stack, null
-                    );
-                    ArmorStand armorStand = EntityType.ARMOR_STAND.spawn(serverLevel, consumer, blockPos, MobSpawnType.DISPENSER, false, false);
-                    if (armorStand != null) {
-                        stack.shrink(1);
-                    }
+        DispenserBlock.registerBehavior(Items.ARMOR_STAND, new DefaultDispenseItemBehavior() {
+            @Override
+            public ItemStack execute(BlockSource pointer, ItemStack stack) {
+                Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING);
+                BlockPos blockposition = pointer.pos().relative(enumdirection);
+                ServerLevel worldserver = pointer.level();
+
+                // CraftBukkit start
+                ItemStack itemstack1 = stack.copyWithCount(1); // Paper - shrink below and single item in event
+                org.bukkit.block.Block block = CraftBlock.at(worldserver, pointer.pos());
+                CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
 
+                BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
+                if (!DispenserBlock.eventFired) {
+                    worldserver.getCraftServer().getPluginManager().callEvent(event);
+                }
+
+                if (event.isCancelled()) {
+                    // stack.grow(1); // Paper - shrink below
                     return stack;
                 }
-            }
-        );
-        DispenserBlock.registerBehavior(
-            Items.SADDLE,
-            new OptionalDispenseItemBehavior() {
-                @Override
-                public ItemStack execute(BlockSource pointer, ItemStack stack) {
-                    BlockPos blockPos = pointer.pos().relative(pointer.state().getValue(DispenserBlock.FACING));
-                    List<LivingEntity> list = pointer.level()
-                        .getEntitiesOfClass(
-                            LivingEntity.class,
-                            new AABB(blockPos),
-                            entity -> entity instanceof Saddleable saddleable && !saddleable.isSaddled() && saddleable.isSaddleable()
-                        );
-                    if (!list.isEmpty()) {
-                        ((Saddleable)list.get(0)).equipSaddle(stack.split(1), SoundSource.BLOCKS);
-                        this.setSuccess(true);
+
+                boolean shrink = true; // Paper
+                if (!event.getItem().equals(craftItem)) {
+                    shrink = false; // Paper - shrink below
+                    // 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;
+                    }
+                }
+                // CraftBukkit end
+
+                final ItemStack newStack = CraftItemStack.unwrap(event.getItem()); // Paper - use event itemstack (unwrap is fine here because the stack won't be modified)
+                Consumer<ArmorStand> consumer = EntityType.appendDefaultStackConfig((entityarmorstand) -> {
+                    entityarmorstand.setYRot(enumdirection.toYRot());
+                }, worldserver, newStack, (Player) null); // Paper - track changed items in the dispense event
+                ArmorStand entityarmorstand = (ArmorStand) EntityType.ARMOR_STAND.spawn(worldserver, consumer, blockposition, MobSpawnType.DISPENSER, false, false);
+
+                if (entityarmorstand != null) {
+                    if (shrink) stack.shrink(1); // Paper - actually handle here
+                }
+
+                return stack;
+            }
+        });
+        DispenserBlock.registerBehavior(Items.SADDLE, new OptionalDispenseItemBehavior() {
+            @Override
+            public ItemStack execute(BlockSource pointer, ItemStack stack) {
+                BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
+                List<LivingEntity> list = pointer.level().getEntitiesOfClass(LivingEntity.class, new AABB(blockposition), (entityliving) -> {
+                    if (!(entityliving instanceof Saddleable isaddleable)) {
+                        return false;
                     } else {
-                        return super.execute(pointer, stack);
+                        return !isaddleable.isSaddled() && isaddleable.isSaddleable();
+                    }
+                });
+
+                if (!list.isEmpty()) {
+                    // CraftBukkit start
+                    ItemStack itemstack1 = stack.copyWithCount(1); // Paper - shrink below and single item in event
+                    ServerLevel world = pointer.level();
+                    org.bukkit.block.Block block = CraftBlock.at(world, pointer.pos());
+                    CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+                    BlockDispenseArmorEvent event = new BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) list.get(0).getBukkitEntity());
+                    if (!DispenserBlock.eventFired) {
+                        world.getCraftServer().getPluginManager().callEvent(event);
+                    }
+
+                    if (event.isCancelled()) {
+                        // stack.grow(1); // Paper - shrink below
+                        return stack;
                     }
+
+                    boolean shrink = true; // Paper
+                    if (!event.getItem().equals(craftItem)) {
+                        shrink = false; // Paper - shrink below
+                        // 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) { // Paper - fix possible StackOverflowError
+                            idispensebehavior.dispense(pointer, eventStack);
+                            return stack;
+                        }
+                    }
+                    ((Saddleable) list.get(0)).equipSaddle(CraftItemStack.asNMSCopy(event.getItem()), SoundSource.BLOCKS); // Paper - track changed items in dispense event
+                    // CraftBukkit end
+                    if (shrink) stack.shrink(1); // Paper - actually handle here
+                    this.setSuccess(true);
+                    return stack;
+                } else {
+                    return super.execute(pointer, stack);
                 }
             }
-        );
-        DefaultDispenseItemBehavior defaultDispenseItemBehavior2 = new OptionalDispenseItemBehavior() {
+        });
+        OptionalDispenseItemBehavior dispensebehaviormaybe = new OptionalDispenseItemBehavior() {
             @Override
             protected ItemStack execute(BlockSource pointer, ItemStack stack) {
-                BlockPos blockPos = pointer.pos().relative(pointer.state().getValue(DispenserBlock.FACING));
+                BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
+                List<AbstractHorse> list = pointer.level().getEntitiesOfClass(AbstractHorse.class, new AABB(blockposition), (entityhorseabstract) -> {
+                    return entityhorseabstract.isAlive() && entityhorseabstract.canUseSlot(EquipmentSlot.BODY);
+                });
+                Iterator iterator1 = list.iterator();
 
-                for (AbstractHorse abstractHorse : pointer.level()
-                    .getEntitiesOfClass(AbstractHorse.class, new AABB(blockPos), horse -> horse.isAlive() && horse.canUseSlot(EquipmentSlot.BODY))) {
-                    if (abstractHorse.isBodyArmorItem(stack) && !abstractHorse.isWearingBodyArmor() && abstractHorse.isTamed()) {
-                        abstractHorse.setBodyArmorItem(stack.split(1));
-                        this.setSuccess(true);
+                AbstractHorse entityhorseabstract;
+
+                do {
+                    if (!iterator1.hasNext()) {
+                        return super.execute(pointer, stack);
+                    }
+
+                    entityhorseabstract = (AbstractHorse) iterator1.next();
+                } while (!entityhorseabstract.isBodyArmorItem(stack) || entityhorseabstract.isWearingBodyArmor() || !entityhorseabstract.isTamed());
+
+                // CraftBukkit start
+                ItemStack itemstack1 = stack.copyWithCount(1); // Paper - shrink below and single item in event
+                ServerLevel world = pointer.level();
+                org.bukkit.block.Block block = CraftBlock.at(world, pointer.pos());
+                CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+                BlockDispenseArmorEvent event = new BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) entityhorseabstract.getBukkitEntity());
+                if (!DispenserBlock.eventFired) {
+                    world.getCraftServer().getPluginManager().callEvent(event);
+                }
+
+                if (event.isCancelled()) {
+                    // stack.grow(1); // Paper - shrink below
+                    return stack;
+                }
+
+                boolean shrink = true; // Paper
+                if (!event.getItem().equals(craftItem)) {
+                    shrink = false; // Paper - shrink below
+                    // 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) { // Paper - fix possible StackOverflowError
+                        idispensebehavior.dispense(pointer, eventStack);
                         return stack;
                     }
                 }
 
-                return super.execute(pointer, stack);
+                if (shrink) stack.shrink(1); // Paper - shrink here
+                entityhorseabstract.setBodyArmorItem(CraftItemStack.asNMSCopy(event.getItem()));
+                // CraftBukkit end
+                this.setSuccess(true);
+                return stack;
             }
         };
-        DispenserBlock.registerBehavior(Items.LEATHER_HORSE_ARMOR, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.IRON_HORSE_ARMOR, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.GOLDEN_HORSE_ARMOR, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.DIAMOND_HORSE_ARMOR, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.WHITE_CARPET, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.ORANGE_CARPET, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.CYAN_CARPET, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.BLUE_CARPET, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.BROWN_CARPET, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.BLACK_CARPET, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.GRAY_CARPET, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.GREEN_CARPET, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.LIGHT_BLUE_CARPET, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.LIGHT_GRAY_CARPET, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.LIME_CARPET, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.MAGENTA_CARPET, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.PINK_CARPET, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.PURPLE_CARPET, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.RED_CARPET, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.YELLOW_CARPET, defaultDispenseItemBehavior2);
-        DispenserBlock.registerBehavior(
-            Items.CHEST,
-            new OptionalDispenseItemBehavior() {
-                @Override
-                public ItemStack execute(BlockSource pointer, ItemStack stack) {
-                    BlockPos blockPos = pointer.pos().relative(pointer.state().getValue(DispenserBlock.FACING));
 
-                    for (AbstractChestedHorse abstractChestedHorse : pointer.level()
-                        .getEntitiesOfClass(AbstractChestedHorse.class, new AABB(blockPos), donkey -> donkey.isAlive() && !donkey.hasChest())) {
-                        if (abstractChestedHorse.isTamed() && abstractChestedHorse.getSlot(499).set(stack)) {
-                            stack.shrink(1);
-                            this.setSuccess(true);
-                            return stack;
-                        }
+        DispenserBlock.registerBehavior(Items.LEATHER_HORSE_ARMOR, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.IRON_HORSE_ARMOR, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.GOLDEN_HORSE_ARMOR, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.DIAMOND_HORSE_ARMOR, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.WHITE_CARPET, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.ORANGE_CARPET, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.CYAN_CARPET, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.BLUE_CARPET, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.BROWN_CARPET, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.BLACK_CARPET, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.GRAY_CARPET, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.GREEN_CARPET, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.LIGHT_BLUE_CARPET, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.LIGHT_GRAY_CARPET, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.LIME_CARPET, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.MAGENTA_CARPET, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.PINK_CARPET, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.PURPLE_CARPET, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.RED_CARPET, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.YELLOW_CARPET, dispensebehaviormaybe);
+        DispenserBlock.registerBehavior(Items.CHEST, new OptionalDispenseItemBehavior() {
+            @Override
+            public ItemStack execute(BlockSource pointer, ItemStack stack) {
+                BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
+                List<AbstractChestedHorse> list = pointer.level().getEntitiesOfClass(AbstractChestedHorse.class, new AABB(blockposition), (entityhorsechestedabstract) -> {
+                    return entityhorsechestedabstract.isAlive() && !entityhorsechestedabstract.hasChest();
+                });
+                Iterator iterator1 = list.iterator();
+
+                AbstractChestedHorse entityhorsechestedabstract;
+
+                do {
+                    if (!iterator1.hasNext()) {
+                        return super.execute(pointer, stack);
                     }
 
-                    return super.execute(pointer, stack);
+                    entityhorsechestedabstract = (AbstractChestedHorse) iterator1.next();
+                    // CraftBukkit start
+                } while (!entityhorsechestedabstract.isTamed());
+                ItemStack itemstack1 = stack.copyWithCount(1); // Paper - shrink below
+                ServerLevel world = pointer.level();
+                org.bukkit.block.Block block = CraftBlock.at(world, pointer.pos());
+                CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+                BlockDispenseArmorEvent event = new BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) entityhorsechestedabstract.getBukkitEntity());
+                if (!DispenserBlock.eventFired) {
+                    world.getCraftServer().getPluginManager().callEvent(event);
+                }
+
+                if (event.isCancelled()) {
+                    // stack.grow(1); // Paper - shrink below (this was actually missing and should be here, added it commented out to be consistent)
+                    return stack;
                 }
+
+                boolean shrink = true; // Paper
+                if (!event.getItem().equals(craftItem)) {
+                    shrink = false; // Paper - shrink below
+                    // 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) { // Paper - fix possible StackOverflowError
+                        idispensebehavior.dispense(pointer, eventStack);
+                        return stack;
+                    }
+                }
+                entityhorsechestedabstract.getSlot(499).set(CraftItemStack.asNMSCopy(event.getItem()));
+                // CraftBukkit end
+
+                if (shrink) stack.shrink(1); // Paper - actually handle here
+                this.setSuccess(true);
+                return stack;
             }
-        );
+        });
         DispenserBlock.registerBehavior(Items.OAK_BOAT, new BoatDispenseItemBehavior(Boat.Type.OAK));
         DispenserBlock.registerBehavior(Items.SPRUCE_BOAT, new BoatDispenseItemBehavior(Boat.Type.SPRUCE));
         DispenserBlock.registerBehavior(Items.BIRCH_BOAT, new BoatDispenseItemBehavior(Boat.Type.BIRCH));
@@ -220,44 +405,118 @@
         DispenserBlock.registerBehavior(Items.CHERRY_CHEST_BOAT, new BoatDispenseItemBehavior(Boat.Type.CHERRY, true));
         DispenserBlock.registerBehavior(Items.MANGROVE_CHEST_BOAT, new BoatDispenseItemBehavior(Boat.Type.MANGROVE, true));
         DispenserBlock.registerBehavior(Items.BAMBOO_CHEST_RAFT, new BoatDispenseItemBehavior(Boat.Type.BAMBOO, true));
-        DispenseItemBehavior dispenseItemBehavior = new DefaultDispenseItemBehavior() {
+        DefaultDispenseItemBehavior dispensebehavioritem1 = new DefaultDispenseItemBehavior() {
             private final DefaultDispenseItemBehavior defaultDispenseItemBehavior = new DefaultDispenseItemBehavior();
 
             @Override
             public ItemStack execute(BlockSource pointer, ItemStack stack) {
-                DispensibleContainerItem dispensibleContainerItem = (DispensibleContainerItem)stack.getItem();
-                BlockPos blockPos = pointer.pos().relative(pointer.state().getValue(DispenserBlock.FACING));
-                Level level = pointer.level();
-                if (dispensibleContainerItem.emptyContents(null, level, blockPos, null)) {
-                    dispensibleContainerItem.checkExtraContent(null, level, stack, blockPos);
+                DispensibleContainerItem dispensiblecontaineritem = (DispensibleContainerItem) stack.getItem();
+                BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
+                ServerLevel worldserver = pointer.level();
+
+                // CraftBukkit start
+                int x = blockposition.getX();
+                int y = blockposition.getY();
+                int z = blockposition.getZ();
+                BlockState iblockdata = worldserver.getBlockState(blockposition);
+                ItemStack dispensedItem = stack; // Paper - track changed item from the dispense event
+                // Paper start - correctly check if the bucket place will succeed
+                /* Taken from SolidBucketItem#emptyContents */
+                boolean willEmptyContentsSolidBucketItem = dispensiblecontaineritem instanceof net.minecraft.world.item.SolidBucketItem && worldserver.isInWorldBounds(blockposition) && iblockdata.isAir();
+                /* Taken from BucketItem#emptyContents */
+                boolean willEmptyBucketItem = dispensiblecontaineritem instanceof final BucketItem bucketItem && bucketItem.content instanceof net.minecraft.world.level.material.FlowingFluid && (iblockdata.isAir() || iblockdata.canBeReplaced(bucketItem.content) || (iblockdata.getBlock() instanceof LiquidBlockContainer liquidBlockContainer && liquidBlockContainer.canPlaceLiquid(null, worldserver, blockposition, iblockdata, bucketItem.content)));
+                if (willEmptyContentsSolidBucketItem || willEmptyBucketItem) {
+                // Paper end - correctly check if the bucket place will succeed
+                    org.bukkit.block.Block block = CraftBlock.at(worldserver, pointer.pos());
+                    CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event
+
+                    BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(x, y, z));
+                    if (!DispenserBlock.eventFired) {
+                        worldserver.getCraftServer().getPluginManager().callEvent(event);
+                    }
+
+                    if (event.isCancelled()) {
+                        return stack;
+                    }
+
+                    if (!event.getItem().equals(craftItem)) {
+                        // 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;
+                        }
+                    }
+
+                    // Paper start - track changed item from dispense event
+                    dispensedItem = CraftItemStack.unwrap(event.getItem()); // unwrap is safe here as the stack isn't mutated
+                    dispensiblecontaineritem = (DispensibleContainerItem) dispensedItem.getItem();
+                    // Paper end - track changed item from dispense event
+                }
+                // CraftBukkit end
+
+                if (dispensiblecontaineritem.emptyContents((Player) null, worldserver, blockposition, (BlockHitResult) null)) {
+                    dispensiblecontaineritem.checkExtraContent((Player) null, worldserver, dispensedItem, blockposition); // Paper - track changed item from dispense event
                     return this.consumeWithRemainder(pointer, stack, new ItemStack(Items.BUCKET));
                 } else {
                     return this.defaultDispenseItemBehavior.dispense(pointer, stack);
                 }
             }
         };
-        DispenserBlock.registerBehavior(Items.LAVA_BUCKET, dispenseItemBehavior);
-        DispenserBlock.registerBehavior(Items.WATER_BUCKET, dispenseItemBehavior);
-        DispenserBlock.registerBehavior(Items.POWDER_SNOW_BUCKET, dispenseItemBehavior);
-        DispenserBlock.registerBehavior(Items.SALMON_BUCKET, dispenseItemBehavior);
-        DispenserBlock.registerBehavior(Items.COD_BUCKET, dispenseItemBehavior);
-        DispenserBlock.registerBehavior(Items.PUFFERFISH_BUCKET, dispenseItemBehavior);
-        DispenserBlock.registerBehavior(Items.TROPICAL_FISH_BUCKET, dispenseItemBehavior);
-        DispenserBlock.registerBehavior(Items.AXOLOTL_BUCKET, dispenseItemBehavior);
-        DispenserBlock.registerBehavior(Items.TADPOLE_BUCKET, dispenseItemBehavior);
+
+        DispenserBlock.registerBehavior(Items.LAVA_BUCKET, dispensebehavioritem1);
+        DispenserBlock.registerBehavior(Items.WATER_BUCKET, dispensebehavioritem1);
+        DispenserBlock.registerBehavior(Items.POWDER_SNOW_BUCKET, dispensebehavioritem1);
+        DispenserBlock.registerBehavior(Items.SALMON_BUCKET, dispensebehavioritem1);
+        DispenserBlock.registerBehavior(Items.COD_BUCKET, dispensebehavioritem1);
+        DispenserBlock.registerBehavior(Items.PUFFERFISH_BUCKET, dispensebehavioritem1);
+        DispenserBlock.registerBehavior(Items.TROPICAL_FISH_BUCKET, dispensebehavioritem1);
+        DispenserBlock.registerBehavior(Items.AXOLOTL_BUCKET, dispensebehavioritem1);
+        DispenserBlock.registerBehavior(Items.TADPOLE_BUCKET, dispensebehavioritem1);
         DispenserBlock.registerBehavior(Items.BUCKET, new DefaultDispenseItemBehavior() {
             @Override
             public ItemStack execute(BlockSource pointer, ItemStack stack) {
-                LevelAccessor levelAccessor = pointer.level();
-                BlockPos blockPos = pointer.pos().relative(pointer.state().getValue(DispenserBlock.FACING));
-                BlockState blockState = levelAccessor.getBlockState(blockPos);
-                if (blockState.getBlock() instanceof BucketPickup bucketPickup) {
-                    ItemStack itemStack = bucketPickup.pickupBlock(null, levelAccessor, blockPos, blockState);
-                    if (itemStack.isEmpty()) {
+                ServerLevel worldserver = pointer.level();
+                BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
+                BlockState iblockdata = worldserver.getBlockState(blockposition);
+                Block block = iblockdata.getBlock();
+
+                if (block instanceof BucketPickup ifluidsource) {
+                    ItemStack itemstack1 = ifluidsource.pickupBlock((Player) null, DummyGeneratorAccess.INSTANCE, blockposition, iblockdata); // CraftBukkit
+
+                    if (itemstack1.isEmpty()) {
                         return super.execute(pointer, stack);
                     } else {
-                        levelAccessor.gameEvent(null, GameEvent.FLUID_PICKUP, blockPos);
-                        Item item = itemStack.getItem();
+                        worldserver.gameEvent((Entity) null, (Holder) GameEvent.FLUID_PICKUP, blockposition);
+                        Item item = itemstack1.getItem();
+
+                        // CraftBukkit start
+                        org.bukkit.block.Block bukkitBlock = CraftBlock.at(worldserver, pointer.pos());
+                        CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event
+
+                        BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ()));
+                        if (!DispenserBlock.eventFired) {
+                            worldserver.getCraftServer().getPluginManager().callEvent(event);
+                        }
+
+                        if (event.isCancelled()) {
+                            return stack;
+                        }
+
+                        if (!event.getItem().equals(craftItem)) {
+                            // 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;
+                            }
+                        }
+
+                        itemstack1 = ifluidsource.pickupBlock((Player) null, worldserver, blockposition, iblockdata); // From above
+                        // CraftBukkit end
+
                         return this.consumeWithRemainder(pointer, stack, new ItemStack(item));
                     }
                 } else {
@@ -268,26 +527,58 @@
         DispenserBlock.registerBehavior(Items.FLINT_AND_STEEL, new OptionalDispenseItemBehavior() {
             @Override
             protected ItemStack execute(BlockSource pointer, ItemStack stack) {
-                ServerLevel serverLevel = pointer.level();
+                ServerLevel worldserver = pointer.level();
+
+                // CraftBukkit start
+                org.bukkit.block.Block bukkitBlock = CraftBlock.at(worldserver, pointer.pos());
+                CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack); // Paper - ignore stack size on damageable items
+
+                BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
+                if (!DispenserBlock.eventFired) {
+                    worldserver.getCraftServer().getPluginManager().callEvent(event);
+                }
+
+                if (event.isCancelled()) {
+                    return stack;
+                }
+
+                if (!event.getItem().equals(craftItem)) {
+                    // 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;
+                    }
+                }
+                // CraftBukkit end
+
                 this.setSuccess(true);
-                Direction direction = pointer.state().getValue(DispenserBlock.FACING);
-                BlockPos blockPos = pointer.pos().relative(direction);
-                BlockState blockState = serverLevel.getBlockState(blockPos);
-                if (BaseFireBlock.canBePlacedAt(serverLevel, blockPos, direction)) {
-                    serverLevel.setBlockAndUpdate(blockPos, BaseFireBlock.getState(serverLevel, blockPos));
-                    serverLevel.gameEvent(null, GameEvent.BLOCK_PLACE, blockPos);
-                } else if (CampfireBlock.canLight(blockState) || CandleBlock.canLight(blockState) || CandleCakeBlock.canLight(blockState)) {
-                    serverLevel.setBlockAndUpdate(blockPos, blockState.setValue(BlockStateProperties.LIT, Boolean.valueOf(true)));
-                    serverLevel.gameEvent(null, GameEvent.BLOCK_CHANGE, blockPos);
-                } else if (blockState.getBlock() instanceof TntBlock) {
-                    TntBlock.explode(serverLevel, blockPos);
-                    serverLevel.removeBlock(blockPos, false);
+                Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING);
+                BlockPos blockposition = pointer.pos().relative(enumdirection);
+                BlockState iblockdata = worldserver.getBlockState(blockposition);
+
+                if (BaseFireBlock.canBePlacedAt(worldserver, blockposition, enumdirection)) {
+                    // CraftBukkit start - Ignition by dispensing flint and steel
+                    if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(worldserver, blockposition, pointer.pos()).isCancelled()) {
+                        worldserver.setBlockAndUpdate(blockposition, BaseFireBlock.getState(worldserver, blockposition));
+                        worldserver.gameEvent((Entity) null, (Holder) GameEvent.BLOCK_PLACE, blockposition);
+                    }
+                    // CraftBukkit end
+                } else if (!CampfireBlock.canLight(iblockdata) && !CandleBlock.canLight(iblockdata) && !CandleCakeBlock.canLight(iblockdata)) {
+                    if (iblockdata.getBlock() instanceof TntBlock && org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(worldserver, blockposition, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.DISPENSER, null, pointer.pos())) { // CraftBukkit - TNTPrimeEvent
+                        TntBlock.explode(worldserver, blockposition);
+                        worldserver.removeBlock(blockposition, false);
+                    } else {
+                        this.setSuccess(false);
+                    }
                 } else {
-                    this.setSuccess(false);
+                    worldserver.setBlockAndUpdate(blockposition, (BlockState) iblockdata.setValue(BlockStateProperties.LIT, true));
+                    worldserver.gameEvent((Entity) null, (Holder) GameEvent.BLOCK_CHANGE, blockposition);
                 }
 
                 if (this.isSuccess()) {
-                    stack.hurtAndBreak(1, serverLevel, null, item -> {
+                    stack.hurtAndBreak(1, worldserver, (ServerPlayer) null, (item) -> {
                     });
                 }
 
@@ -298,13 +589,65 @@
             @Override
             protected ItemStack execute(BlockSource pointer, ItemStack stack) {
                 this.setSuccess(true);
-                Level level = pointer.level();
-                BlockPos blockPos = pointer.pos().relative(pointer.state().getValue(DispenserBlock.FACING));
-                if (!BoneMealItem.growCrop(stack, level, blockPos) && !BoneMealItem.growWaterPlant(stack, level, blockPos, null)) {
+                ServerLevel worldserver = pointer.level();
+                BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
+                // CraftBukkit start
+                org.bukkit.block.Block block = CraftBlock.at(worldserver, pointer.pos());
+                CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event
+
+                BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
+                if (!DispenserBlock.eventFired) {
+                    worldserver.getCraftServer().getPluginManager().callEvent(event);
+                }
+
+                if (event.isCancelled()) {
+                    return stack;
+                }
+
+                if (!event.getItem().equals(craftItem)) {
+                    // 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;
+                    }
+                }
+
+                worldserver.captureTreeGeneration = true;
+                // CraftBukkit end
+
+                if (!BoneMealItem.growCrop(stack, worldserver, blockposition) && !BoneMealItem.growWaterPlant(stack, worldserver, blockposition, (Direction) null)) {
                     this.setSuccess(false);
-                } else if (!level.isClientSide) {
-                    level.levelEvent(1505, blockPos, 15);
+                } else if (!worldserver.isClientSide) {
+                    worldserver.levelEvent(1505, blockposition, 15);
                 }
+                // CraftBukkit start
+                worldserver.captureTreeGeneration = false;
+                if (worldserver.capturedBlockStates.size() > 0) {
+                    TreeType treeType = SaplingBlock.treeType;
+                    SaplingBlock.treeType = null;
+                    Location location = CraftLocation.toBukkit(blockposition, worldserver.getWorld());
+                    List<org.bukkit.block.BlockState> blocks = new java.util.ArrayList<>(worldserver.capturedBlockStates.values());
+                    worldserver.capturedBlockStates.clear();
+                    StructureGrowEvent structureEvent = null;
+                    if (treeType != null) {
+                        structureEvent = new StructureGrowEvent(location, treeType, false, null, blocks);
+                        org.bukkit.Bukkit.getPluginManager().callEvent(structureEvent);
+                    }
+
+                    BlockFertilizeEvent fertilizeEvent = new BlockFertilizeEvent(location.getBlock(), null, blocks);
+                    fertilizeEvent.setCancelled(structureEvent != null && structureEvent.isCancelled());
+                    org.bukkit.Bukkit.getPluginManager().callEvent(fertilizeEvent);
+
+                    if (!fertilizeEvent.isCancelled()) {
+                        for (org.bukkit.block.BlockState blockstate : blocks) {
+                            blockstate.update(true);
+                            worldserver.checkCapturedTreeStateForObserverNotify(blockposition, (org.bukkit.craftbukkit.block.CraftBlockState) blockstate); // Paper - notify observers even if grow failed
+                        }
+                    }
+                }
+                // CraftBukkit end
 
                 return stack;
             }
@@ -312,128 +655,236 @@
         DispenserBlock.registerBehavior(Blocks.TNT, new DefaultDispenseItemBehavior() {
             @Override
             protected ItemStack execute(BlockSource pointer, ItemStack stack) {
-                Level level = pointer.level();
-                BlockPos blockPos = pointer.pos().relative(pointer.state().getValue(DispenserBlock.FACING));
-                PrimedTnt primedTnt = new PrimedTnt(level, (double)blockPos.getX() + 0.5, (double)blockPos.getY(), (double)blockPos.getZ() + 0.5, null);
-                level.addFreshEntity(primedTnt);
-                level.playSound(null, primedTnt.getX(), primedTnt.getY(), primedTnt.getZ(), SoundEvents.TNT_PRIMED, SoundSource.BLOCKS, 1.0F, 1.0F);
-                level.gameEvent(null, GameEvent.ENTITY_PLACE, blockPos);
-                stack.shrink(1);
+                ServerLevel worldserver = pointer.level();
+                BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
+                // CraftBukkit start
+                // EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(worldserver, (double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D, (EntityLiving) null);
+
+                ItemStack itemstack1 = stack.copyWithCount(1); // Paper - shrink at end and single item in event
+                org.bukkit.block.Block block = CraftBlock.at(worldserver, pointer.pos());
+                CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+                BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D));
+                if (!DispenserBlock.eventFired) {
+                   worldserver.getCraftServer().getPluginManager().callEvent(event);
+                }
+
+                if (event.isCancelled()) {
+                    // stack.grow(1); // Paper - shrink below
+                    return stack;
+                }
+
+                boolean shrink = true; // Paper
+                if (!event.getItem().equals(craftItem)) {
+                    shrink = false; // Paper - shrink below
+                    // 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;
+                    }
+                }
+
+                PrimedTnt entitytntprimed = new PrimedTnt(worldserver, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), (LivingEntity) null);
+                // CraftBukkit end
+
+                worldserver.addFreshEntity(entitytntprimed);
+                worldserver.playSound((Player) null, entitytntprimed.getX(), entitytntprimed.getY(), entitytntprimed.getZ(), SoundEvents.TNT_PRIMED, SoundSource.BLOCKS, 1.0F, 1.0F);
+                worldserver.gameEvent((Entity) null, (Holder) GameEvent.ENTITY_PLACE, blockposition);
+                if (shrink) stack.shrink(1); // Paper - actually handle here
                 return stack;
             }
         });
-        DispenseItemBehavior dispenseItemBehavior2 = new OptionalDispenseItemBehavior() {
+        OptionalDispenseItemBehavior dispensebehaviormaybe1 = new OptionalDispenseItemBehavior() {
             @Override
             protected ItemStack execute(BlockSource pointer, ItemStack stack) {
-                this.setSuccess(ArmorItem.dispenseArmor(pointer, stack));
+                this.setSuccess(ArmorItem.dispenseArmor(pointer, stack, this)); // Paper - fix possible StackOverflowError
                 return stack;
             }
         };
-        DispenserBlock.registerBehavior(Items.CREEPER_HEAD, dispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.ZOMBIE_HEAD, dispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.DRAGON_HEAD, dispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.SKELETON_SKULL, dispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.PIGLIN_HEAD, dispenseItemBehavior2);
-        DispenserBlock.registerBehavior(Items.PLAYER_HEAD, dispenseItemBehavior2);
-        DispenserBlock.registerBehavior(
-            Items.WITHER_SKELETON_SKULL,
-            new OptionalDispenseItemBehavior() {
-                @Override
-                protected ItemStack execute(BlockSource pointer, ItemStack stack) {
-                    Level level = pointer.level();
-                    Direction direction = pointer.state().getValue(DispenserBlock.FACING);
-                    BlockPos blockPos = pointer.pos().relative(direction);
-                    if (level.isEmptyBlock(blockPos) && WitherSkullBlock.canSpawnMob(level, blockPos, stack)) {
-                        level.setBlock(
-                            blockPos,
-                            Blocks.WITHER_SKELETON_SKULL
-                                .defaultBlockState()
-                                .setValue(SkullBlock.ROTATION, Integer.valueOf(RotationSegment.convertToSegment(direction))),
-                            3
-                        );
-                        level.gameEvent(null, GameEvent.BLOCK_PLACE, blockPos);
-                        BlockEntity blockEntity = level.getBlockEntity(blockPos);
-                        if (blockEntity instanceof SkullBlockEntity) {
-                            WitherSkullBlock.checkSpawn(level, blockPos, (SkullBlockEntity)blockEntity);
-                        }
 
-                        stack.shrink(1);
-                        this.setSuccess(true);
-                    } else {
-                        this.setSuccess(ArmorItem.dispenseArmor(pointer, stack));
-                    }
+        DispenserBlock.registerBehavior(Items.CREEPER_HEAD, dispensebehaviormaybe1);
+        DispenserBlock.registerBehavior(Items.ZOMBIE_HEAD, dispensebehaviormaybe1);
+        DispenserBlock.registerBehavior(Items.DRAGON_HEAD, dispensebehaviormaybe1);
+        DispenserBlock.registerBehavior(Items.SKELETON_SKULL, dispensebehaviormaybe1);
+        DispenserBlock.registerBehavior(Items.PIGLIN_HEAD, dispensebehaviormaybe1);
+        DispenserBlock.registerBehavior(Items.PLAYER_HEAD, dispensebehaviormaybe1);
+        DispenserBlock.registerBehavior(Items.WITHER_SKELETON_SKULL, new OptionalDispenseItemBehavior() {
+            @Override
+            protected ItemStack execute(BlockSource pointer, ItemStack stack) {
+                ServerLevel worldserver = pointer.level();
+                Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING);
+                BlockPos blockposition = pointer.pos().relative(enumdirection);
+
+                // CraftBukkit start
+                org.bukkit.block.Block bukkitBlock = CraftBlock.at(worldserver, pointer.pos());
+                CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event
 
+                BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ()));
+                if (!DispenserBlock.eventFired) {
+                    worldserver.getCraftServer().getPluginManager().callEvent(event);
+                }
+
+                if (event.isCancelled()) {
                     return stack;
                 }
+
+                if (!event.getItem().equals(craftItem)) {
+                    // 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;
+                    }
+                }
+                // CraftBukkit end
+
+                if (worldserver.isEmptyBlock(blockposition) && WitherSkullBlock.canSpawnMob(worldserver, blockposition, stack)) {
+                    worldserver.setBlock(blockposition, (BlockState) Blocks.WITHER_SKELETON_SKULL.defaultBlockState().setValue(SkullBlock.ROTATION, RotationSegment.convertToSegment(enumdirection)), 3);
+                    worldserver.gameEvent((Entity) null, (Holder) GameEvent.BLOCK_PLACE, blockposition);
+                    BlockEntity tileentity = worldserver.getBlockEntity(blockposition);
+
+                    if (tileentity instanceof SkullBlockEntity) {
+                        WitherSkullBlock.checkSpawn(worldserver, blockposition, (SkullBlockEntity) tileentity);
+                    }
+
+                    stack.shrink(1);
+                    this.setSuccess(true);
+                } else {
+                    this.setSuccess(ArmorItem.dispenseArmor(pointer, stack, this)); // Paper - fix possible StackOverflowError
+                }
+
+                return stack;
             }
-        );
+        });
         DispenserBlock.registerBehavior(Blocks.CARVED_PUMPKIN, new OptionalDispenseItemBehavior() {
             @Override
             protected ItemStack execute(BlockSource pointer, ItemStack stack) {
-                Level level = pointer.level();
-                BlockPos blockPos = pointer.pos().relative(pointer.state().getValue(DispenserBlock.FACING));
-                CarvedPumpkinBlock carvedPumpkinBlock = (CarvedPumpkinBlock)Blocks.CARVED_PUMPKIN;
-                if (level.isEmptyBlock(blockPos) && carvedPumpkinBlock.canSpawnGolem(level, blockPos)) {
-                    if (!level.isClientSide) {
-                        level.setBlock(blockPos, carvedPumpkinBlock.defaultBlockState(), 3);
-                        level.gameEvent(null, GameEvent.BLOCK_PLACE, blockPos);
+                ServerLevel worldserver = pointer.level();
+                BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
+                CarvedPumpkinBlock blockpumpkincarved = (CarvedPumpkinBlock) Blocks.CARVED_PUMPKIN;
+
+                // CraftBukkit start
+                org.bukkit.block.Block bukkitBlock = CraftBlock.at(worldserver, pointer.pos());
+                CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event
+
+                BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ()));
+                if (!DispenserBlock.eventFired) {
+                    worldserver.getCraftServer().getPluginManager().callEvent(event);
+                }
+
+                if (event.isCancelled()) {
+                    return stack;
+                }
+
+                if (!event.getItem().equals(craftItem)) {
+                    // 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;
+                    }
+                }
+                // CraftBukkit end
+
+                if (worldserver.isEmptyBlock(blockposition) && blockpumpkincarved.canSpawnGolem(worldserver, blockposition)) {
+                    if (!worldserver.isClientSide) {
+                        worldserver.setBlock(blockposition, blockpumpkincarved.defaultBlockState(), 3);
+                        worldserver.gameEvent((Entity) null, (Holder) GameEvent.BLOCK_PLACE, blockposition);
                     }
 
                     stack.shrink(1);
                     this.setSuccess(true);
                 } else {
-                    this.setSuccess(ArmorItem.dispenseArmor(pointer, stack));
+                    this.setSuccess(ArmorItem.dispenseArmor(pointer, stack, this)); // Paper - fix possible StackOverflowError
                 }
 
                 return stack;
             }
         });
         DispenserBlock.registerBehavior(Blocks.SHULKER_BOX.asItem(), new ShulkerBoxDispenseBehavior());
+        DyeColor[] aenumcolor = DyeColor.values();
+        int i = aenumcolor.length;
 
-        for (DyeColor dyeColor : DyeColor.values()) {
-            DispenserBlock.registerBehavior(ShulkerBoxBlock.getBlockByColor(dyeColor).asItem(), new ShulkerBoxDispenseBehavior());
+        for (int j = 0; j < i; ++j) {
+            DyeColor enumcolor = aenumcolor[j];
+
+            DispenserBlock.registerBehavior(ShulkerBoxBlock.getBlockByColor(enumcolor).asItem(), new ShulkerBoxDispenseBehavior());
         }
 
-        DispenserBlock.registerBehavior(
-            Items.GLASS_BOTTLE.asItem(),
-            new OptionalDispenseItemBehavior() {
-                private ItemStack takeLiquid(BlockSource pointer, ItemStack oldStack, ItemStack newStack) {
-                    pointer.level().gameEvent(null, GameEvent.FLUID_PICKUP, pointer.pos());
-                    return this.consumeWithRemainder(pointer, oldStack, newStack);
+        DispenserBlock.registerBehavior(Items.GLASS_BOTTLE.asItem(), new OptionalDispenseItemBehavior() {
+            private ItemStack takeLiquid(BlockSource pointer, ItemStack oldStack, ItemStack newStack) {
+                pointer.level().gameEvent((Entity) null, (Holder) GameEvent.FLUID_PICKUP, pointer.pos());
+                return this.consumeWithRemainder(pointer, oldStack, newStack);
+            }
+
+            @Override
+            public ItemStack execute(BlockSource pointer, ItemStack stack) {
+                this.setSuccess(false);
+                ServerLevel worldserver = pointer.level();
+                BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
+                BlockState iblockdata = worldserver.getBlockState(blockposition);
+
+                // CraftBukkit start
+                org.bukkit.block.Block bukkitBlock = CraftBlock.at(worldserver, pointer.pos());
+                CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - only single item in event
+
+                BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ()));
+                if (!DispenserBlock.eventFired) {
+                    worldserver.getCraftServer().getPluginManager().callEvent(event);
                 }
 
-                @Override
-                public ItemStack execute(BlockSource pointer, ItemStack stack) {
-                    this.setSuccess(false);
-                    ServerLevel serverLevel = pointer.level();
-                    BlockPos blockPos = pointer.pos().relative(pointer.state().getValue(DispenserBlock.FACING));
-                    BlockState blockState = serverLevel.getBlockState(blockPos);
-                    if (blockState.is(BlockTags.BEEHIVES, state -> state.hasProperty(BeehiveBlock.HONEY_LEVEL) && state.getBlock() instanceof BeehiveBlock)
-                        && blockState.getValue(BeehiveBlock.HONEY_LEVEL) >= 5) {
-                        ((BeehiveBlock)blockState.getBlock())
-                            .releaseBeesAndResetHoneyLevel(serverLevel, blockState, blockPos, null, BeehiveBlockEntity.BeeReleaseStatus.BEE_RELEASED);
-                        this.setSuccess(true);
-                        return this.takeLiquid(pointer, stack, new ItemStack(Items.HONEY_BOTTLE));
-                    } else if (serverLevel.getFluidState(blockPos).is(FluidTags.WATER)) {
-                        this.setSuccess(true);
-                        return this.takeLiquid(pointer, stack, PotionContents.createItemStack(Items.POTION, Potions.WATER));
-                    } else {
-                        return super.execute(pointer, stack);
+                if (event.isCancelled()) {
+                    return stack;
+                }
+
+                if (!event.getItem().equals(craftItem)) {
+                    // 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;
                     }
                 }
+                // CraftBukkit end
+
+                if (iblockdata.is(BlockTags.BEEHIVES, (blockbase_blockdata) -> {
+                    return blockbase_blockdata.hasProperty(BeehiveBlock.HONEY_LEVEL) && blockbase_blockdata.getBlock() instanceof BeehiveBlock;
+                }) && (Integer) iblockdata.getValue(BeehiveBlock.HONEY_LEVEL) >= 5) {
+                    ((BeehiveBlock) iblockdata.getBlock()).releaseBeesAndResetHoneyLevel(worldserver, iblockdata, blockposition, (Player) null, BeehiveBlockEntity.BeeReleaseStatus.BEE_RELEASED);
+                    this.setSuccess(true);
+                    return this.takeLiquid(pointer, stack, new ItemStack(Items.HONEY_BOTTLE));
+                } else if (worldserver.getFluidState(blockposition).is(FluidTags.WATER)) {
+                    this.setSuccess(true);
+                    return this.takeLiquid(pointer, stack, PotionContents.createItemStack(Items.POTION, Potions.WATER));
+                } else {
+                    return super.execute(pointer, stack);
+                }
             }
-        );
+        });
         DispenserBlock.registerBehavior(Items.GLOWSTONE, new OptionalDispenseItemBehavior() {
             @Override
             public ItemStack execute(BlockSource pointer, ItemStack stack) {
-                Direction direction = pointer.state().getValue(DispenserBlock.FACING);
-                BlockPos blockPos = pointer.pos().relative(direction);
-                Level level = pointer.level();
-                BlockState blockState = level.getBlockState(blockPos);
+                Direction enumdirection = (Direction) pointer.state().getValue(DispenserBlock.FACING);
+                BlockPos blockposition = pointer.pos().relative(enumdirection);
+                ServerLevel worldserver = pointer.level();
+                BlockState iblockdata = worldserver.getBlockState(blockposition);
+
                 this.setSuccess(true);
-                if (blockState.is(Blocks.RESPAWN_ANCHOR)) {
-                    if (blockState.getValue(RespawnAnchorBlock.CHARGE) != 4) {
-                        RespawnAnchorBlock.charge(null, level, blockPos, blockState);
+                if (iblockdata.is(Blocks.RESPAWN_ANCHOR)) {
+                    if ((Integer) iblockdata.getValue(RespawnAnchorBlock.CHARGE) != 4) {
+                        // Paper start - Call missing BlockDispenseEvent
+                        ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(pointer, blockposition, stack, this);
+                        if (result != null) {
+                            this.setSuccess(false);
+                            return result;
+                        }
+                        // Paper end - Call missing BlockDispenseEvent
+                        RespawnAnchorBlock.charge((Entity) null, worldserver, blockposition, iblockdata);
                         stack.shrink(1);
                     } else {
                         this.setSuccess(false);
@@ -449,22 +900,54 @@
         DispenserBlock.registerBehavior(Items.BRUSH.asItem(), new OptionalDispenseItemBehavior() {
             @Override
             protected ItemStack execute(BlockSource pointer, ItemStack stack) {
-                ServerLevel serverLevel = pointer.level();
-                BlockPos blockPos = pointer.pos().relative(pointer.state().getValue(DispenserBlock.FACING));
-                List<Armadillo> list = serverLevel.getEntitiesOfClass(Armadillo.class, new AABB(blockPos), EntitySelector.NO_SPECTATORS);
+                ServerLevel worldserver = pointer.level();
+                BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
+                List<Armadillo> list = worldserver.getEntitiesOfClass(Armadillo.class, new AABB(blockposition), EntitySelector.NO_SPECTATORS);
+
                 if (list.isEmpty()) {
                     this.setSuccess(false);
                     return stack;
                 } else {
-                    for (Armadillo armadillo : list) {
-                        if (armadillo.brushOffScute()) {
-                            stack.hurtAndBreak(16, serverLevel, null, item -> {
-                            });
+                    // CraftBukkit start
+                    ItemStack itemstack1 = stack;
+                    ServerLevel world = pointer.level();
+                    org.bukkit.block.Block block = CraftBlock.at(world, pointer.pos());
+                    CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+                    BlockDispenseEvent event = new BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) list.get(0).getBukkitEntity());
+                    if (!DispenserBlock.eventFired) {
+                        world.getCraftServer().getPluginManager().callEvent(event);
+                    }
+
+                    if (event.isCancelled()) {
+                        return stack;
+                    }
+
+                    if (!event.getItem().equals(craftItem)) {
+                        // 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) { // Paper - fix possible StackOverflowError
+                            idispensebehavior.dispense(pointer, eventStack);
                             return stack;
                         }
                     }
+                    // CraftBukkit end
+                    Iterator iterator1 = list.iterator();
 
-                    this.setSuccess(false);
+                    Armadillo armadillo;
+
+                    do {
+                        if (!iterator1.hasNext()) {
+                            this.setSuccess(false);
+                            return stack;
+                        }
+
+                        armadillo = (Armadillo) iterator1.next();
+                    } while (!armadillo.brushOffScute());
+
+                    stack.hurtAndBreak(16, worldserver, (ServerPlayer) null, (item) -> {
+                    });
                     return stack;
                 }
             }
@@ -472,13 +955,21 @@
         DispenserBlock.registerBehavior(Items.HONEYCOMB, new OptionalDispenseItemBehavior() {
             @Override
             public ItemStack execute(BlockSource pointer, ItemStack stack) {
-                BlockPos blockPos = pointer.pos().relative(pointer.state().getValue(DispenserBlock.FACING));
-                Level level = pointer.level();
-                BlockState blockState = level.getBlockState(blockPos);
-                Optional<BlockState> optional = HoneycombItem.getWaxed(blockState);
+                BlockPos blockposition = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
+                ServerLevel worldserver = pointer.level();
+                BlockState iblockdata = worldserver.getBlockState(blockposition);
+                Optional<BlockState> optional = HoneycombItem.getWaxed(iblockdata);
+
                 if (optional.isPresent()) {
-                    level.setBlockAndUpdate(blockPos, optional.get());
-                    level.levelEvent(3003, blockPos, 0);
+                    // Paper start - Call missing BlockDispenseEvent
+                    ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(pointer, blockposition, stack, this);
+                    if (result != null) {
+                        this.setSuccess(false);
+                        return result;
+                    }
+                    // Paper end - Call missing BlockDispenseEvent
+                    worldserver.setBlockAndUpdate(blockposition, (BlockState) optional.get());
+                    worldserver.levelEvent(3003, blockposition, 0);
                     stack.shrink(1);
                     this.setSuccess(true);
                     return stack;
@@ -487,47 +978,42 @@
                 }
             }
         });
-        DispenserBlock.registerBehavior(
-            Items.POTION,
-            new DefaultDispenseItemBehavior() {
-                private final DefaultDispenseItemBehavior defaultDispenseItemBehavior = new DefaultDispenseItemBehavior();
+        DispenserBlock.registerBehavior(Items.POTION, new DefaultDispenseItemBehavior() {
+            private final DefaultDispenseItemBehavior defaultDispenseItemBehavior = new DefaultDispenseItemBehavior();
 
-                @Override
-                public ItemStack execute(BlockSource pointer, ItemStack stack) {
-                    PotionContents potionContents = stack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY);
-                    if (!potionContents.is(Potions.WATER)) {
+            @Override
+            public ItemStack execute(BlockSource pointer, ItemStack stack) {
+                PotionContents potioncontents = (PotionContents) stack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY);
+
+                if (!potioncontents.is(Potions.WATER)) {
+                    return this.defaultDispenseItemBehavior.dispense(pointer, stack);
+                } else {
+                    ServerLevel worldserver = pointer.level();
+                    BlockPos blockposition = pointer.pos();
+                    BlockPos blockposition1 = pointer.pos().relative((Direction) pointer.state().getValue(DispenserBlock.FACING));
+
+                    if (!worldserver.getBlockState(blockposition1).is(BlockTags.CONVERTABLE_TO_MUD)) {
                         return this.defaultDispenseItemBehavior.dispense(pointer, stack);
                     } else {
-                        ServerLevel serverLevel = pointer.level();
-                        BlockPos blockPos = pointer.pos();
-                        BlockPos blockPos2 = pointer.pos().relative(pointer.state().getValue(DispenserBlock.FACING));
-                        if (!serverLevel.getBlockState(blockPos2).is(BlockTags.CONVERTABLE_TO_MUD)) {
-                            return this.defaultDispenseItemBehavior.dispense(pointer, stack);
-                        } else {
-                            if (!serverLevel.isClientSide) {
-                                for (int i = 0; i < 5; i++) {
-                                    serverLevel.sendParticles(
-                                        ParticleTypes.SPLASH,
-                                        (double)blockPos.getX() + serverLevel.random.nextDouble(),
-                                        (double)(blockPos.getY() + 1),
-                                        (double)blockPos.getZ() + serverLevel.random.nextDouble(),
-                                        1,
-                                        0.0,
-                                        0.0,
-                                        0.0,
-                                        1.0
-                                    );
-                                }
+                        // Paper start - Call missing BlockDispenseEvent
+                        ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(pointer, blockposition1, stack, this);
+                        if (result != null) {
+                            return result;
+                        }
+                        // Paper end - Call missing BlockDispenseEvent
+                        if (!worldserver.isClientSide) {
+                            for (int k = 0; k < 5; ++k) {
+                                worldserver.sendParticles(ParticleTypes.SPLASH, (double) blockposition.getX() + worldserver.random.nextDouble(), (double) (blockposition.getY() + 1), (double) blockposition.getZ() + worldserver.random.nextDouble(), 1, 0.0D, 0.0D, 0.0D, 1.0D);
                             }
-
-                            serverLevel.playSound(null, blockPos, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F);
-                            serverLevel.gameEvent(null, GameEvent.FLUID_PLACE, blockPos);
-                            serverLevel.setBlockAndUpdate(blockPos2, Blocks.MUD.defaultBlockState());
-                            return this.consumeWithRemainder(pointer, stack, new ItemStack(Items.GLASS_BOTTLE));
                         }
+
+                        worldserver.playSound((Player) null, blockposition, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F);
+                        worldserver.gameEvent((Entity) null, (Holder) GameEvent.FLUID_PLACE, blockposition);
+                        worldserver.setBlockAndUpdate(blockposition1, Blocks.MUD.defaultBlockState());
+                        return this.consumeWithRemainder(pointer, stack, new ItemStack(Items.GLASS_BOTTLE));
                     }
                 }
             }
-        );
+        });
     }
 }
