--- a/net/minecraft/world/level/block/CakeBlock.java
+++ b/net/minecraft/world/level/block/CakeBlock.java
@@ -3,6 +3,7 @@
 import com.mojang.serialization.MapCodec;
 import net.minecraft.core.BlockPos;
 import net.minecraft.core.Direction;
+import net.minecraft.core.Holder;
 import net.minecraft.sounds.SoundEvents;
 import net.minecraft.sounds.SoundSource;
 import net.minecraft.stats.Stats;
@@ -10,6 +11,7 @@
 import net.minecraft.world.InteractionHand;
 import net.minecraft.world.InteractionResult;
 import net.minecraft.world.ItemInteractionResult;
+import net.minecraft.world.entity.Entity;
 import net.minecraft.world.entity.player.Player;
 import net.minecraft.world.item.Item;
 import net.minecraft.world.item.ItemStack;
@@ -29,58 +31,62 @@
 import net.minecraft.world.phys.shapes.VoxelShape;
 
 public class CakeBlock extends Block {
+
     public static final MapCodec<CakeBlock> CODEC = simpleCodec(CakeBlock::new);
     public static final int MAX_BITES = 6;
     public static final IntegerProperty BITES = BlockStateProperties.BITES;
-    public static final int FULL_CAKE_SIGNAL = getOutputSignal(0);
+    public static final int FULL_CAKE_SIGNAL = CakeBlock.getOutputSignal(0);
     protected static final float AABB_OFFSET = 1.0F;
     protected static final float AABB_SIZE_PER_BITE = 2.0F;
-    protected static final VoxelShape[] SHAPE_BY_BITE = new VoxelShape[]{
-        Block.box(1.0, 0.0, 1.0, 15.0, 8.0, 15.0),
-        Block.box(3.0, 0.0, 1.0, 15.0, 8.0, 15.0),
-        Block.box(5.0, 0.0, 1.0, 15.0, 8.0, 15.0),
-        Block.box(7.0, 0.0, 1.0, 15.0, 8.0, 15.0),
-        Block.box(9.0, 0.0, 1.0, 15.0, 8.0, 15.0),
-        Block.box(11.0, 0.0, 1.0, 15.0, 8.0, 15.0),
-        Block.box(13.0, 0.0, 1.0, 15.0, 8.0, 15.0)
-    };
+    protected static final VoxelShape[] SHAPE_BY_BITE = new VoxelShape[]{Block.box(1.0D, 0.0D, 1.0D, 15.0D, 8.0D, 15.0D), Block.box(3.0D, 0.0D, 1.0D, 15.0D, 8.0D, 15.0D), Block.box(5.0D, 0.0D, 1.0D, 15.0D, 8.0D, 15.0D), Block.box(7.0D, 0.0D, 1.0D, 15.0D, 8.0D, 15.0D), Block.box(9.0D, 0.0D, 1.0D, 15.0D, 8.0D, 15.0D), Block.box(11.0D, 0.0D, 1.0D, 15.0D, 8.0D, 15.0D), Block.box(13.0D, 0.0D, 1.0D, 15.0D, 8.0D, 15.0D)};
 
     @Override
     public MapCodec<CakeBlock> codec() {
-        return CODEC;
+        return CakeBlock.CODEC;
     }
 
     protected CakeBlock(BlockBehaviour.Properties settings) {
         super(settings);
-        this.registerDefaultState(this.stateDefinition.any().setValue(BITES, Integer.valueOf(0)));
+        this.registerDefaultState((BlockState) ((BlockState) this.stateDefinition.any()).setValue(CakeBlock.BITES, 0));
     }
 
     @Override
     protected VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) {
-        return SHAPE_BY_BITE[state.getValue(BITES)];
+        return CakeBlock.SHAPE_BY_BITE[(Integer) state.getValue(CakeBlock.BITES)];
     }
 
     @Override
