--- a/net/minecraft/world/level/block/VineBlock.java
+++ b/net/minecraft/world/level/block/VineBlock.java
@@ -191,7 +_,7 @@
     @Override
     protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
         if (level.getGameRules().getBoolean(GameRules.RULE_DO_VINES_SPREAD)) {
-            if (random.nextInt(4) == 0) {
+            if (random.nextFloat() < (level.spigotConfig.vineModifier / (100.0f * 4))) { // Spigot - SPIGOT-7159: Better modifier resolution
                 Direction random1 = Direction.getRandom(random);
                 BlockPos blockPos = pos.above();
                 if (random1.getAxis().isHorizontal() && !state.getValue(getPropertyForFace(random1))) {
@@ -205,28 +_,31 @@
                             boolean value1 = state.getValue(getPropertyForFace(counterClockWise));
                             BlockPos blockPos2 = blockPos1.relative(clockWise);
                             BlockPos blockPos3 = blockPos1.relative(counterClockWise);
+                            // CraftBukkit start - Call BlockSpreadEvent
+                            BlockPos source = pos;
                             if (value && isAcceptableNeighbour(level, blockPos2, clockWise)) {
-                                level.setBlock(blockPos1, this.defaultBlockState().setValue(getPropertyForFace(clockWise), Boolean.valueOf(true)), 2);
+                                org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, source, blockPos1, this.defaultBlockState().setValue(getPropertyForFace(clockWise), Boolean.valueOf(true)), 2);
                             } else if (value1 && isAcceptableNeighbour(level, blockPos3, counterClockWise)) {
-                                level.setBlock(blockPos1, this.defaultBlockState().setValue(getPropertyForFace(counterClockWise), Boolean.valueOf(true)), 2);
+                                org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, source, blockPos1, this.defaultBlockState().setValue(getPropertyForFace(counterClockWise), Boolean.valueOf(true)), 2);
                             } else {
                                 Direction opposite = random1.getOpposite();
                                 if (value && level.isEmptyBlock(blockPos2) && isAcceptableNeighbour(level, pos.relative(clockWise), opposite)) {
-                                    level.setBlock(blockPos2, this.defaultBlockState().setValue(getPropertyForFace(opposite), Boolean.valueOf(true)), 2);
+                                    org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, source, blockPos2, this.defaultBlockState().setValue(getPropertyForFace(opposite), Boolean.valueOf(true)), 2);
                                 } else if (value1 && level.isEmptyBlock(blockPos3) && isAcceptableNeighbour(level, pos.relative(counterClockWise), opposite)) {
-                                    level.setBlock(blockPos3, this.defaultBlockState().setValue(getPropertyForFace(opposite), Boolean.valueOf(true)), 2);
+                                    org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, source, blockPos3, this.defaultBlockState().setValue(getPropertyForFace(opposite), Boolean.valueOf(true)), 2);
                                 } else if (random.nextFloat() < 0.05 && isAcceptableNeighbour(level, blockPos1.above(), Direction.UP)) {
-                                    level.setBlock(blockPos1, this.defaultBlockState().setValue(UP, Boolean.valueOf(true)), 2);
+                                    org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, source, blockPos1, this.defaultBlockState().setValue(UP, Boolean.valueOf(true)), 2);
                                 }
+                                // CraftBukkit end
                             }
                         } else if (isAcceptableNeighbour(level, blockPos1, random1)) {
-                            level.setBlock(pos, state.setValue(getPropertyForFace(random1), Boolean.valueOf(true)), 2);
+                            org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, (BlockState) state.setValue(VineBlock.getPropertyForFace(random1), true), 2); // CraftBukkit
                         }
                     }
                 } else {
                     if (random1 == Direction.UP && pos.getY() < level.getMaxY()) {
                         if (this.canSupportAtFace(level, pos, random1)) {
-                            level.setBlock(pos, state.setValue(UP, Boolean.valueOf(true)), 2);
+                            org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, state.setValue(UP, Boolean.valueOf(true)), 2); // CraftBukkit
                             return;
                         }
 
@@ -244,7 +_,7 @@
                             }
 
                             if (this.hasHorizontalConnection(blockState1)) {
-                                level.setBlock(blockPos, blockState1, 2);
+                                org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, blockPos, blockState1, 2); // CraftBukkit
                             }
 
                             return;
@@ -258,7 +_,7 @@
                             BlockState blockState2 = blockState.isAir() ? this.defaultBlockState() : blockState;
                             BlockState blockState3 = this.copyRandomFaces(state, blockState2, random);
                             if (blockState2 != blockState3 && this.hasHorizontalConnection(blockState3)) {
-                                level.setBlock(blockPos1, blockState3, 2);
+                                org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(level, pos, blockPos1, blockState3, 2); // CraftBukkit
                             }
                         }
                     }
