--- a/net/minecraft/world/item/BoneMealItem.java
+++ b/net/minecraft/world/item/BoneMealItem.java
@@ -17,12 +17,14 @@
 import net.minecraft.world.level.LevelAccessor;
 import net.minecraft.world.level.biome.Biome;
 import net.minecraft.world.level.block.BaseCoralWallFanBlock;
+import net.minecraft.world.level.block.Block;
 import net.minecraft.world.level.block.Blocks;
 import net.minecraft.world.level.block.BonemealableBlock;
 import net.minecraft.world.level.block.state.BlockState;
 import net.minecraft.world.level.gameevent.GameEvent;
 
 public class BoneMealItem extends Item {
+
     public static final int GRASS_SPREAD_WIDTH = 3;
     public static final int GRASS_SPREAD_HEIGHT = 1;
     public static final int GRASS_COUNT_MULTIPLIER = 3;
@@ -33,26 +35,34 @@
 
     @Override
     public InteractionResult useOn(UseOnContext context) {
-        Level level = context.getLevel();
-        BlockPos blockPos = context.getClickedPos();
-        BlockPos blockPos2 = blockPos.relative(context.getClickedFace());
-        if (growCrop(context.getItemInHand(), level, blockPos)) {
-            if (!level.isClientSide) {
-                context.getPlayer().gameEvent(GameEvent.ITEM_INTERACT_FINISH);
-                level.levelEvent(1505, blockPos, 15);
+        // CraftBukkit start - extract bonemeal application logic to separate, static method
+        return BoneMealItem.applyBonemeal(context);
+    }
+
+    public static InteractionResult applyBonemeal(UseOnContext itemactioncontext) {
+        // CraftBukkit end
+        Level world = itemactioncontext.getLevel();
+        BlockPos blockposition = itemactioncontext.getClickedPos();
+        BlockPos blockposition1 = blockposition.relative(itemactioncontext.getClickedFace());
+
+        if (BoneMealItem.growCrop(itemactioncontext.getItemInHand(), world, blockposition)) {
+            if (!world.isClientSide) {
+                if (itemactioncontext.getPlayer() != null) itemactioncontext.getPlayer().gameEvent(GameEvent.ITEM_INTERACT_FINISH); // CraftBukkit - SPIGOT-7518
+                world.levelEvent(1505, blockposition, 15);
             }
 
-            return InteractionResult.sidedSuccess(level.isClientSide);
+            return InteractionResult.sidedSuccess(world.isClientSide);
         } else {
-            BlockState blockState = level.getBlockState(blockPos);
-            boolean bl = blockState.isFaceSturdy(level, blockPos, context.getClickedFace());
-            if (bl && growWaterPlant(context.getItemInHand(), level, blockPos2, context.getClickedFace())) {
-                if (!level.isClientSide) {
-                    context.getPlayer().gameEvent(GameEvent.ITEM_INTERACT_FINISH);
-                    level.levelEvent(1505, blockPos2, 15);
+            BlockState iblockdata = world.getBlockState(blockposition);
+            boolean flag = iblockdata.isFaceSturdy(world, blockposition, itemactioncontext.getClickedFace());
+
+            if (flag && BoneMealItem.growWaterPlant(itemactioncontext.getItemInHand(), world, blockposition1, itemactioncontext.getClickedFace())) {
+                if (!world.isClientSide) {
+                    if (itemactioncontext.getPlayer() != null) itemactioncontext.getPlayer().gameEvent(GameEvent.ITEM_INTERACT_FINISH); // CraftBukkit - SPIGOT-7518
+                    world.levelEvent(1505, blockposition1, 15);
                 }
 
-                return InteractionResult.sidedSuccess(level.isClientSide);
+                return InteractionResult.sidedSuccess(world.isClientSide);
             } else {
                 return InteractionResult.PASS;
             }
@@ -60,17 +70,21 @@
     }
 
     public static boolean growCrop(ItemStack stack, Level world, BlockPos pos) {
-        BlockState blockState = world.getBlockState(pos);
-        if (blockState.getBlock() instanceof BonemealableBlock bonemealableBlock && bonemealableBlock.isValidBonemealTarget(world, pos, blockState)) {
-            if (world instanceof ServerLevel) {
-                if (bonemealableBlock.isBonemealSuccess(world, world.random, pos, blockState)) {
-                    bonemealableBlock.performBonemeal((ServerLevel)world, world.random, pos, blockState);
+        BlockState iblockdata = world.getBlockState(pos);
+        Block block = iblockdata.getBlock();
+
+        if (block instanceof BonemealableBlock iblockfragileplantelement) {
+            if (iblockfragileplantelement.isValidBonemealTarget(world, pos, iblockdata)) {
+                if (world instanceof ServerLevel) {
+                    if (iblockfragileplantelement.isBonemealSuccess(world, world.random, pos, iblockdata)) {
+                        iblockfragileplantelement.performBonemeal((ServerLevel) world, world.random, pos, iblockdata);
+                    }
+
+                    stack.shrink(1);
                 }
 
-                stack.shrink(1);
+                return true;
             }
-
-            return true;
         }
 
         return false;
@@ -81,53 +95,60 @@
             if (!(world instanceof ServerLevel)) {
                 return true;
             } else {
-                RandomSource randomSource = world.getRandom();
+                RandomSource randomsource = world.getRandom();
+                int i = 0;
 
-                label78:
-                for (int i = 0; i < 128; i++) {
-                    BlockPos blockPos2 = blockPos;
-                    BlockState blockState = Blocks.SEAGRASS.defaultBlockState();
+                while (i < 128) {
+                    BlockPos blockposition1 = blockPos;
+                    BlockState iblockdata = Blocks.SEAGRASS.defaultBlockState();
+                    int j = 0;
 
-                    for (int j = 0; j < i / 16; j++) {
-                        blockPos2 = blockPos2.offset(
-                            randomSource.nextInt(3) - 1, (randomSource.nextInt(3) - 1) * randomSource.nextInt(3) / 2, randomSource.nextInt(3) - 1
-                        );
-                        if (world.getBlockState(blockPos2).isCollisionShapeFullBlock(world, blockPos2)) {
-                            continue label78;
-                        }
-                    }
+                    while (true) {
+                        if (j < i / 16) {
+                            blockposition1 = blockposition1.offset(randomsource.nextInt(3) - 1, (randomsource.nextInt(3) - 1) * randomsource.nextInt(3) / 2, randomsource.nextInt(3) - 1);
+                            if (!world.getBlockState(blockposition1).isCollisionShapeFullBlock(world, blockposition1)) {
+                                ++j;
+                                continue;
+                            }
+                        } else {
+                            Holder<Biome> holder = world.getBiome(blockposition1);
 
-                    Holder<Biome> holder = world.getBiome(blockPos2);
-                    if (holder.is(BiomeTags.PRODUCES_CORALS_FROM_BONEMEAL)) {
-                        if (i == 0 && facing != null && facing.getAxis().isHorizontal()) {
-                            blockState = BuiltInRegistries.BLOCK
-                                .getRandomElementOf(BlockTags.WALL_CORALS, world.random)
-                                .map(blockEntry -> blockEntry.value().defaultBlockState())
-                                .orElse(blockState);
-                            if (blockState.hasProperty(BaseCoralWallFanBlock.FACING)) {
-                                blockState = blockState.setValue(BaseCoralWallFanBlock.FACING, facing);
+                            if (holder.is(BiomeTags.PRODUCES_CORALS_FROM_BONEMEAL)) {
+                                if (i == 0 && facing != null && facing.getAxis().isHorizontal()) {
+                                    iblockdata = (BlockState) BuiltInRegistries.BLOCK.getRandomElementOf(BlockTags.WALL_CORALS, world.random).map((holder1) -> {
+                                        return ((Block) holder1.value()).defaultBlockState();
+                                    }).orElse(iblockdata);
+                                    if (iblockdata.hasProperty(BaseCoralWallFanBlock.FACING)) {
+                                        iblockdata = (BlockState) iblockdata.setValue(BaseCoralWallFanBlock.FACING, facing);
+                                    }
+                                } else if (randomsource.nextInt(4) == 0) {
+                                    iblockdata = (BlockState) BuiltInRegistries.BLOCK.getRandomElementOf(BlockTags.UNDERWATER_BONEMEALS, world.random).map((holder1) -> {
+                                        return ((Block) holder1.value()).defaultBlockState();
+                                    }).orElse(iblockdata);
+                                }
                             }
-                        } else if (randomSource.nextInt(4) == 0) {
-                            blockState = BuiltInRegistries.BLOCK
-                                .getRandomElementOf(BlockTags.UNDERWATER_BONEMEALS, world.random)
-                                .map(blockEntry -> blockEntry.value().defaultBlockState())
-                                .orElse(blockState);
-                        }
-                    }
 
-                    if (blockState.is(BlockTags.WALL_CORALS, state -> state.hasProperty(BaseCoralWallFanBlock.FACING))) {
-                        for (int k = 0; !blockState.canSurvive(world, blockPos2) && k < 4; k++) {
-                            blockState = blockState.setValue(BaseCoralWallFanBlock.FACING, Direction.Plane.HORIZONTAL.getRandomDirection(randomSource));
-                        }
-                    }
+                            if (iblockdata.is(BlockTags.WALL_CORALS, (blockbase_blockdata) -> {
+                                return blockbase_blockdata.hasProperty(BaseCoralWallFanBlock.FACING);
+                            })) {
+                                for (int k = 0; !iblockdata.canSurvive(world, blockposition1) && k < 4; ++k) {
+                                    iblockdata = (BlockState) iblockdata.setValue(BaseCoralWallFanBlock.FACING, Direction.Plane.HORIZONTAL.getRandomDirection(randomsource));
+                                }
+                            }
 
-                    if (blockState.canSurvive(world, blockPos2)) {
-                        BlockState blockState2 = world.getBlockState(blockPos2);
-                        if (blockState2.is(Blocks.WATER) && world.getFluidState(blockPos2).getAmount() == 8) {
-                            world.setBlock(blockPos2, blockState, 3);
-                        } else if (blockState2.is(Blocks.SEAGRASS) && randomSource.nextInt(10) == 0) {
-                            ((BonemealableBlock)Blocks.SEAGRASS).performBonemeal((ServerLevel)world, randomSource, blockPos2, blockState2);
+                            if (iblockdata.canSurvive(world, blockposition1)) {
+                                BlockState iblockdata1 = world.getBlockState(blockposition1);
+
+                                if (iblockdata1.is(Blocks.WATER) && world.getFluidState(blockposition1).getAmount() == 8) {
+                                    world.setBlock(blockposition1, iblockdata, 3);
+                                } else if (iblockdata1.is(Blocks.SEAGRASS) && randomsource.nextInt(10) == 0) {
+                                    ((BonemealableBlock) Blocks.SEAGRASS).performBonemeal((ServerLevel) world, randomsource, blockposition1, iblockdata1);
+                                }
+                            }
                         }
+
+                        ++i;
+                        break;
                     }
                 }
 
@@ -140,18 +161,23 @@
     }
 
     public static void addGrowthParticles(LevelAccessor world, BlockPos pos, int count) {
-        BlockState blockState = world.getBlockState(pos);
-        if (blockState.getBlock() instanceof BonemealableBlock bonemealableBlock) {
-            BlockPos blockPos = bonemealableBlock.getParticlePos(pos);
-            switch (bonemealableBlock.getType()) {
+        BlockState iblockdata = world.getBlockState(pos);
+        Block block = iblockdata.getBlock();
+
+        if (block instanceof BonemealableBlock) {
+            BonemealableBlock iblockfragileplantelement = (BonemealableBlock) block;
+            BlockPos blockposition1 = iblockfragileplantelement.getParticlePos(pos);
+
+            switch (iblockfragileplantelement.getType()) {
                 case NEIGHBOR_SPREADER:
-                    ParticleUtils.spawnParticles(world, blockPos, count * 3, 3.0, 1.0, false, ParticleTypes.HAPPY_VILLAGER);
+                    ParticleUtils.spawnParticles(world, blockposition1, count * 3, 3.0D, 1.0D, false, ParticleTypes.HAPPY_VILLAGER);
                     break;
                 case GROWER:
-                    ParticleUtils.spawnParticleInBlock(world, blockPos, count, ParticleTypes.HAPPY_VILLAGER);
+                    ParticleUtils.spawnParticleInBlock(world, blockposition1, count, ParticleTypes.HAPPY_VILLAGER);
             }
-        } else if (blockState.is(Blocks.WATER)) {
-            ParticleUtils.spawnParticles(world, pos, count * 3, 3.0, 1.0, false, ParticleTypes.HAPPY_VILLAGER);
+        } else if (iblockdata.is(Blocks.WATER)) {
+            ParticleUtils.spawnParticles(world, pos, count * 3, 3.0D, 1.0D, false, ParticleTypes.HAPPY_VILLAGER);
         }
+
     }
 }
