--- a/net/minecraft/core/cauldron/CauldronInteraction.java
+++ b/net/minecraft/core/cauldron/CauldronInteraction.java
@@ -33,9 +33,15 @@
 import net.minecraft.world.level.block.state.IBlockData;
 import net.minecraft.world.level.gameevent.GameEvent;
 
+// CraftBukkit start
+import org.bukkit.event.block.CauldronLevelChangeEvent;
+// CraftBukkit end
+
 public interface CauldronInteraction {
 
     Map<String, CauldronInteraction.a> INTERACTIONS = new Object2ObjectArrayMap();
+    // CraftBukkit start - decompile error
+    /*
     Codec<CauldronInteraction.a> CODEC;
     CauldronInteraction.a EMPTY;
     CauldronInteraction.a WATER;
@@ -47,6 +53,8 @@
     CauldronInteraction SHULKER_BOX;
     CauldronInteraction BANNER;
     CauldronInteraction DYED_ITEM;
+     */
+    // CraftBukkit end
 
     static CauldronInteraction.a newInteractionMap(String s) {
         Object2ObjectOpenHashMap<Item, CauldronInteraction> object2objectopenhashmap = new Object2ObjectOpenHashMap();
@@ -71,12 +79,17 @@
                 return EnumInteractionResult.PASS;
             } else {
                 if (!world.isClientSide) {
+                    // CraftBukkit start
+                    if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, Blocks.WATER_CAULDRON.defaultBlockState(), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) {
+                        return EnumInteractionResult.SUCCESS;
+                    }
+                    // CraftBukkit end
                     Item item = itemstack.getItem();
 
                     entityhuman.setItemInHand(enumhand, ItemLiquidUtil.createFilledResult(itemstack, entityhuman, new ItemStack(Items.GLASS_BOTTLE)));
                     entityhuman.awardStat(StatisticList.USE_CAULDRON);
                     entityhuman.awardStat(StatisticList.ITEM_USED.get(item));
-                    world.setBlockAndUpdate(blockposition, Blocks.WATER_CAULDRON.defaultBlockState());
+                    // world.setBlockAndUpdate(blockposition, Blocks.WATER_CAULDRON.defaultBlockState()); // CraftBukkit
                     world.playSound((EntityHuman) null, blockposition, SoundEffects.BOTTLE_EMPTY, SoundCategory.BLOCKS, 1.0F, 1.0F);
                     world.gameEvent((Entity) null, GameEvent.FLUID_PLACE, blockposition);
                 }
@@ -94,12 +107,17 @@
         });
         map1.put(Items.GLASS_BOTTLE, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
             if (!world.isClientSide) {
+                // CraftBukkit start
+                if (!LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition, entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_FILL)) {
+                    return EnumInteractionResult.SUCCESS;
+                }
+                // CraftBukkit end
                 Item item = itemstack.getItem();
 
                 entityhuman.setItemInHand(enumhand, ItemLiquidUtil.createFilledResult(itemstack, entityhuman, PotionUtil.setPotion(new ItemStack(Items.POTION), Potions.WATER)));
                 entityhuman.awardStat(StatisticList.USE_CAULDRON);
                 entityhuman.awardStat(StatisticList.ITEM_USED.get(item));
-                LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition);
+                // LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition); // CraftBukkit
                 world.playSound((EntityHuman) null, blockposition, SoundEffects.BOTTLE_FILL, SoundCategory.BLOCKS, 1.0F, 1.0F);
                 world.gameEvent((Entity) null, GameEvent.FLUID_PICKUP, blockposition);
             }
