--- a/net/minecraft/server/TileEntityBeehive.java
+++ b/net/minecraft/server/TileEntityBeehive.java
@@ -10,6 +10,7 @@
     private final List<TileEntityBeehive.HiveBee> bees = Lists.newArrayList();
     @Nullable
     public BlockPosition flowerPos = null;
+    public int maxBees = 3; // CraftBukkit - allow setting max amount of bees a hive can hold
 
     public TileEntityBeehive() {
         super(TileEntityTypes.BEEHIVE);
@@ -49,7 +50,7 @@
     }
 
     public boolean isFull() {
-        return this.bees.size() == 3;
+        return this.bees.size() == this.maxBees; // CraftBukkit
     }
 
     public void a(@Nullable EntityHuman entityhuman, IBlockData iblockdata, TileEntityBeehive.ReleaseStatus tileentitybeehive_releasestatus) {
@@ -66,7 +67,7 @@
 
                     if (entityhuman.getPositionVector().distanceSquared(entity.getPositionVector()) <= 16.0D) {
                         if (!this.isSedated()) {
-                            entitybee.setGoalTarget(entityhuman);
+                            entitybee.setGoalTarget(entityhuman, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // CraftBukkit
                         } else {
                             entitybee.setCannotEnterHiveTicks(400);
                         }
@@ -78,10 +79,16 @@
     }
 
     private List<Entity> releaseBees(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.bees.removeIf((tileentitybeehive_hivebee) -> {
-            return this.releaseBee(iblockdata, tileentitybeehive_hivebee, list, tileentitybeehive_releasestatus);
+            return this.releaseBee(iblockdata, tileentitybeehive_hivebee, list, tileentitybeehive_releasestatus, force);
+            // CraftBukkit end
         });
         return list;
     }
@@ -107,7 +114,19 @@
     }
 
     public void a(Entity entity, boolean flag, int i) {
-        if (this.bees.size() < 3) {
+        if (this.bees.size() < this.maxBees) { // CraftBukkit
+            // CraftBukkit start
+            if (this.world != null) {
+                org.bukkit.event.entity.EntityEnterBlockEvent event = new org.bukkit.event.entity.EntityEnterBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, getPosition()));
+                org.bukkit.Bukkit.getPluginManager().callEvent(event);
+                if (event.isCancelled()) {
+                    if (entity instanceof EntityBee) {
+                        ((EntityBee) entity).setCannotEnterHiveTicks(400);
+                    }
+                    return;
+                }
+            }
+            // CraftBukkit end
             entity.stopRiding();
             entity.ejectPassengers();
             NBTTagCompound nbttagcompound = new NBTTagCompound();
@@ -133,7 +152,13 @@
     }
 
     private boolean releaseBee(IBlockData iblockdata, TileEntityBeehive.HiveBee tileentitybeehive_hivebee, @Nullable List<Entity> list, TileEntityBeehive.ReleaseStatus tileentitybeehive_releasestatus) {
-        if ((this.world.isNight() || this.world.isRaining()) && tileentitybeehive_releasestatus != TileEntityBeehive.ReleaseStatus.EMERGENCY) {
+        // CraftBukkit start - This allows us to bypass the night/rain/emergency check
+        return releaseBee(iblockdata, tileentitybeehive_hivebee, list, tileentitybeehive_releasestatus, false);
+    }
+
+    private boolean releaseBee(IBlockData iblockdata, TileEntityBeehive.HiveBee tileentitybeehive_hivebee, @Nullable List<Entity> list, TileEntityBeehive.ReleaseStatus tileentitybeehive_releasestatus, boolean force) {
+        if (!force && (this.world.isNight() || this.world.isRaining()) && tileentitybeehive_releasestatus != TileEntityBeehive.ReleaseStatus.EMERGENCY) {
+            // CraftBukkit end
             return false;
         } else {
             BlockPosition blockposition = this.getPosition();
@@ -157,6 +182,18 @@
                     if (!entity.getEntityType().a((Tag) TagsEntity.BEEHIVE_INHABITORS)) {
                         return false;
                     } else {
+                        // CraftBukkit start
+                        if (entity instanceof EntityBee) {
+                            float f = entity.getWidth();
+                            double d0 = flag ? 0.0D : 0.55D + (double) (f / 2.0F);
+                            double d1 = (double) blockposition.getX() + 0.5D + d0 * (double) enumdirection.getAdjacentX();
+                            double d2 = (double) blockposition.getY() + 0.5D - (double) (entity.getHeight() / 2.0F);
+                            double d3 = (double) blockposition.getZ() + 0.5D + d0 * (double) enumdirection.getAdjacentZ();
+
+                            entity.setPositionRotation(d1, d2, d3, entity.yaw, entity.pitch);
+                        }
+                        if (!this.world.addEntity(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;
 
@@ -186,6 +223,7 @@
                                 list.add(entitybee);
                             }
 
+                            /* // CraftBukkit start
                             float f = entity.getWidth();
                             double d0 = flag ? 0.0D : 0.55D + (double) (f / 2.0F);
                             double d1 = (double) blockposition.getX() + 0.5D + d0 * (double) enumdirection.getAdjacentX();
@@ -193,10 +231,11 @@
                             double d3 = (double) blockposition.getZ() + 0.5D + d0 * (double) enumdirection.getAdjacentZ();
 
                             entity.setPositionRotation(d1, d2, d3, entity.yaw, entity.pitch);
+                             */ // CraftBukkit end
                         }
 
                         this.world.playSound((EntityHuman) null, blockposition, SoundEffects.BLOCK_BEEHIVE_EXIT, SoundCategory.BLOCKS, 1.0F, 1.0F);
-                        return this.world.addEntity(entity);
+                        return true; // return this.world.addEntity(entity); // CraftBukkit - moved up
                     }
                 } else {
                     return false;
@@ -235,6 +274,11 @@
                 if (this.releaseBee(iblockdata, tileentitybeehive_hivebee, (List) null, tileentitybeehive_releasestatus)) {
                     iterator.remove();
                 }
+                // CraftBukkit start
+                else {
+                    tileentitybeehive_hivebee.ticksInHive = tileentitybeehive_hivebee.minOccupationTicks / 2; // Not strictly Vanilla behaviour in cases where bees cannot spawn but still reasonable
+                }
+                // CraftBukkit end
             }
         }
 
@@ -276,6 +320,11 @@
             this.flowerPos = GameProfileSerializer.b(nbttagcompound.getCompound("FlowerPos"));
         }
 
+        // CraftBukkit start
+        if (nbttagcompound.hasKey("Bukkit.MaxEntities")) {
+            this.maxBees = nbttagcompound.getInt("Bukkit.MaxEntities");
+        }
+        // CraftBukkit end
     }
 
     @Override
@@ -285,6 +334,7 @@
         if (this.x()) {
             nbttagcompound.set("FlowerPos", GameProfileSerializer.a(this.flowerPos));
         }
+        nbttagcompound.setInt("Bukkit.MaxEntities", this.maxBees); // CraftBukkit
 
         return nbttagcompound;
     }