--- a/net/minecraft/world/level/block/CocoaBlock.java
+++ b/net/minecraft/world/level/block/CocoaBlock.java
@@ -20,8 +20,10 @@
 import net.minecraft.world.level.pathfinder.PathComputationType;
 import net.minecraft.world.phys.shapes.CollisionContext;
 import net.minecraft.world.phys.shapes.VoxelShape;
+import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit
 
 public class CocoaBlock extends HorizontalDirectionalBlock implements BonemealableBlock {
+
     public static final MapCodec<CocoaBlock> CODEC = simpleCodec(CocoaBlock::new);
     public static final int MAX_AGE = 2;
     public static final IntegerProperty AGE = BlockStateProperties.AGE_2;
@@ -34,78 +36,78 @@
     protected static final int AGE_2_WIDTH = 8;
     protected static final int AGE_2_HEIGHT = 9;
     protected static final int AGE_2_HALFWIDTH = 4;
-    protected static final VoxelShape[] EAST_AABB = new VoxelShape[]{
-        Block.box(11.0, 7.0, 6.0, 15.0, 12.0, 10.0), Block.box(9.0, 5.0, 5.0, 15.0, 12.0, 11.0), Block.box(7.0, 3.0, 4.0, 15.0, 12.0, 12.0)
-    };
-    protected static final VoxelShape[] WEST_AABB = new VoxelShape[]{
-        Block.box(1.0, 7.0, 6.0, 5.0, 12.0, 10.0), Block.box(1.0, 5.0, 5.0, 7.0, 12.0, 11.0), Block.box(1.0, 3.0, 4.0, 9.0, 12.0, 12.0)
-    };
-    protected static final VoxelShape[] NORTH_AABB = new VoxelShape[]{
-        Block.box(6.0, 7.0, 1.0, 10.0, 12.0, 5.0), Block.box(5.0, 5.0, 1.0, 11.0, 12.0, 7.0), Block.box(4.0, 3.0, 1.0, 12.0, 12.0, 9.0)
-    };
-    protected static final VoxelShape[] SOUTH_AABB = new VoxelShape[]{
-        Block.box(6.0, 7.0, 11.0, 10.0, 12.0, 15.0), Block.box(5.0, 5.0, 9.0, 11.0, 12.0, 15.0), Block.box(4.0, 3.0, 7.0, 12.0, 12.0, 15.0)
-    };
+    protected static final VoxelShape[] EAST_AABB = new VoxelShape[]{Block.box(11.0D, 7.0D, 6.0D, 15.0D, 12.0D, 10.0D), Block.box(9.0D, 5.0D, 5.0D, 15.0D, 12.0D, 11.0D), Block.box(7.0D, 3.0D, 4.0D, 15.0D, 12.0D, 12.0D)};
+    protected static final VoxelShape[] WEST_AABB = new VoxelShape[]{Block.box(1.0D, 7.0D, 6.0D, 5.0D, 12.0D, 10.0D), Block.box(1.0D, 5.0D, 5.0D, 7.0D, 12.0D, 11.0D), Block.box(1.0D, 3.0D, 4.0D, 9.0D, 12.0D, 12.0D)};
+    protected static final VoxelShape[] NORTH_AABB = new VoxelShape[]{Block.box(6.0D, 7.0D, 1.0D, 10.0D, 12.0D, 5.0D), Block.box(5.0D, 5.0D, 1.0D, 11.0D, 12.0D, 7.0D), Block.box(4.0D, 3.0D, 1.0D, 12.0D, 12.0D, 9.0D)};
+    protected static final VoxelShape[] SOUTH_AABB = new VoxelShape[]{Block.box(6.0D, 7.0D, 11.0D, 10.0D, 12.0D, 15.0D), Block.box(5.0D, 5.0D, 9.0D, 11.0D, 12.0D, 15.0D), Block.box(4.0D, 3.0D, 7.0D, 12.0D, 12.0D, 15.0D)};
 
     @Override
     public MapCodec<CocoaBlock> codec() {
-        return CODEC;
+        return CocoaBlock.CODEC;
     }
 
     public CocoaBlock(BlockBehaviour.Properties settings) {
         super(settings);
-        this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(AGE, Integer.valueOf(0)));
+        this.registerDefaultState((BlockState) ((BlockState) ((BlockState) this.stateDefinition.any()).setValue(CocoaBlock.FACING, Direction.NORTH)).setValue(CocoaBlock.AGE, 0));
     }
 
     @Override
     protected boolean isRandomlyTicking(BlockState state) {
-        return state.getValue(AGE) < 2;
+        return (Integer) state.getValue(CocoaBlock.AGE) < 2;
     }
 
     @Override
     protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