-    protected ItemInteractionResult useItemOn(
-        ItemStack stack, BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit
-    ) {
+    protected ItemInteractionResult useItemOn(ItemStack stack, BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
         Item item = stack.getItem();
-        if (stack.is(ItemTags.CANDLES) && state.getValue(BITES) == 0 && Block.byItem(item) instanceof CandleBlock candleBlock) {
-            stack.consume(1, player);
-            world.playSound(null, pos, SoundEvents.CAKE_ADD_CANDLE, SoundSource.BLOCKS, 1.0F, 1.0F);
-            world.setBlockAndUpdate(pos, CandleCakeBlock.byCandle(candleBlock));
-            world.gameEvent(player, GameEvent.BLOCK_CHANGE, pos);
-            player.awardStat(Stats.ITEM_USED.get(item));
-            return ItemInteractionResult.SUCCESS;
-        } else {
-            return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
+
+        if (stack.is(ItemTags.CANDLES) && (Integer) state.getValue(CakeBlock.BITES) == 0) {
+            Block block = Block.byItem(item);
+
+            if (block instanceof CandleBlock) {
+                CandleBlock candleblock = (CandleBlock) block;
+
+                // Paper start - call change block event
+                if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, CandleCakeBlock.byCandle(candleblock))) {
+                    player.containerMenu.sendAllDataToRemote(); // update inv because candle could decrease
+                    return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
+                }
+                // Paper end - call change block event
+                stack.consume(1, player);
+                world.playSound((Player) null, pos, SoundEvents.CAKE_ADD_CANDLE, SoundSource.BLOCKS, 1.0F, 1.0F);
+                world.setBlockAndUpdate(pos, CandleCakeBlock.byCandle(candleblock));
+                world.gameEvent((Entity) player, (Holder) GameEvent.BLOCK_CHANGE, pos);
+                player.awardStat(Stats.ITEM_USED.get(item));
+                return ItemInteractionResult.SUCCESS;
+            }
         }
+
+        return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
     }
 
     @Override
     protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) {
         if (world.isClientSide) {
-            if (eat(world, pos, state, player).consumesAction()) {
+            if (CakeBlock.eat(world, pos, state, player).consumesAction()) {
                 return InteractionResult.SUCCESS;
             }
 
@@ -89,22 +95,42 @@
             }
         }
 
-        return eat(world, pos, state, player);
+        return CakeBlock.eat(world, pos, state, player);
     }
 
     protected static InteractionResult eat(LevelAccessor world, BlockPos pos, BlockState state, Player player) {
         if (!player.canEat(false)) {
             return InteractionResult.PASS;
         } else {
+            // Paper start - call change block event
+            int i = state.getValue(CakeBlock.BITES);
+            final BlockState newState = i < MAX_BITES ? state.setValue(CakeBlock.BITES, i + 1) : world.getFluidState(pos).createLegacyBlock();
+            if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, newState)) {
+                ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity().sendHealthUpdate();
+                return InteractionResult.PASS; // return a non-consume result to cake blocks don't drop their candles
+            }
+            // Paper end - call change block event
             player.awardStat(Stats.EAT_CAKE_SLICE);
-            player.getFoodData().eat(2, 0.1F);
-            int i = state.getValue(BITES);
-            world.gameEvent(player, GameEvent.EAT, pos);
+            // CraftBukkit start
+            // entityhuman.getFoodData().eat(2, 0.1F);
+            int oldFoodLevel = player.getFoodData().foodLevel;
+
+            org.bukkit.event.entity.FoodLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFoodLevelChangeEvent(player, 2 + oldFoodLevel);
+
+            if (!event.isCancelled()) {
+                player.getFoodData().eat(event.getFoodLevel() - oldFoodLevel, 0.1F);
+            }
+
+            ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity().sendHealthUpdate();
+            // CraftBukkit end
+            // Paper - move up
+
+            world.gameEvent((Entity) player, (Holder) GameEvent.EAT, pos);
             if (i < 6) {
-                world.setBlock(pos, state.setValue(BITES, Integer.valueOf(i + 1)), 3);
+                world.setBlock(pos, (BlockState) state.setValue(CakeBlock.BITES, i + 1), 3);
             } else {
                 world.removeBlock(pos, false);
-                world.gameEvent(player, GameEvent.BLOCK_DESTROY, pos);
+                world.gameEvent((Entity) player, (Holder) GameEvent.BLOCK_DESTROY, pos);
             }
 
             return InteractionResult.SUCCESS;
@@ -113,9 +139,7 @@
 
     @Override
     protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
-        return direction == Direction.DOWN && !state.canSurvive(world, pos)
-            ? Blocks.AIR.defaultBlockState()
-            : super.updateShape(state, direction, neighborState, world, pos, neighborPos);
+        return direction == Direction.DOWN && !state.canSurvive(world, pos) ? Blocks.AIR.defaultBlockState() : super.updateShape(state, direction, neighborState, world, pos, neighborPos);
     }
 
     @Override
@@ -125,12 +149,12 @@
 
     @Override
     protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
-        builder.add(BITES);
+        builder.add(CakeBlock.BITES);
     }
 
     @Override
     protected int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) {
-        return getOutputSignal(state.getValue(BITES));
+        return CakeBlock.getOutputSignal((Integer) state.getValue(CakeBlock.BITES));
     }
 
     public static int getOutputSignal(int bites) {
