--- a/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
@@ -82,6 +_,7 @@
     private List<BeehiveBlockEntity.BeeData> stored = Lists.newArrayList();
     @Nullable
     public BlockPos savedFlowerPos;
+    public int maxBees = MAX_OCCUPANTS; // CraftBukkit - allow setting max amount of bees a hive can hold
 
     public BeehiveBlockEntity(BlockPos pos, BlockState blockState) {
         super(BlockEntityType.BEEHIVE, pos, blockState);
@@ -115,7 +_,7 @@
     }
 
     public boolean isFull() {
-        return this.stored.size() == 3;
+        return this.stored.size() == this.maxBees; // CraftBukkit
     }
 
     public void emptyAllLivingFromHive(@Nullable Player player, BlockState state, BeehiveBlockEntity.BeeReleaseStatus releaseStatus) {
@@ -124,7 +_,7 @@
             for (Entity entity : list) {
                 if (entity instanceof Bee bee && player.position().distanceToSqr(entity.position()) <= 16.0) {
                     if (!this.isSedated()) {
-                        bee.setTarget(player);
+                        bee.setTarget(player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER); // CraftBukkit
                     } else {
                         bee.setStayOutOfHiveCountdown(400);
                     }
@@ -134,8 +_,14 @@
     }
 
     private List<Entity> releaseAllOccupants(BlockState state, BeehiveBlockEntity.BeeReleaseStatus releaseStatus) {
+        // CraftBukkit start - This allows us to bypass the night/rain/emergency check
+        return this.releaseBees(state, releaseStatus, false);
+    }
+
+    public List<Entity> releaseBees(BlockState state, BeehiveBlockEntity.BeeReleaseStatus releaseStatus, boolean force) {
+        // CraftBukkit end - This allows us to bypass t he night/rain/emergecny check
         List<Entity> list = Lists.newArrayList();
-        this.stored.removeIf(data -> releaseOccupant(this.level, this.worldPosition, state, data.toOccupant(), list, releaseStatus, this.savedFlowerPos));
+        this.stored.removeIf(data -> releaseOccupant(this.level, this.worldPosition, state, data.toOccupant(), list, releaseStatus, this.savedFlowerPos, force)); // CraftBukkit - This allows us to bypass t he night/rain/emergecny check
         if (!list.isEmpty()) {
             super.setChanged();
         }
@@ -148,6 +_,11 @@
         return this.stored.size();
     }
 
+    // Paper start - Add EntityBlockStorage clearEntities
+    public void clearBees() {
+        this.stored.clear();
+    }
+    // Paper end - Add EntityBlockStorage clearEntities
     public static int getHoneyLevel(BlockState state) {
         return state.getValue(BeehiveBlock.HONEY_LEVEL);
     }
@@ -158,7 +_,16 @@
     }
 
     public void addOccupant(Bee bee) {
-        if (this.stored.size() < 3) {
+        if (this.stored.size() < this.maxBees) { // CraftBukkit
+            // CraftBukkit start
+            if (this.level != null) {
+                org.bukkit.event.entity.EntityEnterBlockEvent event = new org.bukkit.event.entity.EntityEnterBlockEvent(bee.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(this.level, this.getBlockPos()));
+                if (!event.callEvent()) {
+                    bee.setStayOutOfHiveCountdown(MIN_TICKS_BEFORE_REENTERING_HIVE);
+                    return;
+                }
+            }
+            // CraftBukkit end
             bee.stopRiding();
             bee.ejectPassengers();
             bee.dropLeash();
@@ -183,7 +_,7 @@
                 this.level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(bee, this.getBlockState()));
             }
 
-            bee.discard();
+            bee.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.ENTER_BLOCK); // CraftBukkit - add Bukkit remove cause
             super.setChanged();
         }
     }
@@ -201,7 +_,21 @@
         BeehiveBlockEntity.BeeReleaseStatus releaseStatus,
         @Nullable BlockPos storedFlowerPos
     ) {
-        if (Bee.isNightOrRaining(level) && releaseStatus != BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY) {
+        // CraftBukkit start
+        return releaseOccupant(level, pos, state, occupant, storedInHives, releaseStatus, storedFlowerPos, false);
+    }
+    private static boolean releaseOccupant(
+        Level level,
+        BlockPos pos,
+        BlockState state,
+        BeehiveBlockEntity.Occupant occupant,
+        @Nullable List<Entity> storedInHives,
+        BeehiveBlockEntity.BeeReleaseStatus releaseStatus,
+        @Nullable BlockPos storedFlowerPos,
+        boolean force
+    ) {
+        if (!force && Bee.isNightOrRaining(level) && releaseStatus != BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY) {
+        // CraftBukkit end
             return false;
         } else {
             Direction direction = state.getValue(BeehiveBlock.FACING);
@@ -212,6 +_,17 @@
             } else {
                 Entity entity = occupant.createEntity(level, pos);
                 if (entity != null) {
+                    // CraftBukkit start
+                    if (entity instanceof Bee) {
+                        float bbWidth = entity.getBbWidth();
+                        double d = flag ? 0.0 : 0.55 + bbWidth / 2.0F;
+                        double d1 = pos.getX() + 0.5 + d * direction.getStepX();
+                        double d2 = pos.getY() + 0.5 - entity.getBbHeight() / 2.0F;
+                        double d3 = pos.getZ() + 0.5 + d * direction.getStepZ();
+                        entity.snapTo(d1, d2, d3, entity.getYRot(), entity.getXRot());
+                    }
+                    if (!level.addFreshEntity(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BEEHIVE)) return false; // CraftBukkit - SpawnReason, moved from below
+                    // CraftBukkit end
                     if (entity instanceof Bee bee) {
                         if (storedFlowerPos != null && !bee.hasSavedFlowerPos() && level.random.nextFloat() < 0.9F) {
                             bee.setSavedFlowerPos(storedFlowerPos);
@@ -227,7 +_,13 @@
                                         i--;
                                     }
 
-                                    level.setBlockAndUpdate(pos, state.setValue(BeehiveBlock.HONEY_LEVEL, honeyLevel + i));
+                                    // Paper start - Fire EntityChangeBlockEvent in more places
+                                    BlockState newBlockState = state.setValue(BeehiveBlock.HONEY_LEVEL, honeyLevel + i);
+
+                                    if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, newBlockState)) {
+                                        level.setBlockAndUpdate(pos, newBlockState);
+                                    }
+                                    // Paper end - Fire EntityChangeBlockEvent in more places
                                 }
                             }
                         }
