--- a/net/minecraft/core/cauldron/CauldronInteraction.java
+++ b/net/minecraft/core/cauldron/CauldronInteraction.java
@@ -29,86 +29,114 @@
 import net.minecraft.world.level.block.state.BlockState;
 import net.minecraft.world.level.gameevent.GameEvent;
 
+// CraftBukkit start
+import org.bukkit.event.block.CauldronLevelChangeEvent;
+// CraftBukkit end
+
 public interface CauldronInteraction {
-    Map<Item, CauldronInteraction> EMPTY = newInteractionMap();
-    Map<Item, CauldronInteraction> WATER = newInteractionMap();
-    Map<Item, CauldronInteraction> LAVA = newInteractionMap();
-    Map<Item, CauldronInteraction> POWDER_SNOW = newInteractionMap();
-    CauldronInteraction FILL_WATER = (state, world, pos, player, hand, stack) -> {
-        return emptyBucket(world, pos, player, hand, stack, Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, Integer.valueOf(3)), SoundEvents.BUCKET_EMPTY);
+
+    Map<Item, CauldronInteraction> EMPTY = CauldronInteraction.newInteractionMap();
+    Map<Item, CauldronInteraction> WATER = CauldronInteraction.newInteractionMap();
+    Map<Item, CauldronInteraction> LAVA = CauldronInteraction.newInteractionMap();
+    Map<Item, CauldronInteraction> POWDER_SNOW = CauldronInteraction.newInteractionMap();
+    CauldronInteraction FILL_WATER = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+        return CauldronInteraction.emptyBucket(world, blockposition, entityhuman, enumhand, itemstack, (BlockState) Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), SoundEvents.BUCKET_EMPTY);
     };
-    CauldronInteraction FILL_LAVA = (state, world, pos, player, hand, stack) -> {
-        return emptyBucket(world, pos, player, hand, stack, Blocks.LAVA_CAULDRON.defaultBlockState(), SoundEvents.BUCKET_EMPTY_LAVA);
+    CauldronInteraction FILL_LAVA = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+        return CauldronInteraction.emptyBucket(world, blockposition, entityhuman, enumhand, itemstack, Blocks.LAVA_CAULDRON.defaultBlockState(), SoundEvents.BUCKET_EMPTY_LAVA);
     };
-    CauldronInteraction FILL_POWDER_SNOW = (state, world, pos, player, hand, stack) -> {
-        return emptyBucket(world, pos, player, hand, stack, Blocks.POWDER_SNOW_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, Integer.valueOf(3)), SoundEvents.BUCKET_EMPTY_POWDER_SNOW);
+    CauldronInteraction FILL_POWDER_SNOW = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+        return CauldronInteraction.emptyBucket(world, blockposition, entityhuman, enumhand, itemstack, (BlockState) Blocks.POWDER_SNOW_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), SoundEvents.BUCKET_EMPTY_POWDER_SNOW);
     };
-    CauldronInteraction SHULKER_BOX = (state, world, pos, player, hand, stack) -> {
-        Block block = Block.byItem(stack.getItem());
+    CauldronInteraction SHULKER_BOX = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+        Block block = Block.byItem(itemstack.getItem());
+
         if (!(block instanceof ShulkerBoxBlock)) {
             return InteractionResult.PASS;
         } else {
             if (!world.isClientSide) {
-                ItemStack itemStack = new ItemStack(Blocks.SHULKER_BOX);
-                if (stack.hasTag()) {
-                    itemStack.setTag(stack.getTag().copy());
+                // CraftBukkit start
+                if (!LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition, entityhuman, CauldronLevelChangeEvent.ChangeReason.SHULKER_WASH)) {
+                    return InteractionResult.SUCCESS;
                 }
+                // CraftBukkit end
+                ItemStack itemstack1 = new ItemStack(Blocks.SHULKER_BOX);
 
-                player.setItemInHand(hand, itemStack);
-                player.awardStat(Stats.CLEAN_SHULKER_BOX);
-                LayeredCauldronBlock.lowerFillLevel(state, world, pos);
+                if (itemstack.hasTag()) {
+                    itemstack1.setTag(itemstack.getTag().copy());
+                }
+
+                entityhuman.setItemInHand(enumhand, itemstack1);
+                entityhuman.awardStat(Stats.CLEAN_SHULKER_BOX);
+                // LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition); // CraftBukkit
             }
 
             return InteractionResult.sidedSuccess(world.isClientSide);
         }
     };
