--- a/net/minecraft/world/level/block/BigDripleafBlock.java
+++ b/net/minecraft/world/level/block/BigDripleafBlock.java
@@ -32,6 +32,7 @@
 import net.minecraft.world.level.block.state.properties.EnumProperty;
 import net.minecraft.world.level.block.state.properties.Tilt;
 import net.minecraft.world.level.gameevent.GameEvent;
+import net.minecraft.world.level.material.Fluid;
 import net.minecraft.world.level.material.FluidState;
 import net.minecraft.world.level.material.Fluids;
 import net.minecraft.world.phys.BlockHitResult;
@@ -39,16 +40,21 @@
 import net.minecraft.world.phys.shapes.CollisionContext;
 import net.minecraft.world.phys.shapes.Shapes;
 import net.minecraft.world.phys.shapes.VoxelShape;
+// CraftBukkit start
+import org.bukkit.craftbukkit.v1_19_R1.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityInteractEvent;
+// CraftBukkit end
 
 public class BigDripleafBlock extends HorizontalDirectionalBlock implements BonemealableBlock, SimpleWaterloggedBlock {
+
     private static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
     private static final EnumProperty<Tilt> TILT = BlockStateProperties.TILT;
     private static final int NO_TICK = -1;
-    private static final Object2IntMap<Tilt> DELAY_UNTIL_NEXT_TILT_STATE = Util.make(new Object2IntArrayMap<>(), (delays) -> {
-        delays.defaultReturnValue(-1);
-        delays.put(Tilt.UNSTABLE, 10);
-        delays.put(Tilt.PARTIAL, 10);
-        delays.put(Tilt.FULL, 100);
+    private static final Object2IntMap<Tilt> DELAY_UNTIL_NEXT_TILT_STATE = (Object2IntMap) Util.make(new Object2IntArrayMap(), (object2intarraymap) -> {
+        object2intarraymap.defaultReturnValue(-1);
+        object2intarraymap.put(Tilt.UNSTABLE, 10);
+        object2intarraymap.put(Tilt.PARTIAL, 10);
+        object2intarraymap.put(Tilt.FULL, 100);
     });
     private static final int MAX_GEN_HEIGHT = 5;
     private static final int STEM_WIDTH = 6;
@@ -56,38 +62,39 @@
     private static final int LOWEST_LEAF_TOP = 13;
     private static final Map<Tilt, VoxelShape> LEAF_SHAPES = ImmutableMap.of(Tilt.NONE, Block.box(0.0D, 11.0D, 0.0D, 16.0D, 15.0D, 16.0D), Tilt.UNSTABLE, Block.box(0.0D, 11.0D, 0.0D, 16.0D, 15.0D, 16.0D), Tilt.PARTIAL, Block.box(0.0D, 11.0D, 0.0D, 16.0D, 13.0D, 16.0D), Tilt.FULL, Shapes.empty());
     private static final VoxelShape STEM_SLICER = Block.box(0.0D, 13.0D, 0.0D, 16.0D, 16.0D, 16.0D);
-    private static final Map<Direction, VoxelShape> STEM_SHAPES = ImmutableMap.of(Direction.NORTH, Shapes.joinUnoptimized(BigDripleafStemBlock.NORTH_SHAPE, STEM_SLICER, BooleanOp.ONLY_FIRST), Direction.SOUTH, Shapes.joinUnoptimized(BigDripleafStemBlock.SOUTH_SHAPE, STEM_SLICER, BooleanOp.ONLY_FIRST), Direction.EAST, Shapes.joinUnoptimized(BigDripleafStemBlock.EAST_SHAPE, STEM_SLICER, BooleanOp.ONLY_FIRST), Direction.WEST, Shapes.joinUnoptimized(BigDripleafStemBlock.WEST_SHAPE, STEM_SLICER, BooleanOp.ONLY_FIRST));
+    private static final Map<Direction, VoxelShape> STEM_SHAPES = ImmutableMap.of(Direction.NORTH, Shapes.joinUnoptimized(BigDripleafStemBlock.NORTH_SHAPE, BigDripleafBlock.STEM_SLICER, BooleanOp.ONLY_FIRST), Direction.SOUTH, Shapes.joinUnoptimized(BigDripleafStemBlock.SOUTH_SHAPE, BigDripleafBlock.STEM_SLICER, BooleanOp.ONLY_FIRST), Direction.EAST, Shapes.joinUnoptimized(BigDripleafStemBlock.EAST_SHAPE, BigDripleafBlock.STEM_SLICER, BooleanOp.ONLY_FIRST), Direction.WEST, Shapes.joinUnoptimized(BigDripleafStemBlock.WEST_SHAPE, BigDripleafBlock.STEM_SLICER, BooleanOp.ONLY_FIRST));
     private final Map<BlockState, VoxelShape> shapesCache;
 
     protected BigDripleafBlock(BlockBehaviour.Properties settings) {
         super(settings);
-        this.registerDefaultState(this.stateDefinition.any().setValue(WATERLOGGED, Boolean.valueOf(false)).setValue(FACING, Direction.NORTH).setValue(TILT, Tilt.NONE));
+        this.registerDefaultState((BlockState) ((BlockState) ((BlockState) ((BlockState) this.stateDefinition.any()).setValue(BigDripleafBlock.WATERLOGGED, false)).setValue(BigDripleafBlock.FACING, Direction.NORTH)).setValue(BigDripleafBlock.TILT, Tilt.NONE));
         this.shapesCache = this.getShapeForEachState(BigDripleafBlock::calculateShape);
     }
 
     private static VoxelShape calculateShape(BlockState state) {
-        return Shapes.or(LEAF_SHAPES.get(state.getValue(TILT)), STEM_SHAPES.get(state.getValue(FACING)));
+        return Shapes.or((VoxelShape) BigDripleafBlock.LEAF_SHAPES.get(state.getValue(BigDripleafBlock.TILT)), (VoxelShape) BigDripleafBlock.STEM_SHAPES.get(state.getValue(BigDripleafBlock.FACING)));
     }
 
     public static void placeWithRandomHeight(LevelAccessor world, RandomSource random, BlockPos pos, Direction direction) {
         int i = Mth.nextInt(random, 2, 5);
-        BlockPos.MutableBlockPos mutableBlockPos = pos.mutable();
+        BlockPos.MutableBlockPos blockposition_mutableblockposition = pos.mutable();
         int j = 0;
 
-        while(j < i && canPlaceAt(world, mutableBlockPos, world.getBlockState(mutableBlockPos))) {
+        while (j < i && BigDripleafBlock.canPlaceAt(world, blockposition_mutableblockposition, world.getBlockState(blockposition_mutableblockposition))) {
             ++j;
-            mutableBlockPos.move(Direction.UP);
+            blockposition_mutableblockposition.move(Direction.UP);
         }
 
         int k = pos.getY() + j - 1;
-        mutableBlockPos.setY(pos.getY());
 
-        while(mutableBlockPos.getY() < k) {
-            BigDripleafStemBlock.place(world, mutableBlockPos, world.getFluidState(mutableBlockPos), direction);
-            mutableBlockPos.move(Direction.UP);
+        blockposition_mutableblockposition.setY(pos.getY());
+
+        while (blockposition_mutableblockposition.getY() < k) {
+            BigDripleafStemBlock.place(world, blockposition_mutableblockposition, world.getFluidState(blockposition_mutableblockposition), direction);
+            blockposition_mutableblockposition.move(Direction.UP);
         }
 
-        place(world, mutableBlockPos, world.getFluidState(mutableBlockPos), direction);
+        BigDripleafBlock.place(world, blockposition_mutableblockposition, world.getFluidState(blockposition_mutableblockposition), direction);
     }
 
     private static boolean canReplace(BlockState state) {
@@ -95,29 +102,31 @@
     }
 
     protected static boolean canPlaceAt(LevelHeightAccessor world, BlockPos pos, BlockState state) {
-        return !world.isOutsideBuildHeight(pos) && canReplace(state);
+        return !world.isOutsideBuildHeight(pos) && BigDripleafBlock.canReplace(state);
     }
 
     protected static boolean place(LevelAccessor world, BlockPos pos, FluidState fluidState, Direction direction) {
-        BlockState blockState = Blocks.BIG_DRIPLEAF.defaultBlockState().setValue(WATERLOGGED, Boolean.valueOf(fluidState.isSourceOfType(Fluids.WATER))).setValue(FACING, direction);
-        return world.setBlock(pos, blockState, 3);
+        BlockState iblockdata = (BlockState) ((BlockState) Blocks.BIG_DRIPLEAF.defaultBlockState().setValue(BigDripleafBlock.WATERLOGGED, fluidState.isSourceOfType(Fluids.WATER))).setValue(BigDripleafBlock.FACING, direction);
+
+        return world.setBlock(pos, iblockdata, 3);
     }
 
     @Override
     public void onProjectileHit(Level world, BlockState state, BlockHitResult hit, Projectile projectile) {
-        this.setTiltAndScheduleTick(state, world, hit.getBlockPos(), Tilt.FULL, SoundEvents.BIG_DRIPLEAF_TILT_DOWN);
+        this.setTiltAndScheduleTick(state, world, hit.getBlockPos(), Tilt.FULL, SoundEvents.BIG_DRIPLEAF_TILT_DOWN, projectile); // CraftBukkit
     }
 
     @Override
     public FluidState getFluidState(BlockState state) {
-        return state.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(state);
+        return (Boolean) state.getValue(BigDripleafBlock.WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(state);
     }
 
     @Override
     public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
-        BlockPos blockPos = pos.below();
-        BlockState blockState = world.getBlockState(blockPos);
-        return blockState.is(this) || blockState.is(Blocks.BIG_DRIPLEAF_STEM) || blockState.is(BlockTags.BIG_DRIPLEAF_PLACEABLE);
+        BlockPos blockposition1 = pos.below();
+        BlockState iblockdata1 = world.getBlockState(blockposition1);
+
+        return iblockdata1.is((Block) this) || iblockdata1.is(Blocks.BIG_DRIPLEAF_STEM) || iblockdata1.is(BlockTags.BIG_DRIPLEAF_PLACEABLE);
     }
 
     @Override
@@ -125,18 +134,19 @@
         if (direction == Direction.DOWN && !state.canSurvive(world, pos)) {
             return Blocks.AIR.defaultBlockState();
         } else {
-            if (state.getValue(WATERLOGGED)) {
-                world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world));
+            if ((Boolean) state.getValue(BigDripleafBlock.WATERLOGGED)) {
+                world.scheduleTick(pos, (Fluid) Fluids.WATER, Fluids.WATER.getTickDelay(world));
             }
 
-            return direction == Direction.UP && neighborState.is(this) ? Blocks.BIG_DRIPLEAF_STEM.withPropertiesOf(state) : super.updateShape(state, direction, neighborState, world, pos, neighborPos);
+            return direction == Direction.UP && neighborState.is((Block) this) ? Blocks.BIG_DRIPLEAF_STEM.withPropertiesOf(state) : super.updateShape(state, direction, neighborState, world, pos, neighborPos);
         }
     }
 
     @Override
     public boolean isValidBonemealTarget(BlockGetter world, BlockPos pos, BlockState state, boolean isClient) {
-        BlockState blockState = world.getBlockState(pos.above());
-        return canReplace(blockState);
+        BlockState iblockdata1 = world.getBlockState(pos.above());
+
+        return BigDripleafBlock.canReplace(iblockdata1);
     }
 
     @Override
@@ -146,21 +156,37 @@
 
     @Override
     public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) {
-        BlockPos blockPos = pos.above();
-        BlockState blockState = world.getBlockState(blockPos);
-        if (canPlaceAt(world, blockPos, blockState)) {
-            Direction direction = state.getValue(FACING);
-            BigDripleafStemBlock.place(world, pos, state.getFluidState(), direction);
-            place(world, blockPos, blockState.getFluidState(), direction);
+        BlockPos blockposition1 = pos.above();
+        BlockState iblockdata1 = world.getBlockState(blockposition1);
+
+        if (BigDripleafBlock.canPlaceAt(world, blockposition1, iblockdata1)) {
+            Direction enumdirection = (Direction) state.getValue(BigDripleafBlock.FACING);
+
+            BigDripleafStemBlock.place(world, pos, state.getFluidState(), enumdirection);
+            BigDripleafBlock.place(world, blockposition1, iblockdata1.getFluidState(), enumdirection);
         }
 
     }
 
     @Override
     public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) {
+        if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.v1_19_R1.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper
         if (!world.isClientSide) {
-            if (state.getValue(TILT) == Tilt.NONE && canEntityTilt(pos, entity) && !world.hasNeighborSignal(pos)) {
-                this.setTiltAndScheduleTick(state, world, pos, Tilt.UNSTABLE, (SoundEvent)null);
+            if (state.getValue(BigDripleafBlock.TILT) == Tilt.NONE && BigDripleafBlock.canEntityTilt(pos, entity) && !world.hasNeighborSignal(pos)) {
+                // CraftBukkit start - tilt dripleaf
+                org.bukkit.event.Cancellable cancellable;
+                if (entity instanceof Player) {
+                    cancellable = CraftEventFactory.callPlayerInteractEvent((Player) entity, org.bukkit.event.block.Action.PHYSICAL, pos, null, null, null);
+                } else {
+                    cancellable = new EntityInteractEvent(entity.getBukkitEntity(), world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()));
+                    world.getCraftServer().getPluginManager().callEvent((EntityInteractEvent) cancellable);
+                }
+
+                if (cancellable.isCancelled()) {
+                    return;
+                }
+                this.setTiltAndScheduleTick(state, world, pos, Tilt.UNSTABLE, (SoundEvent) null, entity);
+                // CraftBukkit end
             }
 
         }
@@ -169,15 +195,16 @@
     @Override
     public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
         if (world.hasNeighborSignal(pos)) {
-            resetTilt(state, world, pos);
+            BigDripleafBlock.resetTilt(state, world, pos);
         } else {
-            Tilt tilt = state.getValue(TILT);
+            Tilt tilt = (Tilt) state.getValue(BigDripleafBlock.TILT);
+
             if (tilt == Tilt.UNSTABLE) {
-                this.setTiltAndScheduleTick(state, world, pos, Tilt.PARTIAL, SoundEvents.BIG_DRIPLEAF_TILT_DOWN);
+                this.setTiltAndScheduleTick(state, world, pos, Tilt.PARTIAL, SoundEvents.BIG_DRIPLEAF_TILT_DOWN, null); // CraftBukkit
             } else if (tilt == Tilt.PARTIAL) {
-                this.setTiltAndScheduleTick(state, world, pos, Tilt.FULL, SoundEvents.BIG_DRIPLEAF_TILT_DOWN);
+                this.setTiltAndScheduleTick(state, world, pos, Tilt.FULL, SoundEvents.BIG_DRIPLEAF_TILT_DOWN, null); // CraftBukkit
             } else if (tilt == Tilt.FULL) {
-                resetTilt(state, world, pos);
+                BigDripleafBlock.resetTilt(state, world, pos);
             }
 
         }
@@ -186,70 +213,84 @@
     @Override
     public void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) {
         if (world.hasNeighborSignal(pos)) {
-            resetTilt(state, world, pos);
+            BigDripleafBlock.resetTilt(state, world, pos);
         }
 
     }
 
     private static void playTiltSound(Level world, BlockPos pos, SoundEvent soundEvent) {
         float f = Mth.randomBetween(world.random, 0.8F, 1.2F);
-        world.playSound((Player)null, pos, soundEvent, SoundSource.BLOCKS, 1.0F, f);
+
+        world.playSound((Player) null, pos, soundEvent, SoundSource.BLOCKS, 1.0F, f);
     }
 
     private static boolean canEntityTilt(BlockPos pos, Entity entity) {
-        return entity.isOnGround() && entity.position().y > (double)((float)pos.getY() + 0.6875F);
+        return entity.isOnGround() && entity.position().y > (double) ((float) pos.getY() + 0.6875F);
     }
 
-    private void setTiltAndScheduleTick(BlockState state, Level world, BlockPos pos, Tilt tilt, @Nullable SoundEvent sound) {
-        setTilt(state, world, pos, tilt);
-        if (sound != null) {
-            playTiltSound(world, pos, sound);
+    // CraftBukkit start
+    private void setTiltAndScheduleTick(BlockState iblockdata, Level world, BlockPos blockposition, Tilt tilt, @Nullable SoundEvent soundeffect, @Nullable Entity entity) {
+        if (!BigDripleafBlock.setTilt(iblockdata, world, blockposition, tilt, entity)) return;
+        // CraftBukkit end
+        if (soundeffect != null) {
+            BigDripleafBlock.playTiltSound(world, blockposition, soundeffect);
         }
 
-        int i = DELAY_UNTIL_NEXT_TILT_STATE.getInt(tilt);
+        int i = BigDripleafBlock.DELAY_UNTIL_NEXT_TILT_STATE.getInt(tilt);
+
         if (i != -1) {
-            world.scheduleTick(pos, this, i);
+            world.scheduleTick(blockposition, (Block) this, i);
         }
 
     }
 
     private static void resetTilt(BlockState state, Level world, BlockPos pos) {
-        setTilt(state, world, pos, Tilt.NONE);
-        if (state.getValue(TILT) != Tilt.NONE) {
-            playTiltSound(world, pos, SoundEvents.BIG_DRIPLEAF_TILT_UP);
+        BigDripleafBlock.setTilt(state, world, pos, Tilt.NONE, null); // CraftBukkit
+        if (state.getValue(BigDripleafBlock.TILT) != Tilt.NONE) {
+            BigDripleafBlock.playTiltSound(world, pos, SoundEvents.BIG_DRIPLEAF_TILT_UP);
         }
 
     }
 
-    private static void setTilt(BlockState state, Level world, BlockPos pos, Tilt tilt) {
-        Tilt tilt2 = state.getValue(TILT);
-        world.setBlock(pos, state.setValue(TILT, tilt), 2);
-        if (tilt.causesVibration() && tilt != tilt2) {
-            world.gameEvent((Entity)null, GameEvent.BLOCK_CHANGE, pos);
+    // CraftBukkit start
+    private static boolean setTilt(BlockState iblockdata, Level world, BlockPos blockposition, Tilt tilt, @Nullable Entity entity) {
+        if (entity != null) {
+            if (CraftEventFactory.callEntityChangeBlockEvent(entity, blockposition, iblockdata.setValue(BigDripleafBlock.TILT, tilt)).isCancelled()) {
+                return false;
+            }
         }
+        // CraftBukkit end
+        Tilt tilt1 = (Tilt) iblockdata.getValue(BigDripleafBlock.TILT);
 
+        world.setBlock(blockposition, (BlockState) iblockdata.setValue(BigDripleafBlock.TILT, tilt), 2);
+        if (tilt.causesVibration() && tilt != tilt1) {
+            world.gameEvent((Entity) null, GameEvent.BLOCK_CHANGE, blockposition);
+        }
+
+        return true; // CraftBukkit
     }
 
     @Override
     public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) {
-        return LEAF_SHAPES.get(state.getValue(TILT));
+        return (VoxelShape) BigDripleafBlock.LEAF_SHAPES.get(state.getValue(BigDripleafBlock.TILT));
     }
 
     @Override
     public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) {
-        return this.shapesCache.get(state);
+        return (VoxelShape) this.shapesCache.get(state);
     }
 
     @Override
     public BlockState getStateForPlacement(BlockPlaceContext ctx) {
-        BlockState blockState = ctx.getLevel().getBlockState(ctx.getClickedPos().below());
-        FluidState fluidState = ctx.getLevel().getFluidState(ctx.getClickedPos());
-        boolean bl = blockState.is(Blocks.BIG_DRIPLEAF) || blockState.is(Blocks.BIG_DRIPLEAF_STEM);
-        return this.defaultBlockState().setValue(WATERLOGGED, Boolean.valueOf(fluidState.isSourceOfType(Fluids.WATER))).setValue(FACING, bl ? blockState.getValue(FACING) : ctx.getHorizontalDirection().getOpposite());
+        BlockState iblockdata = ctx.getLevel().getBlockState(ctx.getClickedPos().below());
+        FluidState fluid = ctx.getLevel().getFluidState(ctx.getClickedPos());
+        boolean flag = iblockdata.is(Blocks.BIG_DRIPLEAF) || iblockdata.is(Blocks.BIG_DRIPLEAF_STEM);
+
+        return (BlockState) ((BlockState) this.defaultBlockState().setValue(BigDripleafBlock.WATERLOGGED, fluid.isSourceOfType(Fluids.WATER))).setValue(BigDripleafBlock.FACING, flag ? (Direction) iblockdata.getValue(BigDripleafBlock.FACING) : ctx.getHorizontalDirection().getOpposite());
     }
 
     @Override
     protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
-        builder.add(WATERLOGGED, FACING, TILT);
+        builder.add(BigDripleafBlock.WATERLOGGED, BigDripleafBlock.FACING, BigDripleafBlock.TILT);
     }
 }
