--- a/net/minecraft/world/level/block/entity/TileEntityBeehive.java
+++ b/net/minecraft/world/level/block/entity/TileEntityBeehive.java
@@ -43,6 +43,10 @@
 import net.minecraft.world.level.gameevent.GameEvent;
 import org.slf4j.Logger;
 
+// CraftBukkit start
+import org.bukkit.event.entity.EntityRemoveEvent;
+// CraftBukkit end
+
 public class TileEntityBeehive extends TileEntity {
 
     private static final Logger LOGGER = LogUtils.getLogger();
@@ -56,6 +60,7 @@
     private List<TileEntityBeehive.HiveBee> stored = Lists.newArrayList();
     @Nullable
     public BlockPosition savedFlowerPos;
+    public int maxBees = 3; // CraftBukkit - allow setting max amount of bees a hive can hold
 
     public TileEntityBeehive(BlockPosition blockposition, IBlockData iblockdata) {
         super(TileEntityTypes.BEEHIVE, blockposition, iblockdata);
@@ -95,7 +100,7 @@
     }
 
     public boolean isFull() {
-        return this.stored.size() == 3;
+        return this.stored.size() == this.maxBees; // CraftBukkit
     }
 
     public void emptyAllLivingFromHive(@Nullable EntityHuman entityhuman, IBlockData iblockdata, TileEntityBeehive.ReleaseStatus tileentitybeehive_releasestatus) {
@@ -112,7 +117,7 @@
 
                     if (entityhuman.position().distanceToSqr(entity.position()) <= 16.0D) {
                         if (!this.isSedated()) {
-                            entitybee.setTarget(entityhuman);
+                            entitybee.setTarget(entityhuman, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // CraftBukkit
                         } else {
                             entitybee.setStayOutOfHiveCountdown(400);
                         }
@@ -124,10 +129,16 @@
     }
 
     private List<Entity> releaseAllOccupants(IBlockData iblockdata, TileEntityBeehive.ReleaseStatus tileentitybeehive_releasestatus) {
+        // CraftBukkit start - This allows us to bypass the night/rain/emergency check
+        return releaseBees(iblockdata, tileentitybeehive_releasestatus, false);
+    }
+
+    public List<Entity> releaseBees(IBlockData iblockdata, TileEntityBeehive.ReleaseStatus tileentitybeehive_releasestatus, boolean force) {
         List<Entity> list = Lists.newArrayList();
 
         this.stored.removeIf((tileentitybeehive_hivebee) -> {
-            return releaseOccupant(this.level, this.worldPosition, iblockdata, tileentitybeehive_hivebee.toOccupant(), list, tileentitybeehive_releasestatus, this.savedFlowerPos);
+            return releaseOccupant(this.level, this.worldPosition, iblockdata, tileentitybeehive_hivebee.toOccupant(), list, tileentitybeehive_releasestatus, this.savedFlowerPos, force);
+            // CraftBukkit end
         });
         if (!list.isEmpty()) {
             super.setChanged();
@@ -151,7 +162,17 @@
     }
 
     public void addOccupant(EntityBee entitybee) {
-        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(entitybee.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, getBlockPos()));
+                org.bukkit.Bukkit.getPluginManager().callEvent(event);
+                if (event.isCancelled()) {
+                    entitybee.setStayOutOfHiveCountdown(400);
+                    return;
+                }
+            }
+            // CraftBukkit end
             entitybee.stopRiding();
             entitybee.ejectPassengers();
             entitybee.dropLeash();
@@ -167,7 +188,7 @@
                 this.level.gameEvent((Holder) GameEvent.BLOCK_CHANGE, blockposition, GameEvent.a.of(entitybee, this.getBlockState()));
             }
 
-            entitybee.discard();
+            entitybee.discard(EntityRemoveEvent.Cause.ENTER_BLOCK); // CraftBukkit - add Bukkit remove cause
             super.setChanged();
         }
     }
