--- a/net/minecraft/world/level/block/LayeredCauldronBlock.java
+++ b/net/minecraft/world/level/block/LayeredCauldronBlock.java
@@ -3,6 +3,7 @@
 import com.mojang.serialization.MapCodec;
 import com.mojang.serialization.codecs.RecordCodecBuilder;
 import net.minecraft.core.BlockPos;
+import net.minecraft.core.Holder;
 import net.minecraft.core.cauldron.CauldronInteraction;
 import net.minecraft.world.entity.Entity;
 import net.minecraft.world.level.Level;
@@ -15,37 +16,42 @@
 import net.minecraft.world.level.gameevent.GameEvent;
 import net.minecraft.world.level.material.Fluid;
 import net.minecraft.world.level.material.Fluids;
+// CraftBukkit start
+import org.bukkit.craftbukkit.block.CraftBlockState;
+import org.bukkit.craftbukkit.block.CraftBlockStates;
+import org.bukkit.event.block.CauldronLevelChangeEvent;
+// CraftBukkit end
 
 public class LayeredCauldronBlock extends AbstractCauldronBlock {
-    public static final MapCodec<LayeredCauldronBlock> CODEC = RecordCodecBuilder.mapCodec(
-        instance -> instance.group(
-                    Biome.Precipitation.CODEC.fieldOf("precipitation").forGetter(block -> block.precipitationType),
-                    CauldronInteraction.CODEC.fieldOf("interactions").forGetter(block -> block.interactions),
-                    propertiesCodec()
-                )
-                .apply(instance, LayeredCauldronBlock::new)
-    );
+
+    public static final MapCodec<LayeredCauldronBlock> CODEC = RecordCodecBuilder.mapCodec((instance) -> {
+        return instance.group(Biome.Precipitation.CODEC.fieldOf("precipitation").forGetter((layeredcauldronblock) -> {
+            return layeredcauldronblock.precipitationType;
+        }), CauldronInteraction.CODEC.fieldOf("interactions").forGetter((layeredcauldronblock) -> {
+            return layeredcauldronblock.interactions;
+        }), propertiesCodec()).apply(instance, LayeredCauldronBlock::new);
+    });
     public static final int MIN_FILL_LEVEL = 1;
     public static final int MAX_FILL_LEVEL = 3;
     public static final IntegerProperty LEVEL = BlockStateProperties.LEVEL_CAULDRON;
     private static final int BASE_CONTENT_HEIGHT = 6;
-    private static final double HEIGHT_PER_LEVEL = 3.0;
+    private static final double HEIGHT_PER_LEVEL = 3.0D;
     private final Biome.Precipitation precipitationType;
 
     @Override
     public MapCodec<LayeredCauldronBlock> codec() {
-        return CODEC;
+        return LayeredCauldronBlock.CODEC;
     }
 
     public LayeredCauldronBlock(Biome.Precipitation precipitation, CauldronInteraction.InteractionMap behaviorMap, BlockBehaviour.Properties settings) {
         super(settings, behaviorMap);
         this.precipitationType = precipitation;
-        this.registerDefaultState(this.stateDefinition.any().setValue(LEVEL, Integer.valueOf(1)));
+        this.registerDefaultState((BlockState) ((BlockState) this.stateDefinition.any()).setValue(LayeredCauldronBlock.LEVEL, 1));
     }
 
     @Override
     public boolean isFull(BlockState state) {
-        return state.getValue(LEVEL) == 3;
+        return (Integer) state.getValue(LayeredCauldronBlock.LEVEL) == 3;
     }
 
     @Override
@@ -55,59 +61,110 @@
 
     @Override
     protected double getContentHeight(BlockState state) {
-        return (6.0 + (double)state.getValue(LEVEL).intValue() * 3.0) / 16.0;
+        return (6.0D + (double) (Integer) state.getValue(LayeredCauldronBlock.LEVEL) * 3.0D) / 16.0D;
     }
 
     @Override
     protected void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) {
+        if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent
         if (!world.isClientSide && entity.isOnFire() && this.isEntityInsideContent(state, pos, entity)) {
-            entity.clearFire();
-            if (entity.mayInteract(world, pos)) {
-                this.handleEntityOnFireInside(state, world, pos);
+            // CraftBukkit start
+            if ((entity instanceof net.minecraft.world.entity.player.Player || world.getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING)) && entity.mayInteract(world, pos)) { // Paper - Fixes MC-248588
+                if (!this.handleEntityOnFireInsideWithEvent(state, world, pos, entity)) { // Paper - fix powdered snow cauldron extinguishing entities
+                    return;
+                }
             }
+            entity.clearFire();
+            // CraftBukkit end
         }
+
     }
 
+    @io.papermc.paper.annotation.DoNotUse @Deprecated // Paper - fix powdered snow cauldron extinguishing entities; use #handleEntityOnFireInsideWithEvent
     private void handleEntityOnFireInside(BlockState state, Level world, BlockPos pos) {
         if (this.precipitationType == Biome.Precipitation.SNOW) {
-            lowerFillLevel(Blocks.WATER_CAULDRON.defaultBlockState().setValue(LEVEL, state.getValue(LEVEL)), world, pos);
+            LayeredCauldronBlock.lowerFillLevel((BlockState) Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, (Integer) state.getValue(LayeredCauldronBlock.LEVEL)), world, pos);
         } else {
-            lowerFillLevel(state, world, pos);
+            LayeredCauldronBlock.lowerFillLevel(state, world, pos);
         }