@@ -236,17 +_,19 @@
                             storedInHives.add(bee);
                         }
 
+                        /* CraftBukkit start - move up
                         float bbWidth = entity.getBbWidth();
                         double d = flag ? 0.0 : 0.55 + bbWidth / 2.0F;
                         double d1 = pos.getX() + 0.5 + d * direction.getStepX();
                         double d2 = pos.getY() + 0.5 - entity.getBbHeight() / 2.0F;
                         double d3 = pos.getZ() + 0.5 + d * direction.getStepZ();
                         entity.snapTo(d1, d2, d3, entity.getYRot(), entity.getXRot());
+                        */ // CraftBukkit end
                     }
 
                     level.playSound(null, pos, SoundEvents.BEEHIVE_EXIT, SoundSource.BLOCKS, 1.0F, 1.0F);
                     level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(entity, level.getBlockState(pos)));
-                    return level.addFreshEntity(entity);
+                    return true; // CraftBukkit - moved up
                 } else {
                     return false;
                 }
@@ -272,6 +_,11 @@
                     flag = true;
                     iterator.remove();
                 }
+                // Paper start - Fix bees aging inside; use exitTickCounter to keep actual bee life
+                else if (level.paperConfig().entities.behavior.cooldownFailedBeehiveReleases) {
+                    beeData.exitTickCounter = beeData.occupant.minTicksInHive / 2;
+                }
+                // Paper end - Fix bees aging inside; use exitTickCounter to keep actual bee life
             }
         }
 
@@ -295,9 +_,10 @@
     @Override
     protected void loadAdditional(ValueInput input) {
         super.loadAdditional(input);
-        this.stored.clear();
+        this.stored = Lists.newArrayList(); // CraftBukkit - SPIGOT-7790: create new copy (may be modified in physics event triggered by honey change)
         input.read("bees", BeehiveBlockEntity.Occupant.LIST_CODEC).orElse(List.of()).forEach(this::storeBee);
         this.savedFlowerPos = input.read("flower_pos", BlockPos.CODEC).orElse(null);
+        this.maxBees = input.getIntOr("Bukkit.MaxEntities", MAX_OCCUPANTS); // Paper - persist max bukkit occupants
     }
 
     @Override
@@ -305,12 +_,13 @@
         super.saveAdditional(output);
         output.store("bees", BeehiveBlockEntity.Occupant.LIST_CODEC, this.getBees());
         output.storeNullable("flower_pos", BlockPos.CODEC, this.savedFlowerPos);
+        output.putInt("Bukkit.MaxEntities", this.maxBees); // Paper - persist max bukkit occupants
     }
 
     @Override
     protected void applyImplicitComponents(DataComponentGetter componentGetter) {
         super.applyImplicitComponents(componentGetter);
-        this.stored.clear();
+        this.stored = Lists.newArrayList(); // CraftBukkit - SPIGOT-7790: create new copy (may be modified in physics event triggered by honey change)
         List<BeehiveBlockEntity.Occupant> list = componentGetter.getOrDefault(DataComponents.BEES, Bees.EMPTY).bees();
         list.forEach(this::storeBee);
     }
@@ -333,15 +_,18 @@
 
     static class BeeData {
         private final BeehiveBlockEntity.Occupant occupant;
+        private int exitTickCounter; // Paper - Fix bees aging inside hives; separate counter for checking if bee should exit to reduce exit attempts
         private int ticksInHive;
 
         BeeData(BeehiveBlockEntity.Occupant occupant) {
             this.occupant = occupant;
             this.ticksInHive = occupant.ticksInHive();
+            this.exitTickCounter = this.ticksInHive; // Paper - Fix bees aging inside hives
         }
 
         public boolean tick() {
-            return this.ticksInHive++ > this.occupant.minTicksInHive;
+            this.ticksInHive++; // Paper - Fix bees aging inside hives
+            return this.exitTickCounter++ > this.occupant.minTicksInHive; // Paper - Fix bees aging inside hives
         }
 
         public BeehiveBlockEntity.Occupant toOccupant() {
@@ -418,6 +_,7 @@
         }
 
         private static void setBeeReleaseData(int ticksInHive, Bee bee) {
+            if (!bee.ageLocked) { // Paper - Honor ageLock
             int age = bee.getAge();
             if (age < 0) {
                 bee.setAge(Math.min(0, age + ticksInHive));
@@ -426,6 +_,7 @@
             }
 
             bee.setInLoveTime(Math.max(0, bee.getInLoveTime() - ticksInHive));
+            } // Paper - Honor ageLock
         }
     }
 }