@@ -109,10 +127,15 @@
         map1.put(Items.POTION, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
             if ((Integer) iblockdata.getValue(LayeredCauldronBlock.LEVEL) != 3 && PotionUtil.getPotion(itemstack) == Potions.WATER) {
                 if (!world.isClientSide) {
+                    // CraftBukkit start
+                    if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, iblockdata.cycle(LayeredCauldronBlock.LEVEL), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) {
+                        return EnumInteractionResult.SUCCESS;
+                    }
+                    // CraftBukkit end
                     entityhuman.setItemInHand(enumhand, ItemLiquidUtil.createFilledResult(itemstack, entityhuman, new ItemStack(Items.GLASS_BOTTLE)));
                     entityhuman.awardStat(StatisticList.USE_CAULDRON);
                     entityhuman.awardStat(StatisticList.ITEM_USED.get(itemstack.getItem()));
-                    world.setBlockAndUpdate(blockposition, (IBlockData) iblockdata.cycle(LayeredCauldronBlock.LEVEL));
+                    // world.setBlockAndUpdate(blockposition, (IBlockData) iblockdata.cycle(LayeredCauldronBlock.LEVEL)); // CraftBukkit
                     world.playSound((EntityHuman) null, blockposition, SoundEffects.BOTTLE_EMPTY, SoundCategory.BLOCKS, 1.0F, 1.0F);
                     world.gameEvent((Entity) null, GameEvent.FLUID_PLACE, blockposition);
                 }
@@ -188,12 +211,17 @@
             return EnumInteractionResult.PASS;
         } else {
             if (!world.isClientSide) {
+                // CraftBukkit start
+                if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, Blocks.CAULDRON.defaultBlockState(), entityhuman, CauldronLevelChangeEvent.ChangeReason.BUCKET_FILL)) {
+                    return EnumInteractionResult.SUCCESS;
+                }
+                // CraftBukkit end
                 Item item = itemstack.getItem();
 
                 entityhuman.setItemInHand(enumhand, ItemLiquidUtil.createFilledResult(itemstack, entityhuman, itemstack1));
                 entityhuman.awardStat(StatisticList.USE_CAULDRON);
                 entityhuman.awardStat(StatisticList.ITEM_USED.get(item));
-                world.setBlockAndUpdate(blockposition, Blocks.CAULDRON.defaultBlockState());
+                // world.setBlockAndUpdate(blockposition, Blocks.CAULDRON.defaultBlockState()); // CraftBukkit
                 world.playSound((EntityHuman) null, blockposition, soundeffect, SoundCategory.BLOCKS, 1.0F, 1.0F);
                 world.gameEvent((Entity) null, GameEvent.FLUID_PICKUP, blockposition);
             }
@@ -204,12 +232,17 @@
 
     static EnumInteractionResult emptyBucket(World world, BlockPosition blockposition, EntityHuman entityhuman, EnumHand enumhand, ItemStack itemstack, IBlockData iblockdata, SoundEffect soundeffect) {
         if (!world.isClientSide) {
+            // CraftBukkit start
+            if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, iblockdata, entityhuman, CauldronLevelChangeEvent.ChangeReason.BUCKET_EMPTY)) {
+                return EnumInteractionResult.SUCCESS;
+            }
+            // CraftBukkit end
             Item item = itemstack.getItem();
 
             entityhuman.setItemInHand(enumhand, ItemLiquidUtil.createFilledResult(itemstack, entityhuman, new ItemStack(Items.BUCKET)));
             entityhuman.awardStat(StatisticList.FILL_CAULDRON);
             entityhuman.awardStat(StatisticList.ITEM_USED.get(item));
-            world.setBlockAndUpdate(blockposition, iblockdata);
+            // world.setBlockAndUpdate(blockposition, iblockdata); // CraftBukkit
             world.playSound((EntityHuman) null, blockposition, soundeffect, SoundCategory.BLOCKS, 1.0F, 1.0F);
             world.gameEvent((Entity) null, GameEvent.FLUID_PLACE, blockposition);
         }
@@ -217,32 +250,35 @@
         return EnumInteractionResult.sidedSuccess(world.isClientSide);
     }
 
-    static {
-        Function function = CauldronInteraction.a::name;
-        Map map = CauldronInteraction.INTERACTIONS;
-
-        Objects.requireNonNull(map);
-        CODEC = ExtraCodecs.stringResolverCodec(function, map::get);
-        EMPTY = newInteractionMap("empty");
-        WATER = newInteractionMap("water");
-        LAVA = newInteractionMap("lava");
-        POWDER_SNOW = newInteractionMap("powder_snow");
-        FILL_WATER = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+    // CraftBukkit start - decompile errors
+    // static {
+        Codec<CauldronInteraction.a> CODEC = ExtraCodecs.stringResolverCodec(CauldronInteraction.a::name, CauldronInteraction.INTERACTIONS::get);
+        CauldronInteraction.a EMPTY = newInteractionMap("empty");
+        CauldronInteraction.a WATER = newInteractionMap("water");
+        CauldronInteraction.a LAVA = newInteractionMap("lava");
+        CauldronInteraction.a POWDER_SNOW = newInteractionMap("powder_snow");
+        CauldronInteraction FILL_WATER = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
             return emptyBucket(world, blockposition, entityhuman, enumhand, itemstack, (IBlockData) Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), SoundEffects.BUCKET_EMPTY);
         };