-    CauldronInteraction BANNER = (state, world, pos, player, hand, stack) -> {
-        if (BannerBlockEntity.getPatternCount(stack) <= 0) {
+    CauldronInteraction BANNER = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+        if (BannerBlockEntity.getPatternCount(itemstack) <= 0) {
             return InteractionResult.PASS;
         } else {
             if (!world.isClientSide) {
-                ItemStack itemStack = stack.copy();
-                itemStack.setCount(1);
-                BannerBlockEntity.removeLastPattern(itemStack);
-                if (!player.getAbilities().instabuild) {
-                    stack.shrink(1);
+                // CraftBukkit start
+                if (!LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition, entityhuman, CauldronLevelChangeEvent.ChangeReason.BANNER_WASH)) {
+                    return InteractionResult.SUCCESS;
                 }
+                // CraftBukkit end
+                ItemStack itemstack1 = itemstack.copy();
 
-                if (stack.isEmpty()) {
-                    player.setItemInHand(hand, itemStack);
-                } else if (player.getInventory().add(itemStack)) {
-                    player.inventoryMenu.sendAllDataToRemote();
+                itemstack1.setCount(1);
+                BannerBlockEntity.removeLastPattern(itemstack1);
+                if (!entityhuman.getAbilities().instabuild) {
+                    itemstack.shrink(1);
+                }
+
+                if (itemstack.isEmpty()) {
+                    entityhuman.setItemInHand(enumhand, itemstack1);
+                } else if (entityhuman.getInventory().add(itemstack1)) {
+                    entityhuman.inventoryMenu.sendAllDataToRemote();
                 } else {
-                    player.drop(itemStack, false);
+                    entityhuman.drop(itemstack1, false);
                 }
 
-                player.awardStat(Stats.CLEAN_BANNER);
-                LayeredCauldronBlock.lowerFillLevel(state, world, pos);
+                entityhuman.awardStat(Stats.CLEAN_BANNER);
+                // LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition); // CraftBukkit
             }
 
             return InteractionResult.sidedSuccess(world.isClientSide);
         }
     };
-    CauldronInteraction DYED_ITEM = (state, world, pos, player, hand, stack) -> {
-        Item item = stack.getItem();
-        if (!(item instanceof DyeableLeatherItem dyeableLeatherItem)) {
-            return InteractionResult.PASS;
-        } else if (!dyeableLeatherItem.hasCustomColor(stack)) {
+    CauldronInteraction DYED_ITEM = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+        Item item = itemstack.getItem();
+
+        if (!(item instanceof DyeableLeatherItem)) {
             return InteractionResult.PASS;
         } else {
-            if (!world.isClientSide) {
-                dyeableLeatherItem.clearColor(stack);
-                player.awardStat(Stats.CLEAN_ARMOR);
-                LayeredCauldronBlock.lowerFillLevel(state, world, pos);
-            }
+            DyeableLeatherItem idyeable = (DyeableLeatherItem) item;
 
-            return InteractionResult.sidedSuccess(world.isClientSide);
+            if (!idyeable.hasCustomColor(itemstack)) {
+                return InteractionResult.PASS;
+            } else {
+                if (!world.isClientSide) {
+                    // CraftBukkit start
+                    if (!LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition, entityhuman, CauldronLevelChangeEvent.ChangeReason.ARMOR_WASH)) {
+                        return InteractionResult.SUCCESS;
+                    }
+                    // CraftBukkit end
+                    idyeable.clearColor(itemstack);
+                    entityhuman.awardStat(Stats.CLEAN_ARMOR);
+                    // LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition); // CraftBukkit
+                }
+
+                return InteractionResult.sidedSuccess(world.isClientSide);
+            }
         }
     };
 
     static Object2ObjectOpenHashMap<Item, CauldronInteraction> newInteractionMap() {
-        return Util.make(new Object2ObjectOpenHashMap<>(), (map) -> {
-            map.defaultReturnValue((state, world, pos, player, hand, stack) -> {
+        return Util.make(new Object2ObjectOpenHashMap<>(), (object2objectopenhashmap) -> { // CraftBukkit - decompile error
+            object2objectopenhashmap.defaultReturnValue((iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
                 return InteractionResult.PASS;
             });
         });
@@ -117,52 +145,69 @@
     InteractionResult interact(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, ItemStack stack);
 
     static void bootStrap() {
-        addDefaultInteractions(EMPTY);
-        EMPTY.put(Items.POTION, (state, world, pos, player, hand, stack) -> {
-            if (PotionUtils.getPotion(stack) != Potions.WATER) {
+        CauldronInteraction.addDefaultInteractions(CauldronInteraction.EMPTY);
+        CauldronInteraction.EMPTY.put(Items.POTION, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+            if (PotionUtils.getPotion(itemstack) != Potions.WATER) {
                 return InteractionResult.PASS;
             } else {
                 if (!world.isClientSide) {
-                    Item item = stack.getItem();
-                    player.setItemInHand(hand, ItemUtils.createFilledResult(stack, player, new ItemStack(Items.GLASS_BOTTLE)));
-                    player.awardStat(Stats.USE_CAULDRON);
-                    player.awardStat(Stats.ITEM_USED.get(item));
-                    world.setBlockAndUpdate(pos, Blocks.WATER_CAULDRON.defaultBlockState());
-                    world.playSound((Player)null, pos, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F);
-                    world.gameEvent((Entity)null, GameEvent.FLUID_PLACE, pos);
+                    // CraftBukkit start
+                    if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, Blocks.WATER_CAULDRON.defaultBlockState(), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) {
+                        return InteractionResult.SUCCESS;
+                    }
+                    // CraftBukkit end
+                    Item item = itemstack.getItem();
+
+                    entityhuman.setItemInHand(enumhand, ItemUtils.createFilledResult(itemstack, entityhuman, new ItemStack(Items.GLASS_BOTTLE)));
+                    entityhuman.awardStat(Stats.USE_CAULDRON);
+                    entityhuman.awardStat(Stats.ITEM_USED.get(item));
+                    // world.setBlockAndUpdate(blockposition, Blocks.WATER_CAULDRON.defaultBlockState()); // CraftBukkit
+                    world.playSound((Player) null, blockposition, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F);
+                    world.gameEvent((Entity) null, GameEvent.FLUID_PLACE, blockposition);
                 }
 
                 return InteractionResult.sidedSuccess(world.isClientSide);
             }
         });
-        addDefaultInteractions(WATER);
-        WATER.put(Items.BUCKET, (state, world, pos, player, hand, stack) -> {
-            return fillBucket(state, world, pos, player, hand, stack, new ItemStack(Items.WATER_BUCKET), (statex) -> {
-                return statex.getValue(LayeredCauldronBlock.LEVEL) == 3;
+        CauldronInteraction.addDefaultInteractions(CauldronInteraction.WATER);
+        CauldronInteraction.WATER.put(Items.BUCKET, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+            return CauldronInteraction.fillBucket(iblockdata, world, blockposition, entityhuman, enumhand, itemstack, new ItemStack(Items.WATER_BUCKET), (iblockdata1) -> {
+                return (Integer) iblockdata1.getValue(LayeredCauldronBlock.LEVEL) == 3;
             }, SoundEvents.BUCKET_FILL);
         });
-        WATER.put(Items.GLASS_BOTTLE, (state, world, pos, player, hand, stack) -> {
+        CauldronInteraction.WATER.put(Items.GLASS_BOTTLE, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
             if (!world.isClientSide) {
-                Item item = stack.getItem();
-                player.setItemInHand(hand, ItemUtils.createFilledResult(stack, player, PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.WATER)));
-                player.awardStat(Stats.USE_CAULDRON);
-                player.awardStat(Stats.ITEM_USED.get(item));
-                LayeredCauldronBlock.lowerFillLevel(state, world, pos);
-                world.playSound((Player)null, pos, SoundEvents.BOTTLE_FILL, SoundSource.BLOCKS, 1.0F, 1.0F);
-                world.gameEvent((Entity)null, GameEvent.FLUID_PICKUP, pos);
+                // CraftBukkit start
+                if (!LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition, entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_FILL)) {
+                    return InteractionResult.SUCCESS;
+                }
+                // CraftBukkit end
+                Item item = itemstack.getItem();
+
+                entityhuman.setItemInHand(enumhand, ItemUtils.createFilledResult(itemstack, entityhuman, PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.WATER)));
+                entityhuman.awardStat(Stats.USE_CAULDRON);
+                entityhuman.awardStat(Stats.ITEM_USED.get(item));
+                // LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition); // CraftBukkit
+                world.playSound((Player) null, blockposition, SoundEvents.BOTTLE_FILL, SoundSource.BLOCKS, 1.0F, 1.0F);
+                world.gameEvent((Entity) null, GameEvent.FLUID_PICKUP, blockposition);
             }
 
             return InteractionResult.sidedSuccess(world.isClientSide);
         });
-        WATER.put(Items.POTION, (state, world, pos, player, hand, stack) -> {
-            if (state.getValue(LayeredCauldronBlock.LEVEL) != 3 && PotionUtils.getPotion(stack) == Potions.WATER) {
+        CauldronInteraction.WATER.put(Items.POTION, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+            if ((Integer) iblockdata.getValue(LayeredCauldronBlock.LEVEL) != 3 && PotionUtils.getPotion(itemstack) == Potions.WATER) {
                 if (!world.isClientSide) {
-                    player.setItemInHand(hand, ItemUtils.createFilledResult(stack, player, new ItemStack(Items.GLASS_BOTTLE)));
-                    player.awardStat(Stats.USE_CAULDRON);
-                    player.awardStat(Stats.ITEM_USED.get(stack.getItem()));
-                    world.setBlockAndUpdate(pos, state.cycle(LayeredCauldronBlock.LEVEL));
-                    world.playSound((Player)null, pos, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F);
-                    world.gameEvent((Entity)null, GameEvent.FLUID_PLACE, pos);
+                    // CraftBukkit start
+                    if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, iblockdata.cycle(LayeredCauldronBlock.LEVEL), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) {
+                        return InteractionResult.SUCCESS;
+                    }
+                    // CraftBukkit end
+                    entityhuman.setItemInHand(enumhand, ItemUtils.createFilledResult(itemstack, entityhuman, new ItemStack(Items.GLASS_BOTTLE)));
+                    entityhuman.awardStat(Stats.USE_CAULDRON);
+                    entityhuman.awardStat(Stats.ITEM_USED.get(itemstack.getItem()));
+                    // world.setBlockAndUpdate(blockposition, (IBlockData) iblockdata.cycle(LayeredCauldronBlock.LEVEL)); // CraftBukkit
+                    world.playSound((Player) null, blockposition, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F);
+                    world.gameEvent((Entity) null, GameEvent.FLUID_PLACE, blockposition);
                 }
 
                 return InteractionResult.sidedSuccess(world.isClientSide);
@@ -170,61 +215,61 @@
                 return InteractionResult.PASS;
             }
         });
-        WATER.put(Items.LEATHER_BOOTS, DYED_ITEM);
-        WATER.put(Items.LEATHER_LEGGINGS, DYED_ITEM);
-        WATER.put(Items.LEATHER_CHESTPLATE, DYED_ITEM);
-        WATER.put(Items.LEATHER_HELMET, DYED_ITEM);
-        WATER.put(Items.LEATHER_HORSE_ARMOR, DYED_ITEM);
-        WATER.put(Items.WHITE_BANNER, BANNER);
-        WATER.put(Items.GRAY_BANNER, BANNER);
-        WATER.put(Items.BLACK_BANNER, BANNER);
-        WATER.put(Items.BLUE_BANNER, BANNER);
-        WATER.put(Items.BROWN_BANNER, BANNER);
-        WATER.put(Items.CYAN_BANNER, BANNER);
-        WATER.put(Items.GREEN_BANNER, BANNER);
-        WATER.put(Items.LIGHT_BLUE_BANNER, BANNER);
-        WATER.put(Items.LIGHT_GRAY_BANNER, BANNER);
-        WATER.put(Items.LIME_BANNER, BANNER);
-        WATER.put(Items.MAGENTA_BANNER, BANNER);
-        WATER.put(Items.ORANGE_BANNER, BANNER);
-        WATER.put(Items.PINK_BANNER, BANNER);
-        WATER.put(Items.PURPLE_BANNER, BANNER);
-        WATER.put(Items.RED_BANNER, BANNER);
-        WATER.put(Items.YELLOW_BANNER, BANNER);
-        WATER.put(Items.WHITE_SHULKER_BOX, SHULKER_BOX);
-        WATER.put(Items.GRAY_SHULKER_BOX, SHULKER_BOX);
-        WATER.put(Items.BLACK_SHULKER_BOX, SHULKER_BOX);
-        WATER.put(Items.BLUE_SHULKER_BOX, SHULKER_BOX);
-        WATER.put(Items.BROWN_SHULKER_BOX, SHULKER_BOX);
-        WATER.put(Items.CYAN_SHULKER_BOX, SHULKER_BOX);
-        WATER.put(Items.GREEN_SHULKER_BOX, SHULKER_BOX);
-        WATER.put(Items.LIGHT_BLUE_SHULKER_BOX, SHULKER_BOX);
-        WATER.put(Items.LIGHT_GRAY_SHULKER_BOX, SHULKER_BOX);
-        WATER.put(Items.LIME_SHULKER_BOX, SHULKER_BOX);
-        WATER.put(Items.MAGENTA_SHULKER_BOX, SHULKER_BOX);
-        WATER.put(Items.ORANGE_SHULKER_BOX, SHULKER_BOX);
-        WATER.put(Items.PINK_SHULKER_BOX, SHULKER_BOX);
-        WATER.put(Items.PURPLE_SHULKER_BOX, SHULKER_BOX);
-        WATER.put(Items.RED_SHULKER_BOX, SHULKER_BOX);
-        WATER.put(Items.YELLOW_SHULKER_BOX, SHULKER_BOX);
-        LAVA.put(Items.BUCKET, (state, world, pos, player, hand, stack) -> {
-            return fillBucket(state, world, pos, player, hand, stack, new ItemStack(Items.LAVA_BUCKET), (statex) -> {
+        CauldronInteraction.WATER.put(Items.LEATHER_BOOTS, CauldronInteraction.DYED_ITEM);
+        CauldronInteraction.WATER.put(Items.LEATHER_LEGGINGS, CauldronInteraction.DYED_ITEM);
+        CauldronInteraction.WATER.put(Items.LEATHER_CHESTPLATE, CauldronInteraction.DYED_ITEM);
+        CauldronInteraction.WATER.put(Items.LEATHER_HELMET, CauldronInteraction.DYED_ITEM);
+        CauldronInteraction.WATER.put(Items.LEATHER_HORSE_ARMOR, CauldronInteraction.DYED_ITEM);
+        CauldronInteraction.WATER.put(Items.WHITE_BANNER, CauldronInteraction.BANNER);
+        CauldronInteraction.WATER.put(Items.GRAY_BANNER, CauldronInteraction.BANNER);
+        CauldronInteraction.WATER.put(Items.BLACK_BANNER, CauldronInteraction.BANNER);
+        CauldronInteraction.WATER.put(Items.BLUE_BANNER, CauldronInteraction.BANNER);
+        CauldronInteraction.WATER.put(Items.BROWN_BANNER, CauldronInteraction.BANNER);
+        CauldronInteraction.WATER.put(Items.CYAN_BANNER, CauldronInteraction.BANNER);
+        CauldronInteraction.WATER.put(Items.GREEN_BANNER, CauldronInteraction.BANNER);
+        CauldronInteraction.WATER.put(Items.LIGHT_BLUE_BANNER, CauldronInteraction.BANNER);
+        CauldronInteraction.WATER.put(Items.LIGHT_GRAY_BANNER, CauldronInteraction.BANNER);
+        CauldronInteraction.WATER.put(Items.LIME_BANNER, CauldronInteraction.BANNER);
+        CauldronInteraction.WATER.put(Items.MAGENTA_BANNER, CauldronInteraction.BANNER);
+        CauldronInteraction.WATER.put(Items.ORANGE_BANNER, CauldronInteraction.BANNER);
+        CauldronInteraction.WATER.put(Items.PINK_BANNER, CauldronInteraction.BANNER);
+        CauldronInteraction.WATER.put(Items.PURPLE_BANNER, CauldronInteraction.BANNER);
+        CauldronInteraction.WATER.put(Items.RED_BANNER, CauldronInteraction.BANNER);
+        CauldronInteraction.WATER.put(Items.YELLOW_BANNER, CauldronInteraction.BANNER);
+        CauldronInteraction.WATER.put(Items.WHITE_SHULKER_BOX, CauldronInteraction.SHULKER_BOX);
+        CauldronInteraction.WATER.put(Items.GRAY_SHULKER_BOX, CauldronInteraction.SHULKER_BOX);
+        CauldronInteraction.WATER.put(Items.BLACK_SHULKER_BOX, CauldronInteraction.SHULKER_BOX);
+        CauldronInteraction.WATER.put(Items.BLUE_SHULKER_BOX, CauldronInteraction.SHULKER_BOX);
+        CauldronInteraction.WATER.put(Items.BROWN_SHULKER_BOX, CauldronInteraction.SHULKER_BOX);
+        CauldronInteraction.WATER.put(Items.CYAN_SHULKER_BOX, CauldronInteraction.SHULKER_BOX);
+        CauldronInteraction.WATER.put(Items.GREEN_SHULKER_BOX, CauldronInteraction.SHULKER_BOX);
+        CauldronInteraction.WATER.put(Items.LIGHT_BLUE_SHULKER_BOX, CauldronInteraction.SHULKER_BOX);
+        CauldronInteraction.WATER.put(Items.LIGHT_GRAY_SHULKER_BOX, CauldronInteraction.SHULKER_BOX);
+        CauldronInteraction.WATER.put(Items.LIME_SHULKER_BOX, CauldronInteraction.SHULKER_BOX);
+        CauldronInteraction.WATER.put(Items.MAGENTA_SHULKER_BOX, CauldronInteraction.SHULKER_BOX);
+        CauldronInteraction.WATER.put(Items.ORANGE_SHULKER_BOX, CauldronInteraction.SHULKER_BOX);
+        CauldronInteraction.WATER.put(Items.PINK_SHULKER_BOX, CauldronInteraction.SHULKER_BOX);
+        CauldronInteraction.WATER.put(Items.PURPLE_SHULKER_BOX, CauldronInteraction.SHULKER_BOX);
+        CauldronInteraction.WATER.put(Items.RED_SHULKER_BOX, CauldronInteraction.SHULKER_BOX);
+        CauldronInteraction.WATER.put(Items.YELLOW_SHULKER_BOX, CauldronInteraction.SHULKER_BOX);
+        CauldronInteraction.LAVA.put(Items.BUCKET, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+            return CauldronInteraction.fillBucket(iblockdata, world, blockposition, entityhuman, enumhand, itemstack, new ItemStack(Items.LAVA_BUCKET), (iblockdata1) -> {
                 return true;
             }, SoundEvents.BUCKET_FILL_LAVA);
         });
-        addDefaultInteractions(LAVA);
-        POWDER_SNOW.put(Items.BUCKET, (state, world, pos, player, hand, stack) -> {
-            return fillBucket(state, world, pos, player, hand, stack, new ItemStack(Items.POWDER_SNOW_BUCKET), (statex) -> {
-                return statex.getValue(LayeredCauldronBlock.LEVEL) == 3;
+        CauldronInteraction.addDefaultInteractions(CauldronInteraction.LAVA);
+        CauldronInteraction.POWDER_SNOW.put(Items.BUCKET, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+            return CauldronInteraction.fillBucket(iblockdata, world, blockposition, entityhuman, enumhand, itemstack, new ItemStack(Items.POWDER_SNOW_BUCKET), (iblockdata1) -> {
+                return (Integer) iblockdata1.getValue(LayeredCauldronBlock.LEVEL) == 3;
             }, SoundEvents.BUCKET_FILL_POWDER_SNOW);
         });
-        addDefaultInteractions(POWDER_SNOW);
+        CauldronInteraction.addDefaultInteractions(CauldronInteraction.POWDER_SNOW);
     }
 
     static void addDefaultInteractions(Map<Item, CauldronInteraction> behavior) {
-        behavior.put(Items.LAVA_BUCKET, FILL_LAVA);
-        behavior.put(Items.WATER_BUCKET, FILL_WATER);
-        behavior.put(Items.POWDER_SNOW_BUCKET, FILL_POWDER_SNOW);
+        behavior.put(Items.LAVA_BUCKET, CauldronInteraction.FILL_LAVA);
+        behavior.put(Items.WATER_BUCKET, CauldronInteraction.FILL_WATER);
+        behavior.put(Items.POWDER_SNOW_BUCKET, CauldronInteraction.FILL_POWDER_SNOW);
     }
 
     static InteractionResult fillBucket(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, ItemStack stack, ItemStack output, Predicate<BlockState> fullPredicate, SoundEvent soundEvent) {
@@ -232,13 +277,19 @@
             return InteractionResult.PASS;
         } else {
             if (!world.isClientSide) {
+                // CraftBukkit start
+                if (!LayeredCauldronBlock.changeLevel(state, world, pos, Blocks.CAULDRON.defaultBlockState(), player, CauldronLevelChangeEvent.ChangeReason.BUCKET_FILL)) {
+                    return InteractionResult.SUCCESS;
+                }
+                // CraftBukkit end
                 Item item = stack.getItem();
+
                 player.setItemInHand(hand, ItemUtils.createFilledResult(stack, player, output));
                 player.awardStat(Stats.USE_CAULDRON);
                 player.awardStat(Stats.ITEM_USED.get(item));
-                world.setBlockAndUpdate(pos, Blocks.CAULDRON.defaultBlockState());
-                world.playSound((Player)null, pos, soundEvent, SoundSource.BLOCKS, 1.0F, 1.0F);
-                world.gameEvent((Entity)null, GameEvent.FLUID_PICKUP, pos);
+                // world.setBlockAndUpdate(blockposition, Blocks.CAULDRON.defaultBlockState()); // CraftBukkit
+                world.playSound((Player) null, pos, soundEvent, SoundSource.BLOCKS, 1.0F, 1.0F);
+                world.gameEvent((Entity) null, GameEvent.FLUID_PICKUP, pos);
             }
 
             return InteractionResult.sidedSuccess(world.isClientSide);
@@ -247,13 +298,19 @@
 
     static InteractionResult emptyBucket(Level world, BlockPos pos, Player player, InteractionHand hand, ItemStack stack, BlockState state, SoundEvent soundEvent) {
         if (!world.isClientSide) {
+            // CraftBukkit start
+            if (!LayeredCauldronBlock.changeLevel(state, world, pos, state, player, CauldronLevelChangeEvent.ChangeReason.BUCKET_EMPTY)) {
+                return InteractionResult.SUCCESS;
+            }
+            // CraftBukkit end
             Item item = stack.getItem();
+
             player.setItemInHand(hand, ItemUtils.createFilledResult(stack, player, new ItemStack(Items.BUCKET)));
             player.awardStat(Stats.FILL_CAULDRON);
             player.awardStat(Stats.ITEM_USED.get(item));
-            world.setBlockAndUpdate(pos, state);
-            world.playSound((Player)null, pos, soundEvent, SoundSource.BLOCKS, 1.0F, 1.0F);
-            world.gameEvent((Entity)null, GameEvent.FLUID_PLACE, pos);
+            // world.setBlockAndUpdate(blockposition, iblockdata); // CraftBukkit
+            world.playSound((Player) null, pos, soundEvent, SoundSource.BLOCKS, 1.0F, 1.0F);
+            world.gameEvent((Entity) null, GameEvent.FLUID_PLACE, pos);
         }
 
         return InteractionResult.sidedSuccess(world.isClientSide);