+
     }
+    // Paper start - fix powdered snow cauldron extinguishing entities
+    protected boolean handleEntityOnFireInsideWithEvent(BlockState state, Level world, BlockPos pos, Entity entity) {
+        if (this.precipitationType == Biome.Precipitation.SNOW) {
+            return LayeredCauldronBlock.lowerFillLevel((BlockState) Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, (Integer) state.getValue(LayeredCauldronBlock.LEVEL)), world, pos, entity, CauldronLevelChangeEvent.ChangeReason.EXTINGUISH);
+        } else {
+            return LayeredCauldronBlock.lowerFillLevel(state, world, pos, entity, CauldronLevelChangeEvent.ChangeReason.EXTINGUISH);
+        }
+    }
+    // Paper end - fix powdered snow cauldron extinguishing entities
 
     public static void lowerFillLevel(BlockState state, Level world, BlockPos pos) {
-        int i = state.getValue(LEVEL) - 1;
-        BlockState blockState = i == 0 ? Blocks.CAULDRON.defaultBlockState() : state.setValue(LEVEL, Integer.valueOf(i));
-        world.setBlockAndUpdate(pos, blockState);
-        world.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(blockState));
+        // CraftBukkit start
+        LayeredCauldronBlock.lowerFillLevel(state, world, pos, null, CauldronLevelChangeEvent.ChangeReason.UNKNOWN);
+    }
+
+    public static boolean lowerFillLevel(BlockState iblockdata, Level world, BlockPos blockposition, Entity entity, CauldronLevelChangeEvent.ChangeReason reason) {
+        int i = (Integer) iblockdata.getValue(LayeredCauldronBlock.LEVEL) - 1;
+        BlockState iblockdata1 = i == 0 ? Blocks.CAULDRON.defaultBlockState() : (BlockState) iblockdata.setValue(LayeredCauldronBlock.LEVEL, i);
+
+        return LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, iblockdata1, entity, reason);
+    }
+
+    // CraftBukkit start
+    // Paper start - Call CauldronLevelChangeEvent
+    public static boolean changeLevel(BlockState iblockdata, Level world, BlockPos blockposition, BlockState newBlock, @javax.annotation.Nullable Entity entity, CauldronLevelChangeEvent.ChangeReason reason) { // Paper - entity is nullable
+        return changeLevel(iblockdata, world, blockposition, newBlock, entity, reason, true);
     }
 
+    public static boolean changeLevel(BlockState iblockdata, Level world, BlockPos blockposition, BlockState newBlock, @javax.annotation.Nullable Entity entity, CauldronLevelChangeEvent.ChangeReason reason, boolean sendGameEvent) { // Paper - entity is nullable
+    // Paper end - Call CauldronLevelChangeEvent
+        CraftBlockState newState = CraftBlockStates.getBlockState(world, blockposition);
+        newState.setData(newBlock);
+
+        CauldronLevelChangeEvent event = new CauldronLevelChangeEvent(
+                world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()),
+                (entity == null) ? null : entity.getBukkitEntity(), reason, newState
+        );
+        world.getCraftServer().getPluginManager().callEvent(event);
+        if (event.isCancelled()) {
+            return false;
+        }
+        newState.update(true);
+        if (sendGameEvent) world.gameEvent((Holder) GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of(newBlock)); // Paper - Call CauldronLevelChangeEvent
+        return true;
+    }
+    // CraftBukkit end
+
     @Override
     public void handlePrecipitation(BlockState state, Level world, BlockPos pos, Biome.Precipitation precipitation) {
-        if (CauldronBlock.shouldHandlePrecipitation(world, precipitation) && state.getValue(LEVEL) != 3 && precipitation == this.precipitationType) {
-            BlockState blockState = state.cycle(LEVEL);
-            world.setBlockAndUpdate(pos, blockState);
-            world.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(blockState));
+        if (CauldronBlock.shouldHandlePrecipitation(world, precipitation) && (Integer) state.getValue(LayeredCauldronBlock.LEVEL) != 3 && precipitation == this.precipitationType) {
+            BlockState iblockdata1 = (BlockState) state.cycle(LayeredCauldronBlock.LEVEL);
+
+            LayeredCauldronBlock.changeLevel(state, world, pos, iblockdata1, null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL); // CraftBukkit
         }
     }
 
     @Override
     protected int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) {
-        return state.getValue(LEVEL);
+        return (Integer) state.getValue(LayeredCauldronBlock.LEVEL);
     }
 
     @Override
     protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
-        builder.add(LEVEL);
+        builder.add(LayeredCauldronBlock.LEVEL);
     }
 
     @Override
     protected void receiveStalactiteDrip(BlockState state, Level world, BlockPos pos, Fluid fluid) {
         if (!this.isFull(state)) {
-            BlockState blockState = state.setValue(LEVEL, Integer.valueOf(state.getValue(LEVEL) + 1));
-            world.setBlockAndUpdate(pos, blockState);
-            world.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(blockState));
+            BlockState iblockdata1 = (BlockState) state.setValue(LayeredCauldronBlock.LEVEL, (Integer) state.getValue(LayeredCauldronBlock.LEVEL) + 1);
+
+            // CraftBukkit start
+            if (!LayeredCauldronBlock.changeLevel(state, world, pos, iblockdata1, null, CauldronLevelChangeEvent.ChangeReason.NATURAL_FILL)) {
+                return;
+            }
+            // CraftBukkit end
             world.levelEvent(1047, pos, 0);
         }
     }
