--- a/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
+++ b/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
@@ -13,20 +13,20 @@
 import net.minecraft.world.level.block.state.StateDefinition;
 import net.minecraft.world.level.block.state.properties.BlockStateProperties;
 import net.minecraft.world.level.block.state.properties.IntegerProperty;
+import net.minecraft.world.level.material.Fluid;
 import net.minecraft.world.level.material.Fluids;
 import net.minecraft.world.phys.shapes.VoxelShape;
 
 public abstract class GrowingPlantHeadBlock extends GrowingPlantBlock implements BonemealableBlock {
+
     public static final IntegerProperty AGE = BlockStateProperties.AGE_25;
     public static final int MAX_AGE = 25;
     private final double growPerTickProbability;
 
-    protected GrowingPlantHeadBlock(
-        BlockBehaviour.Properties settings, Direction growthDirection, VoxelShape outlineShape, boolean tickWater, double growthChance
-    ) {
+    protected GrowingPlantHeadBlock(BlockBehaviour.Properties settings, Direction growthDirection, VoxelShape outlineShape, boolean tickWater, double growthChance) {
         super(settings, growthDirection, outlineShape, tickWater);
         this.growPerTickProbability = growthChance;
-        this.registerDefaultState(this.stateDefinition.any().setValue(AGE, Integer.valueOf(0)));
+        this.registerDefaultState((BlockState) ((BlockState) this.stateDefinition.any()).setValue(GrowingPlantHeadBlock.AGE, 0));
     }
 
     @Override
@@ -34,34 +34,54 @@
 
     @Override
     public BlockState getStateForPlacement(LevelAccessor world) {
-        return this.defaultBlockState().setValue(AGE, Integer.valueOf(world.getRandom().nextInt(25)));
+        return (BlockState) this.defaultBlockState().setValue(GrowingPlantHeadBlock.AGE, world.getRandom().nextInt(25));
     }
 
     @Override
     protected boolean isRandomlyTicking(BlockState state) {
-        return state.getValue(AGE) < 25;
+        return (Integer) state.getValue(GrowingPlantHeadBlock.AGE) < 25;
     }
 
     @Override
     protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
-        if (state.getValue(AGE) < 25 && random.nextDouble() < this.growPerTickProbability) {
-            BlockPos blockPos = pos.relative(this.growthDirection);
-            if (this.canGrowInto(world.getBlockState(blockPos))) {
-                world.setBlockAndUpdate(blockPos, this.getGrowIntoState(state, world.random));
+        // Spigot start
+        int modifier;
+        if (this == Blocks.KELP) {
+            modifier = world.spigotConfig.kelpModifier;
+        } else if (this == Blocks.TWISTING_VINES) {
+            modifier = world.spigotConfig.twistingVinesModifier;
+        } else if (this == Blocks.WEEPING_VINES) {
+            modifier = world.spigotConfig.weepingVinesModifier;
+        } else {
+            modifier = world.spigotConfig.caveVinesModifier;
+        }
+        if ((Integer) state.getValue(GrowingPlantHeadBlock.AGE) < 25 && random.nextDouble() < ((modifier / 100.0D) * this.growPerTickProbability)) { // Spigot - SPIGOT-7159: Better modifier resolution
+            // Spigot end
+            BlockPos blockposition1 = pos.relative(this.growthDirection);
+
+            if (this.canGrowInto(world.getBlockState(blockposition1))) {
+                org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, blockposition1, this.getGrowIntoState(state, world.random, world)); // CraftBukkit // Paper - Fix Spigot growth modifiers
             }
         }
+
     }
 
+    // Paper start - Fix Spigot growth modifiers
+    protected BlockState getGrowIntoState(BlockState state, RandomSource random, @javax.annotation.Nullable Level level) {
+        return this.getGrowIntoState(state, random);
+    }
+    // Paper end - Fix Spigot growth modifiers
+
     protected BlockState getGrowIntoState(BlockState state, RandomSource random) {
-        return state.cycle(AGE);
+        return (BlockState) state.cycle(GrowingPlantHeadBlock.AGE);
     }
 
     public BlockState getMaxAgeState(BlockState state) {
-        return state.setValue(AGE, Integer.valueOf(25));
+        return (BlockState) state.setValue(GrowingPlantHeadBlock.AGE, 25);
     }
 
     public boolean isMaxAge(BlockState state) {
-        return state.getValue(AGE) == 25;
+        return (Integer) state.getValue(GrowingPlantHeadBlock.AGE) == 25;
     }
 
     protected BlockState updateBodyAfterConvertedFromHead(BlockState from, BlockState to) {
@@ -71,23 +91,23 @@
     @Override
     protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
         if (direction == this.growthDirection.getOpposite() && !state.canSurvive(world, pos)) {
-            world.scheduleTick(pos, this, 1);
+            world.scheduleTick(pos, (Block) this, 1);
         }
 
-        if (direction != this.growthDirection || !neighborState.is(this) && !neighborState.is(this.getBodyBlock())) {
+        if (direction == this.growthDirection && (neighborState.is((Block) this) || neighborState.is(this.getBodyBlock()))) {
+            return this.updateBodyAfterConvertedFromHead(state, this.getBodyBlock().defaultBlockState());
+        } else {
             if (this.scheduleFluidTicks) {
-                world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world));
+                world.scheduleTick(pos, (Fluid) Fluids.WATER, Fluids.WATER.getTickDelay(world));
             }
 
             return super.updateShape(state, direction, neighborState, world, pos, neighborPos);
-        } else {
-            return this.updateBodyAfterConvertedFromHead(state, this.getBodyBlock().defaultBlockState());
         }
     }
 
     @Override
     protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
-        builder.add(AGE);
+        builder.add(GrowingPlantHeadBlock.AGE);
     }
 
     @Override
@@ -102,15 +122,16 @@
 
     @Override
     public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) {
-        BlockPos blockPos = pos.relative(this.growthDirection);
-        int i = Math.min(state.getValue(AGE) + 1, 25);
+        BlockPos blockposition1 = pos.relative(this.growthDirection);
+        int i = Math.min((Integer) state.getValue(GrowingPlantHeadBlock.AGE) + 1, 25);
         int j = this.getBlocksToGrowWhenBonemealed(random);
 
-        for (int k = 0; k < j && this.canGrowInto(world.getBlockState(blockPos)); k++) {
-            world.setBlockAndUpdate(blockPos, state.setValue(AGE, Integer.valueOf(i)));
-            blockPos = blockPos.relative(this.growthDirection);
+        for (int k = 0; k < j && this.canGrowInto(world.getBlockState(blockposition1)); ++k) {
+            world.setBlockAndUpdate(blockposition1, (BlockState) state.setValue(GrowingPlantHeadBlock.AGE, i));
+            blockposition1 = blockposition1.relative(this.growthDirection);
             i = Math.min(i + 1, 25);
         }
+
     }
 
     protected abstract int getBlocksToGrowWhenBonemealed(RandomSource random);
