--- a/net/minecraft/world/entity/LightningBolt.java
+++ b/net/minecraft/world/entity/LightningBolt.java
@@ -1,6 +1,8 @@
 package net.minecraft.world.entity;
 
 import com.google.common.collect.Sets;
+import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
@@ -8,6 +10,8 @@
 import javax.annotation.Nullable;
 import net.minecraft.advancements.CriteriaTriggers;
 import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.core.Vec3i;
 import net.minecraft.nbt.CompoundTag;
 import net.minecraft.server.level.ServerLevel;
 import net.minecraft.server.level.ServerPlayer;
@@ -24,8 +28,12 @@
 import net.minecraft.world.level.gameevent.GameEvent;
 import net.minecraft.world.phys.AABB;
 import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.craftbukkit.v1_19_R2.event.CraftEventFactory;
+// CraftBukkit end
 
 public class LightningBolt extends Entity {
+
     private static final int START_LIFE = 2;
     private static final double DAMAGE_RADIUS = 3.0D;
     private static final double DETECTION_RADIUS = 15.0D;
@@ -37,6 +45,7 @@
     private ServerPlayer cause;
     private final Set<Entity> hitEntities = Sets.newHashSet();
     private int blocksSetOnFire;
+    public boolean isSilent = false; // Spigot
 
     public LightningBolt(EntityType<? extends LightningBolt> type, Level world) {
         super(type, world);
@@ -65,10 +74,11 @@
     }
 
     private void powerLightningRod() {
-        BlockPos blockPos = this.getStrikePosition();
-        BlockState blockState = this.level.getBlockState(blockPos);
-        if (blockState.is(Blocks.LIGHTNING_ROD)) {
-            ((LightningRodBlock)blockState.getBlock()).onLightningStrike(blockState, this.level, blockPos);
+        BlockPos blockposition = this.getStrikePosition();
+        BlockState iblockdata = this.level.getBlockState(blockposition);
+
+        if (iblockdata.is(Blocks.LIGHTNING_ROD)) {
+            ((LightningRodBlock) iblockdata.getBlock()).onLightningStrike(iblockdata, this.level, blockposition);
         }
 
     }
@@ -76,34 +86,41 @@
     @Override
     public void tick() {
         super.tick();
-        if (this.life == 2) {
+        if (!this.isSilent && this.life == 2) { // Spigot
             if (this.level.isClientSide()) {
                 this.level.playLocalSound(this.getX(), this.getY(), this.getZ(), SoundEvents.LIGHTNING_BOLT_THUNDER, SoundSource.WEATHER, 10000.0F, 0.8F + this.random.nextFloat() * 0.2F, false);
                 this.level.playLocalSound(this.getX(), this.getY(), this.getZ(), SoundEvents.LIGHTNING_BOLT_IMPACT, SoundSource.WEATHER, 2.0F, 0.5F + this.random.nextFloat() * 0.2F, false);
             } else {
-                Difficulty difficulty = this.level.getDifficulty();
-                if (difficulty == Difficulty.NORMAL || difficulty == Difficulty.HARD) {
+                Difficulty enumdifficulty = this.level.getDifficulty();
+
+                if (enumdifficulty == Difficulty.NORMAL || enumdifficulty == Difficulty.HARD) {
                     this.spawnFire(4);
                 }
 
                 this.powerLightningRod();
-                clearCopperOnLightningStrike(this.level, this.getStrikePosition());
+                LightningBolt.clearCopperOnLightningStrike(this.level, this.getStrikePosition(), this); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent
                 this.gameEvent(GameEvent.LIGHTNING_STRIKE);
             }
         }
 
         --this.life;
+        List list;
+        Iterator iterator;
+
         if (this.life < 0) {
             if (this.flashes == 0) {
                 if (this.level instanceof ServerLevel) {
-                    List<Entity> list = this.level.getEntities(this, new AABB(this.getX() - 15.0D, this.getY() - 15.0D, this.getZ() - 15.0D, this.getX() + 15.0D, this.getY() + 6.0D + 15.0D, this.getZ() + 15.0D), (entityx) -> {
-                        return entityx.isAlive() && !this.hitEntities.contains(entityx);
+                    list = this.level.getEntities((Entity) this, new AABB(this.getX() - 15.0D, this.getY() - 15.0D, this.getZ() - 15.0D, this.getX() + 15.0D, this.getY() + 6.0D + 15.0D, this.getZ() + 15.0D), (entity) -> {
+                        return entity.isAlive() && !this.hitEntities.contains(entity);
                     });
+                    iterator = ((ServerLevel) this.level).getPlayers((entityplayer) -> {
+                        return entityplayer.distanceTo(this) < 256.0F;
+                    }).iterator();
 
-                    for(ServerPlayer serverPlayer : ((ServerLevel)this.level).getPlayers((serverPlayer) -> {
-                        return serverPlayer.distanceTo(this) < 256.0F;
-                    })) {
-                        CriteriaTriggers.LIGHTNING_STRIKE.trigger(serverPlayer, this, list);
+                    while (iterator.hasNext()) {
+                        ServerPlayer entityplayer = (ServerPlayer) iterator.next();
+
+                        CriteriaTriggers.LIGHTNING_STRIKE.trigger(entityplayer, this, list);
                     }
                 }
 
@@ -116,19 +133,22 @@
             }
         }
 
-        if (this.life >= 0) {
+        if (this.life >= 0 && !this.visualOnly) { // CraftBukkit - add !this.visualOnly
             if (!(this.level instanceof ServerLevel)) {
                 this.level.setSkyFlashTime(2);
             } else if (!this.visualOnly) {
-                List<Entity> list2 = this.level.getEntities(this, new AABB(this.getX() - 3.0D, this.getY() - 3.0D, this.getZ() - 3.0D, this.getX() + 3.0D, this.getY() + 6.0D + 3.0D, this.getZ() + 3.0D), Entity::isAlive);
+                list = this.level.getEntities((Entity) this, new AABB(this.getX() - 3.0D, this.getY() - 3.0D, this.getZ() - 3.0D, this.getX() + 3.0D, this.getY() + 6.0D + 3.0D, this.getZ() + 3.0D), Entity::isAlive);
+                iterator = list.iterator();
 
-                for(Entity entity : list2) {
-                    entity.thunderHit((ServerLevel)this.level, this);
+                while (iterator.hasNext()) {
+                    Entity entity = (Entity) iterator.next();
+
+                    entity.thunderHit((ServerLevel) this.level, this);
                 }
 
-                this.hitEntities.addAll(list2);
+                this.hitEntities.addAll(list);
                 if (this.cause != null) {
-                    CriteriaTriggers.CHANNELED_LIGHTNING.trigger(this.cause, list2);
+                    CriteriaTriggers.CHANNELED_LIGHTNING.trigger(this.cause, (Collection) list);
                 }
             }
         }
@@ -136,102 +156,128 @@
     }
 
     private BlockPos getStrikePosition() {
-        Vec3 vec3 = this.position();
-        return new BlockPos(vec3.x, vec3.y - 1.0E-6D, vec3.z);
+        Vec3 vec3d = this.position();
+
+        return new BlockPos(vec3d.x, vec3d.y - 1.0E-6D, vec3d.z);
     }
 
     private void spawnFire(int spreadAttempts) {
         if (!this.visualOnly && !this.level.isClientSide && this.level.getGameRules().getBoolean(GameRules.RULE_DOFIRETICK)) {
-            BlockPos blockPos = this.blockPosition();
-            BlockState blockState = BaseFireBlock.getState(this.level, blockPos);
-            if (this.level.getBlockState(blockPos).isAir() && blockState.canSurvive(this.level, blockPos)) {
-                this.level.setBlockAndUpdate(blockPos, blockState);
-                ++this.blocksSetOnFire;
-            }
+            BlockPos blockposition = this.blockPosition();
+            BlockState iblockdata = BaseFireBlock.getState(this.level, blockposition);
 
-            for(int i = 0; i < spreadAttempts; ++i) {
-                BlockPos blockPos2 = blockPos.offset(this.random.nextInt(3) - 1, this.random.nextInt(3) - 1, this.random.nextInt(3) - 1);
-                blockState = BaseFireBlock.getState(this.level, blockPos2);
-                if (this.level.getBlockState(blockPos2).isAir() && blockState.canSurvive(this.level, blockPos2)) {
-                    this.level.setBlockAndUpdate(blockPos2, blockState);
+            if (this.level.getBlockState(blockposition).isAir() && iblockdata.canSurvive(this.level, blockposition)) {
+                // CraftBukkit start - add "!visualOnly"
+                if (!this.visualOnly && !CraftEventFactory.callBlockIgniteEvent(level, blockposition, this).isCancelled()) {
+                    this.level.setBlockAndUpdate(blockposition, iblockdata);
                     ++this.blocksSetOnFire;
                 }
+                // CraftBukkit end
+            }
+
+            for (int j = 0; j < spreadAttempts; ++j) {
+                BlockPos blockposition1 = blockposition.offset(this.random.nextInt(3) - 1, this.random.nextInt(3) - 1, this.random.nextInt(3) - 1);
+
+                iblockdata = BaseFireBlock.getState(this.level, blockposition1);
+                if (this.level.getBlockState(blockposition1).isAir() && iblockdata.canSurvive(this.level, blockposition1)) {
+                    // CraftBukkit start - add "!visualOnly"
+                    if (!this.visualOnly && !CraftEventFactory.callBlockIgniteEvent(level, blockposition1, this).isCancelled()) {
+                        this.level.setBlockAndUpdate(blockposition1, iblockdata);
+                        ++this.blocksSetOnFire;
+                    }
+                    // CraftBukkit end
+                }
             }
 
         }
     }
 
-    private static void clearCopperOnLightningStrike(Level world, BlockPos pos) {
-        BlockState blockState = world.getBlockState(pos);
-        BlockPos blockPos;
-        BlockState blockState2;
-        if (blockState.is(Blocks.LIGHTNING_ROD)) {
-            blockPos = pos.relative(blockState.getValue(LightningRodBlock.FACING).getOpposite());
-            blockState2 = world.getBlockState(blockPos);
+    private static void clearCopperOnLightningStrike(Level world, BlockPos pos, Entity lightning) { // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent
+        BlockState iblockdata = world.getBlockState(pos);
+        BlockPos blockposition1;
+        BlockState iblockdata1;
+
+        if (iblockdata.is(Blocks.LIGHTNING_ROD)) {
+            blockposition1 = pos.relative(((Direction) iblockdata.getValue(LightningRodBlock.FACING)).getOpposite());
+            iblockdata1 = world.getBlockState(blockposition1);
         } else {
-            blockPos = pos;
-            blockState2 = blockState;
+            blockposition1 = pos;
+            iblockdata1 = iblockdata;
         }
 
-        if (blockState2.getBlock() instanceof WeatheringCopper) {
-            world.setBlockAndUpdate(blockPos, WeatheringCopper.getFirst(world.getBlockState(blockPos)));
-            BlockPos.MutableBlockPos mutableBlockPos = pos.mutable();
+        if (iblockdata1.getBlock() instanceof WeatheringCopper) {
+            // Paper start - call EntityChangeBlockEvent
+            BlockState newBlock = WeatheringCopper.getFirst(world.getBlockState(blockposition1));
+            if (!CraftEventFactory.callEntityChangeBlockEvent(lightning, blockposition1, newBlock).isCancelled()) {
+                world.setBlockAndUpdate(blockposition1, newBlock);
+            }
+            // Paper end
+            BlockPos.MutableBlockPos blockposition_mutableblockposition = pos.mutable();
             int i = world.random.nextInt(3) + 3;
 
-            for(int j = 0; j < i; ++j) {
+            for (int j = 0; j < i; ++j) {
                 int k = world.random.nextInt(8) + 1;
-                randomWalkCleaningCopper(world, blockPos, mutableBlockPos, k);
+
+                LightningBolt.randomWalkCleaningCopper(world, blockposition1, blockposition_mutableblockposition, k, lightning); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent
             }
 
         }
     }
 
-    private static void randomWalkCleaningCopper(Level world, BlockPos pos, BlockPos.MutableBlockPos mutablePos, int count) {
+    private static void randomWalkCleaningCopper(Level world, BlockPos pos, BlockPos.MutableBlockPos mutablePos, int count, Entity lightning) { // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent
         mutablePos.set(pos);
 
-        for(int i = 0; i < count; ++i) {
-            Optional<BlockPos> optional = randomStepCleaningCopper(world, mutablePos);
+        for (int j = 0; j < count; ++j) {
+            Optional<BlockPos> optional = LightningBolt.randomStepCleaningCopper(world, mutablePos, lightning); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent
+
             if (!optional.isPresent()) {
                 break;
             }
 
-            mutablePos.set(optional.get());
+            mutablePos.set((Vec3i) optional.get());
         }
 
     }
 
-    private static Optional<BlockPos> randomStepCleaningCopper(Level world, BlockPos pos) {
-        for(BlockPos blockPos : BlockPos.randomInCube(world.random, 10, pos, 1)) {
-            BlockState blockState = world.getBlockState(blockPos);
-            if (blockState.getBlock() instanceof WeatheringCopper) {
-                WeatheringCopper.getPrevious(blockState).ifPresent((state) -> {
-                    world.setBlockAndUpdate(blockPos, state);
-                });
-                world.levelEvent(3002, blockPos, -1);
-                return Optional.of(blockPos);
+    private static Optional<BlockPos> randomStepCleaningCopper(Level world, BlockPos pos, Entity lightning) { // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent
+        Iterator iterator = BlockPos.randomInCube(world.random, 10, pos, 1).iterator();
+
+        BlockPos blockposition1;
+        BlockState iblockdata;
+
+        do {
+            if (!iterator.hasNext()) {
+                return Optional.empty();
             }
-        }
 
-        return Optional.empty();
+            blockposition1 = (BlockPos) iterator.next();
+            iblockdata = world.getBlockState(blockposition1);
+        } while (!(iblockdata.getBlock() instanceof WeatheringCopper));
+
+        BlockPos blockposition1Final = blockposition1; // CraftBukkit - decompile error
+        WeatheringCopper.getPrevious(iblockdata).ifPresent((iblockdata1) -> {
+            if (!CraftEventFactory.callEntityChangeBlockEvent(lightning, blockposition1Final, iblockdata1).isCancelled()) // Paper - call EntityChangeBlockEvent
+            world.setBlockAndUpdate(blockposition1Final, iblockdata1); // CraftBukkit - decompile error
+        });
+        world.levelEvent(3002, blockposition1, -1);
+        return Optional.of(blockposition1);
     }
 
     @Override
     public boolean shouldRenderAtSqrDistance(double distance) {
-        double d = 64.0D * getViewScale();
-        return distance < d * d;
+        double d1 = 64.0D * getViewScale();
+
+        return distance < d1 * d1;
     }
 
     @Override
-    protected void defineSynchedData() {
-    }
+    protected void defineSynchedData() {}
 
     @Override
-    protected void readAdditionalSaveData(CompoundTag nbt) {
-    }
+    protected void readAdditionalSaveData(CompoundTag nbt) {}
 
     @Override
-    protected void addAdditionalSaveData(CompoundTag nbt) {
-    }
+    protected void addAdditionalSaveData(CompoundTag nbt) {}
 
     public int getBlocksSetOnFire() {
         return this.blocksSetOnFire;