@@ -177,7 +198,13 @@
     }
 
     private static boolean releaseOccupant(World world, BlockPosition blockposition, IBlockData iblockdata, TileEntityBeehive.c tileentitybeehive_c, @Nullable List<Entity> list, TileEntityBeehive.ReleaseStatus tileentitybeehive_releasestatus, @Nullable BlockPosition blockposition1) {
-        if (EntityBee.isNightOrRaining(world) && tileentitybeehive_releasestatus != TileEntityBeehive.ReleaseStatus.EMERGENCY) {
+        // CraftBukkit start - This allows us to bypass the night/rain/emergency check
+        return releaseOccupant(world, blockposition, iblockdata, tileentitybeehive_c, list, tileentitybeehive_releasestatus, blockposition1, false);
+    }
+
+    private static boolean releaseOccupant(World world, BlockPosition blockposition, IBlockData iblockdata, TileEntityBeehive.c tileentitybeehive_c, @Nullable List<Entity> list, TileEntityBeehive.ReleaseStatus tileentitybeehive_releasestatus, @Nullable BlockPosition blockposition1, boolean force) {
+        if (!force && EntityBee.isNightOrRaining(world) && tileentitybeehive_releasestatus != TileEntityBeehive.ReleaseStatus.EMERGENCY) {
+            // CraftBukkit end
             return false;
         } else {
             EnumDirection enumdirection = (EnumDirection) iblockdata.getValue(BlockBeehive.FACING);
@@ -190,6 +217,18 @@
                 Entity entity = tileentitybeehive_c.createEntity(world, blockposition);
 
                 if (entity != null) {
+                    // CraftBukkit start
+                    if (entity instanceof EntityBee) {
+                        float f = entity.getBbWidth();
+                        double d0 = flag ? 0.0D : 0.55D + (double) (f / 2.0F);
+                        double d1 = (double) blockposition.getX() + 0.5D + d0 * (double) enumdirection.getStepX();
+                        double d2 = (double) blockposition.getY() + 0.5D - (double) (entity.getBbHeight() / 2.0F);
+                        double d3 = (double) blockposition.getZ() + 0.5D + d0 * (double) enumdirection.getStepZ();
+
+                        entity.moveTo(d1, d2, d3, entity.getYRot(), entity.getXRot());
+                    }
+                    if (!world.addFreshEntity(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BEEHIVE)) return false; // CraftBukkit - SpawnReason, moved from below
+                    // CraftBukkit end
                     if (entity instanceof EntityBee) {
                         EntityBee entitybee = (EntityBee) entity;
 
@@ -220,6 +259,7 @@
                             list.add(entitybee);
                         }
 
+                        /* // CraftBukkit start
                         float f = entity.getBbWidth();
                         double d0 = flag ? 0.0D : 0.55D + (double) (f / 2.0F);
                         double d1 = (double) blockposition.getX() + 0.5D + d0 * (double) enumdirection.getStepX();
@@ -227,11 +267,12 @@
                         double d3 = (double) blockposition.getZ() + 0.5D + d0 * (double) enumdirection.getStepZ();
 
                         entity.moveTo(d1, d2, d3, entity.getYRot(), entity.getXRot());
+                         */ // CraftBukkit end
                     }
 
                     world.playSound((EntityHuman) null, blockposition, SoundEffects.BEEHIVE_EXIT, SoundCategory.BLOCKS, 1.0F, 1.0F);
                     world.gameEvent((Holder) GameEvent.BLOCK_CHANGE, blockposition, GameEvent.a.of(entity, world.getBlockState(blockposition)));
-                    return world.addFreshEntity(entity);
+                    return true; // return this.world.addFreshEntity(entity); // CraftBukkit - moved up
                 } else {
                     return false;
                 }
@@ -256,6 +297,10 @@
                 if (releaseOccupant(world, blockposition, iblockdata, tileentitybeehive_hivebee.toOccupant(), (List) null, tileentitybeehive_releasestatus, blockposition1)) {
                     flag = true;
                     iterator.remove();
+                    // CraftBukkit start
+                } else {
+                    tileentitybeehive_hivebee.ticksInHive = tileentitybeehive_hivebee.occupant.minTicksInHive / 2; // Not strictly Vanilla behaviour in cases where bees cannot spawn but still reasonable
+                    // CraftBukkit end
                 }
             }
         }
@@ -282,7 +327,7 @@
     @Override
     protected void loadAdditional(NBTTagCompound nbttagcompound, HolderLookup.a holderlookup_a) {
         super.loadAdditional(nbttagcompound, holderlookup_a);
-        this.stored.clear();
+        this.stored = Lists.newArrayList(); // CraftBukkit - SPIGOT-7790: create new copy (may be modified in physics event triggered by honey change)
         if (nbttagcompound.contains("bees")) {
             TileEntityBeehive.c.LIST_CODEC.parse(DynamicOpsNBT.INSTANCE, nbttagcompound.get("bees")).resultOrPartial((s) -> {
                 TileEntityBeehive.LOGGER.error("Failed to parse bees: '{}'", s);
@@ -291,7 +336,12 @@
             });
         }
 
-        this.savedFlowerPos = (BlockPosition) GameProfileSerializer.readBlockPos(nbttagcompound, "flower_pos").orElse((Object) null);
+        this.savedFlowerPos = (BlockPosition) GameProfileSerializer.readBlockPos(nbttagcompound, "flower_pos").orElse(null); // CraftBukkit - decompile error
+        // CraftBukkit start
+        if (nbttagcompound.contains("Bukkit.MaxEntities")) {
+            this.maxBees = nbttagcompound.getInt("Bukkit.MaxEntities");
+        }
+        // CraftBukkit end
     }
 
     @Override
@@ -301,13 +351,14 @@
         if (this.hasSavedFlowerPos()) {
             nbttagcompound.put("flower_pos", GameProfileSerializer.writeBlockPos(this.savedFlowerPos));
         }
+        nbttagcompound.putInt("Bukkit.MaxEntities", this.maxBees); // CraftBukkit
 
     }
 
     @Override
     protected void applyImplicitComponents(TileEntity.b tileentity_b) {
         super.applyImplicitComponents(tileentity_b);
-        this.stored.clear();
+        this.stored = Lists.newArrayList(); // CraftBukkit - SPIGOT-7790: create new copy (may be modified in physics event triggered by honey change)
         List<TileEntityBeehive.c> list = (List) tileentity_b.getOrDefault(DataComponents.BEES, List.of());
 
         list.forEach(this::storeBee);
@@ -348,7 +399,7 @@
             NBTTagCompound nbttagcompound = new NBTTagCompound();
 
             entity.save(nbttagcompound);
-            List list = TileEntityBeehive.IGNORED_BEE_TAGS;
+            List<String> list = TileEntityBeehive.IGNORED_BEE_TAGS; // CraftBukkit - decompile error
 
             Objects.requireNonNull(nbttagcompound);
             list.forEach(nbttagcompound::remove);
@@ -367,7 +418,7 @@
         @Nullable
         public Entity createEntity(World world, BlockPosition blockposition) {
             NBTTagCompound nbttagcompound = this.entityData.copyTag();
-            List list = TileEntityBeehive.IGNORED_BEE_TAGS;
+            List<String> list = TileEntityBeehive.IGNORED_BEE_TAGS; // CraftBukkit - decompile error
 
             Objects.requireNonNull(nbttagcompound);
             list.forEach(nbttagcompound::remove);
