--- a/net/minecraft/world/level/block/entity/BellBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BellBlockEntity.java
@@ -1,5 +1,6 @@
 package net.minecraft.world.level.block.entity;
 
+import java.util.Iterator;
 import java.util.List;
 import net.minecraft.core.BlockPos;
 import net.minecraft.core.Direction;
@@ -13,12 +14,14 @@
 import net.minecraft.world.effect.MobEffects;
 import net.minecraft.world.entity.LivingEntity;
 import net.minecraft.world.entity.ai.memory.MemoryModuleType;
+import net.minecraft.world.entity.player.Player;
 import net.minecraft.world.level.Level;
 import net.minecraft.world.level.block.state.BlockState;
 import net.minecraft.world.phys.AABB;
 import org.apache.commons.lang3.mutable.MutableInt;
 
 public class BellBlockEntity extends BlockEntity {
+
     private static final int DURATION = 50;
     private static final int GLOW_DURATION = 60;
     private static final int MIN_TICKS_BETWEEN_SEARCHES = 60;
@@ -55,39 +58,47 @@
 
     private static void tick(Level world, BlockPos pos, BlockState state, BellBlockEntity blockEntity, BellBlockEntity.ResonationEndAction bellEffect) {
         if (blockEntity.shaking) {
-            blockEntity.ticks++;
+            ++blockEntity.ticks;
         }
 
         if (blockEntity.ticks >= 50) {
             blockEntity.shaking = false;
+            // Paper start - Fix bell block entity memory leak
+            if (!blockEntity.resonating) {
+                blockEntity.nearbyEntities.clear();
+            }
+            // Paper end - Fix bell block entity memory leak
             blockEntity.ticks = 0;
         }
 
-        if (blockEntity.ticks >= 5 && blockEntity.resonationTicks == 0 && areRaidersNearby(pos, blockEntity.nearbyEntities)) {
+        if (blockEntity.ticks >= 5 && blockEntity.resonationTicks == 0 && BellBlockEntity.areRaidersNearby(pos, blockEntity.nearbyEntities)) {
             blockEntity.resonating = true;
-            world.playSound(null, pos, SoundEvents.BELL_RESONATE, SoundSource.BLOCKS, 1.0F, 1.0F);
+            world.playSound((Player) null, pos, SoundEvents.BELL_RESONATE, SoundSource.BLOCKS, 1.0F, 1.0F);
         }
 
         if (blockEntity.resonating) {
             if (blockEntity.resonationTicks < 40) {
-                blockEntity.resonationTicks++;
+                ++blockEntity.resonationTicks;
             } else {
                 bellEffect.run(world, pos, blockEntity.nearbyEntities);
+                blockEntity.nearbyEntities.clear(); // Paper - Fix bell block entity memory leak
                 blockEntity.resonating = false;
             }
         }
+
     }
 
     public static void clientTick(Level world, BlockPos pos, BlockState state, BellBlockEntity blockEntity) {
-        tick(world, pos, state, blockEntity, BellBlockEntity::showBellParticles);
+        BellBlockEntity.tick(world, pos, state, blockEntity, BellBlockEntity::showBellParticles);
     }
 
     public static void serverTick(Level world, BlockPos pos, BlockState state, BellBlockEntity blockEntity) {
-        tick(world, pos, state, blockEntity, BellBlockEntity::makeRaidersGlow);
+        BellBlockEntity.tick(world, pos, state, blockEntity, BellBlockEntity::makeRaidersGlow);
     }
 
     public void onHit(Direction direction) {
-        BlockPos blockPos = this.getBlockPos();
+        BlockPos blockposition = this.getBlockPos();
+
         this.clickDirection = direction;
         if (this.shaking) {
             this.ticks = 0;
@@ -95,77 +106,102 @@
             this.shaking = true;
         }
 
-        this.level.blockEvent(blockPos, this.getBlockState().getBlock(), 1, direction.get3DDataValue());
+        this.level.blockEvent(blockposition, this.getBlockState().getBlock(), 1, direction.get3DDataValue());
     }
 
     private void updateEntities() {
-        BlockPos blockPos = this.getBlockPos();
+        BlockPos blockposition = this.getBlockPos();
+
         if (this.level.getGameTime() > this.lastRingTimestamp + 60L || this.nearbyEntities == null) {
             this.lastRingTimestamp = this.level.getGameTime();
-            AABB aABB = new AABB(blockPos).inflate(48.0);
-            this.nearbyEntities = this.level.getEntitiesOfClass(LivingEntity.class, aABB);
+            AABB axisalignedbb = (new AABB(blockposition)).inflate(48.0D);
+
+            this.nearbyEntities = this.level.getEntitiesOfClass(LivingEntity.class, axisalignedbb);
         }
 
         if (!this.level.isClientSide) {
-            for (LivingEntity livingEntity : this.nearbyEntities) {
-                if (livingEntity.isAlive() && !livingEntity.isRemoved() && blockPos.closerToCenterThan(livingEntity.position(), 32.0)) {
-                    livingEntity.getBrain().setMemory(MemoryModuleType.HEARD_BELL_TIME, this.level.getGameTime());
+            Iterator iterator = this.nearbyEntities.iterator();
+
+            while (iterator.hasNext()) {
+                LivingEntity entityliving = (LivingEntity) iterator.next();
+
+                if (entityliving.isAlive() && !entityliving.isRemoved() && blockposition.closerToCenterThan(entityliving.position(), 32.0D)) {
+                    entityliving.getBrain().setMemory(MemoryModuleType.HEARD_BELL_TIME, this.level.getGameTime()); // CraftBukkit - decompile error
                 }
             }
         }
+
+        this.nearbyEntities.removeIf(e -> !e.isAlive()); // Paper - Fix bell block entity memory leak
     }
 
     private static boolean areRaidersNearby(BlockPos pos, List<LivingEntity> hearingEntities) {
-        for (LivingEntity livingEntity : hearingEntities) {
-            if (livingEntity.isAlive()
-                && !livingEntity.isRemoved()
-                && pos.closerToCenterThan(livingEntity.position(), 32.0)
-                && livingEntity.getType().is(EntityTypeTags.RAIDERS)) {
-                return true;
+        Iterator iterator = hearingEntities.iterator();
+
+        LivingEntity entityliving;
+
+        do {
+            if (!iterator.hasNext()) {
+                return false;
             }
-        }
 
-        return false;
+            entityliving = (LivingEntity) iterator.next();
+        } while (!entityliving.isAlive() || entityliving.isRemoved() || !pos.closerToCenterThan(entityliving.position(), 32.0D) || !entityliving.getType().is(EntityTypeTags.RAIDERS));
+
+        return true;
     }
 
     private static void makeRaidersGlow(Level world, BlockPos pos, List<LivingEntity> hearingEntities) {
-        hearingEntities.stream().filter(entity -> isRaiderWithinRange(pos, entity)).forEach(BellBlockEntity::glow);
+        List<org.bukkit.entity.LivingEntity> entities = // CraftBukkit
+        hearingEntities.stream().filter((entityliving) -> {
+            return BellBlockEntity.isRaiderWithinRange(pos, entityliving);
+        }).map((entity) -> (org.bukkit.entity.LivingEntity) entity.getBukkitEntity()).collect(java.util.stream.Collectors.toCollection(java.util.ArrayList::new)); // CraftBukkit
+
+        org.bukkit.craftbukkit.event.CraftEventFactory.handleBellResonateEvent(world, pos, entities).forEach(entity -> glow(entity, pos)); // Paper - Add BellRevealRaiderEvent
+        // CraftBukkit end
     }
 
     private static void showBellParticles(Level world, BlockPos pos, List<LivingEntity> hearingEntities) {
-        MutableInt mutableInt = new MutableInt(16700985);
-        int i = (int)hearingEntities.stream().filter(entity -> pos.closerToCenterThan(entity.position(), 48.0)).count();
-        hearingEntities.stream()
-            .filter(entity -> isRaiderWithinRange(pos, entity))
-            .forEach(
-                entity -> {
-                    float f = 1.0F;
-                    double d = Math.sqrt(
-                        (entity.getX() - (double)pos.getX()) * (entity.getX() - (double)pos.getX())
-                            + (entity.getZ() - (double)pos.getZ()) * (entity.getZ() - (double)pos.getZ())
-                    );
-                    double e = (double)((float)pos.getX() + 0.5F) + 1.0 / d * (entity.getX() - (double)pos.getX());
-                    double g = (double)((float)pos.getZ() + 0.5F) + 1.0 / d * (entity.getZ() - (double)pos.getZ());
-                    int j = Mth.clamp((i - 21) / -2, 3, 15);
+        MutableInt mutableint = new MutableInt(16700985);
+        int i = (int) hearingEntities.stream().filter((entityliving) -> {
+            return pos.closerToCenterThan(entityliving.position(), 48.0D);
+        }).count();
 
-                    for (int k = 0; k < j; k++) {
-                        int l = mutableInt.addAndGet(5);
-                        world.addParticle(ColorParticleOption.create(ParticleTypes.ENTITY_EFFECT, l), e, (double)((float)pos.getY() + 0.5F), g, 0.0, 0.0, 0.0);
-                    }
-                }
-            );
+        hearingEntities.stream().filter((entityliving) -> {
+            return BellBlockEntity.isRaiderWithinRange(pos, entityliving);
+        }).forEach((entityliving) -> {
+            float f = 1.0F;
+            double d0 = Math.sqrt((entityliving.getX() - (double) pos.getX()) * (entityliving.getX() - (double) pos.getX()) + (entityliving.getZ() - (double) pos.getZ()) * (entityliving.getZ() - (double) pos.getZ()));
+            double d1 = (double) ((float) pos.getX() + 0.5F) + 1.0D / d0 * (entityliving.getX() - (double) pos.getX());
+            double d2 = (double) ((float) pos.getZ() + 0.5F) + 1.0D / d0 * (entityliving.getZ() - (double) pos.getZ());
+            int j = Mth.clamp((i - 21) / -2, 3, 15);
+
+            for (int k = 0; k < j; ++k) {
+                int l = mutableint.addAndGet(5);
+
+                world.addParticle(ColorParticleOption.create(ParticleTypes.ENTITY_EFFECT, l), d1, (double) ((float) pos.getY() + 0.5F), d2, 0.0D, 0.0D, 0.0D);
+            }
+
+        });
     }
 
     private static boolean isRaiderWithinRange(BlockPos pos, LivingEntity entity) {
-        return entity.isAlive() && !entity.isRemoved() && pos.closerToCenterThan(entity.position(), 48.0) && entity.getType().is(EntityTypeTags.RAIDERS);
+        return entity.isAlive() && !entity.isRemoved() && pos.closerToCenterThan(entity.position(), 48.0D) && entity.getType().is(EntityTypeTags.RAIDERS);
     }
 
     private static void glow(LivingEntity entity) {
+        // Paper start - Add BellRevealRaiderEvent
+        glow(entity, null);
+    }
+
+    private static void glow(LivingEntity entity, @javax.annotation.Nullable BlockPos pos) {
+        if (pos != null && !new io.papermc.paper.event.block.BellRevealRaiderEvent(org.bukkit.craftbukkit.block.CraftBlock.at(entity.level(), pos), (org.bukkit.entity.Raider) entity.getBukkitEntity()).callEvent()) return;
+        // Paper end - Add BellRevealRaiderEvent
         entity.addEffect(new MobEffectInstance(MobEffects.GLOWING, 60));
     }
 
     @FunctionalInterface
-    interface ResonationEndAction {
+    private interface ResonationEndAction {
+
         void run(Level world, BlockPos pos, List<LivingEntity> hearingEntities);
     }
 }