-        FILL_LAVA = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+        CauldronInteraction FILL_LAVA = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
             return emptyBucket(world, blockposition, entityhuman, enumhand, itemstack, Blocks.LAVA_CAULDRON.defaultBlockState(), SoundEffects.BUCKET_EMPTY_LAVA);
         };
-        FILL_POWDER_SNOW = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+        CauldronInteraction FILL_POWDER_SNOW = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
             return emptyBucket(world, blockposition, entityhuman, enumhand, itemstack, (IBlockData) Blocks.POWDER_SNOW_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), SoundEffects.BUCKET_EMPTY_POWDER_SNOW);
         };
-        SHULKER_BOX = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+        CauldronInteraction SHULKER_BOX = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+            // CraftBukkit end
             Block block = Block.byItem(itemstack.getItem());
 
             if (!(block instanceof BlockShulkerBox)) {
                 return EnumInteractionResult.PASS;
             } else {
                 if (!world.isClientSide) {
+                    // CraftBukkit start
+                    if (!LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition, entityhuman, CauldronLevelChangeEvent.ChangeReason.SHULKER_WASH)) {
+                        return EnumInteractionResult.SUCCESS;
+                    }
+                    // CraftBukkit end
                     ItemStack itemstack1 = new ItemStack(Blocks.SHULKER_BOX);
 
                     if (itemstack.hasTag()) {
@@ -251,17 +287,22 @@
 
                     entityhuman.setItemInHand(enumhand, itemstack1);
                     entityhuman.awardStat(StatisticList.CLEAN_SHULKER_BOX);
-                    LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition);
+                    // LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition); // CraftBukkit
                 }
 
                 return EnumInteractionResult.sidedSuccess(world.isClientSide);
             }
         };
-        BANNER = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+        CauldronInteraction BANNER = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> { // CraftBukkit - decompile error
             if (TileEntityBanner.getPatternCount(itemstack) <= 0) {
                 return EnumInteractionResult.PASS;
             } else {
                 if (!world.isClientSide) {
+                    // CraftBukkit start
+                    if (!LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition, entityhuman, CauldronLevelChangeEvent.ChangeReason.BANNER_WASH)) {
+                        return EnumInteractionResult.SUCCESS;
+                    }
+                    // CraftBukkit end
                     ItemStack itemstack1 = itemstack.copyWithCount(1);
 
                     TileEntityBanner.removeLastPattern(itemstack1);
@@ -278,13 +319,13 @@
                     }
 
                     entityhuman.awardStat(StatisticList.CLEAN_BANNER);
-                    LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition);
+                    // LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition); // CraftBukkit
                 }
 
                 return EnumInteractionResult.sidedSuccess(world.isClientSide);
             }
         };
-        DYED_ITEM = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+        CauldronInteraction DYED_ITEM = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> { // CraftBukkit - decompile error
             Item item = itemstack.getItem();
 
             if (!(item instanceof IDyeable)) {
@@ -296,16 +337,21 @@
                     return EnumInteractionResult.PASS;
                 } else {
                     if (!world.isClientSide) {
+                        // CraftBukkit start
+                        if (!LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition, entityhuman, CauldronLevelChangeEvent.ChangeReason.ARMOR_WASH)) {
+                            return EnumInteractionResult.SUCCESS;
+                        }
+                        // CraftBukkit end
                         idyeable.clearColor(itemstack);
                         entityhuman.awardStat(StatisticList.CLEAN_ARMOR);
-                        LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition);
+                        // LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition); // CraftBukkit
                     }
 
                     return EnumInteractionResult.sidedSuccess(world.isClientSide);
                 }
             }
         };
-    }
+    // } // CraftBukkit - decompile error
 
     public static record a(String name, Map<Item, CauldronInteraction> map) {
 