-        if (world.random.nextInt(5) == 0) {
-            int i = state.getValue(AGE);
+        if (world.random.nextFloat() < (world.spigotConfig.cocoaModifier / (100.0f * 5))) { // Spigot - SPIGOT-7159: Better modifier resolution
+            int i = (Integer) state.getValue(CocoaBlock.AGE);
+
             if (i < 2) {
-                world.setBlock(pos, state.setValue(AGE, Integer.valueOf(i + 1)), 2);
+                CraftEventFactory.handleBlockGrowEvent(world, pos, (BlockState) state.setValue(CocoaBlock.AGE, i + 1), 2); // CraftBukkkit
             }
         }
+
     }
 
     @Override
     protected boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
-        BlockState blockState = world.getBlockState(pos.relative(state.getValue(FACING)));
-        return blockState.is(BlockTags.JUNGLE_LOGS);
+        BlockState iblockdata1 = world.getBlockState(pos.relative((Direction) state.getValue(CocoaBlock.FACING)));
+
+        return iblockdata1.is(BlockTags.JUNGLE_LOGS);
     }
 
     @Override
     protected VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) {
-        int i = state.getValue(AGE);
-        switch ((Direction)state.getValue(FACING)) {
+        int i = (Integer) state.getValue(CocoaBlock.AGE);
+
+        switch ((Direction) state.getValue(CocoaBlock.FACING)) {
             case SOUTH:
-                return SOUTH_AABB[i];
+                return CocoaBlock.SOUTH_AABB[i];
             case NORTH:
             default:
-                return NORTH_AABB[i];
+                return CocoaBlock.NORTH_AABB[i];
             case WEST:
-                return WEST_AABB[i];
+                return CocoaBlock.WEST_AABB[i];
             case EAST:
-                return EAST_AABB[i];
+                return CocoaBlock.EAST_AABB[i];
         }
     }
 
     @Nullable
     @Override
     public BlockState getStateForPlacement(BlockPlaceContext ctx) {
-        BlockState blockState = this.defaultBlockState();
-        LevelReader levelReader = ctx.getLevel();
-        BlockPos blockPos = ctx.getClickedPos();
+        BlockState iblockdata = this.defaultBlockState();
+        Level world = ctx.getLevel();
+        BlockPos blockposition = ctx.getClickedPos();
+        Direction[] aenumdirection = ctx.getNearestLookingDirections();
+        int i = aenumdirection.length;
 
-        for (Direction direction : ctx.getNearestLookingDirections()) {
-            if (direction.getAxis().isHorizontal()) {
-                blockState = blockState.setValue(FACING, direction);
-                if (blockState.canSurvive(levelReader, blockPos)) {
-                    return blockState;
+        for (int j = 0; j < i; ++j) {
+            Direction enumdirection = aenumdirection[j];
+
+            if (enumdirection.getAxis().isHorizontal()) {
+                iblockdata = (BlockState) iblockdata.setValue(CocoaBlock.FACING, enumdirection);
+                if (iblockdata.canSurvive(world, blockposition)) {
+                    return iblockdata;
                 }
             }
         }
@@ -115,14 +117,12 @@
 
     @Override
     protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
-        return direction == state.getValue(FACING) && !state.canSurvive(world, pos)
-            ? Blocks.AIR.defaultBlockState()
-            : super.updateShape(state, direction, neighborState, world, pos, neighborPos);
+        return direction == state.getValue(CocoaBlock.FACING) && !state.canSurvive(world, pos) ? Blocks.AIR.defaultBlockState() : super.updateShape(state, direction, neighborState, world, pos, neighborPos);
     }
 
     @Override
     public boolean isValidBonemealTarget(LevelReader world, BlockPos pos, BlockState state) {
-        return state.getValue(AGE) < 2;
+        return (Integer) state.getValue(CocoaBlock.AGE) < 2;
     }
 
     @Override
@@ -132,12 +132,12 @@
 
     @Override
     public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) {
-        world.setBlock(pos, state.setValue(AGE, Integer.valueOf(state.getValue(AGE) + 1)), 2);
+        CraftEventFactory.handleBlockGrowEvent(world, pos, (BlockState) state.setValue(CocoaBlock.AGE, (Integer) state.getValue(CocoaBlock.AGE) + 1), 2); // CraftBukkit
     }
 
     @Override
     protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
-        builder.add(FACING, AGE);
+        builder.add(CocoaBlock.FACING, CocoaBlock.AGE);
     }
 
     @Override
