--- a/net/minecraft/world/entity/animal/Bee.java
+++ b/net/minecraft/world/entity/animal/Bee.java
@@ -128,9 +_,9 @@
     private float rollAmount;
     private float rollAmountO;
     private int timeSinceSting;
-    int ticksWithoutNectarSinceExitingHive = 0;
-    private int stayOutOfHiveCountdown = 0;
-    private int numCropsGrownSincePollination = 0;
+    public int ticksWithoutNectarSinceExitingHive = 0;
+    public int stayOutOfHiveCountdown = 0;
+    public int numCropsGrownSincePollination = 0;
     private static final int COOLDOWN_BEFORE_LOCATING_NEW_HIVE = 200;
     int remainingCooldownBeforeLocatingNewHive;
     private static final int COOLDOWN_BEFORE_LOCATING_NEW_FLOWER = 200;
@@ -140,15 +_,31 @@
     @Nullable
     BlockPos savedFlowerPos;
     @Nullable
-    BlockPos hivePos;
+    public BlockPos hivePos;
     Bee.BeePollinateGoal beePollinateGoal;
     Bee.BeeGoToHiveGoal goToHiveGoal;
     private Bee.BeeGoToKnownFlowerGoal goToKnownFlowerGoal;
     private int underWaterTicks;
+    public net.kyori.adventure.util.TriState rollingOverride = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Rolling override
 
     public Bee(EntityType<? extends Bee> entityType, Level level) {
         super(entityType, level);
-        this.moveControl = new FlyingMoveControl(this, 20, true);
+        // Paper start - Fix MC-167279
+        class BeeFlyingMoveControl extends FlyingMoveControl {
+            public BeeFlyingMoveControl(final Mob entity, final int maxPitchChange, final boolean noGravity) {
+                super(entity, maxPitchChange, noGravity);
+            }
+
+            @Override
+            public void tick() {
+                if (this.mob.getY() <= Bee.this.level().getMinY()) {
+                    this.mob.setNoGravity(false);
+                }
+                super.tick();
+            }
+        }
+        this.moveControl = new BeeFlyingMoveControl(this, 20, true);
+        // Paper end - Fix MC-167279
         this.lookControl = new Bee.BeeLookControl(this);
         this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F);
         this.setPathfindingMalus(PathType.WATER, -1.0F);
@@ -195,9 +_,18 @@
 
     @Override
     public void addAdditionalSaveData(CompoundTag compound) {
+        // CraftBukkit start - selectively save data
+        this.addAdditionalSaveData(compound, true);
+    }
+
+    @Override
+    public void addAdditionalSaveData(CompoundTag compound, boolean saveAll) {
+        // CraftBukkit end
         super.addAdditionalSaveData(compound);
+        if (saveAll) { // Paper
         compound.storeNullable("hive_pos", BlockPos.CODEC, this.hivePos);
         compound.storeNullable("flower_pos", BlockPos.CODEC, this.savedFlowerPos);
+        } // Paper
         compound.putBoolean("HasNectar", this.hasNectar());
         compound.putBoolean("HasStung", this.hasStung());
         compound.putInt("TicksSincePollination", this.ticksWithoutNectarSinceExitingHive);
@@ -235,7 +_,7 @@
                 }
 
                 if (i > 0) {
-                    livingEntity.addEffect(new MobEffectInstance(MobEffects.POISON, i * 20, 0), this);
+                    livingEntity.addEffect(new MobEffectInstance(MobEffects.POISON, i * 20, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit
                 }
             }
 
@@ -490,7 +_,11 @@
         if (this.hivePos == null) {
             return null;
         } else {
-            return this.isTooFarAway(this.hivePos) ? null : this.level().getBlockEntity(this.hivePos, BlockEntityType.BEEHIVE).orElse(null);
+            // Paper start - move over logic to accommodate isTooFarAway with chunk load check
+            return this.isTooFarAway(this.hivePos) || this.level().getChunkIfLoadedImmediately(this.hivePos.getX() >> 4, this.hivePos.getZ() >> 4) == null
+                ? null
+                : this.level().getBlockEntity(this.hivePos, BlockEntityType.BEEHIVE).orElse(null);
+            // Paper end
         }
     }
 
@@ -502,7 +_,7 @@
         return this.getFlag(8);
     }
 
-    void setHasNectar(boolean hasNectar) {
+    public void setHasNectar(boolean hasNectar) {
         if (hasNectar) {
             this.resetTicksWithoutNectarSinceExitingHive();
         }
@@ -514,15 +_,16 @@
         return this.getFlag(4);
     }
 
-    private void setHasStung(boolean hasStung) {
+    public void setHasStung(boolean hasStung) {
         this.setFlag(4, hasStung);
     }
 
-    private boolean isRolling() {
+    public boolean isRolling() {
         return this.getFlag(2);
     }
 
-    private void setRolling(boolean isRolling) {
+    public void setRolling(boolean isRolling) {
+        isRolling = this.rollingOverride.toBooleanOrElse(isRolling); // Paper - Rolling override
         this.setFlag(2, isRolling);
     }
 
@@ -579,7 +_,7 @@
             if (beeInteractionEffect != null) {
                 this.usePlayerItem(player, hand, itemInHand);
                 if (!this.level().isClientSide) {
-                    this.addEffect(beeInteractionEffect);
+                    this.addEffect(beeInteractionEffect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.FOOD); // Paper - Add missing effect cause
                 }
 
                 return InteractionResult.SUCCESS;
@@ -599,22 +_,22 @@
     }
 
     @Override
-    protected SoundEvent getAmbientSound() {
+    public SoundEvent getAmbientSound() {
         return null;
     }
 
     @Override
-    protected SoundEvent getHurtSound(DamageSource damageSource) {
+    public SoundEvent getHurtSound(DamageSource damageSource) {
         return SoundEvents.BEE_HURT;
     }
 
     @Override
-    protected SoundEvent getDeathSound() {
+    public SoundEvent getDeathSound() {
         return SoundEvents.BEE_DEATH;
     }
 
     @Override
-    protected float getSoundVolume() {
+    public float getSoundVolume() {
         return 0.4F;
     }
 
@@ -648,8 +_,9 @@
         if (this.isInvulnerableTo(level, damageSource)) {
             return false;
         } else {
+            if (!super.hurtServer(level, damageSource, amount)) return false; // CraftBukkit - Only stop pollinating if entity was damaged
             this.beePollinateGoal.stopPollinating();
-            return super.hurtServer(level, damageSource, amount);
+            return true; // CraftBukkit - Only stop pollinating if entity was damaged
         }
     }
 
@@ -770,7 +_,7 @@
     @VisibleForDebug
     public class BeeGoToHiveGoal extends Bee.BaseBeeGoal {
         public static final int MAX_TRAVELLING_TICKS = 2400;
-        int travellingTicks = Bee.this.level().random.nextInt(10);
+        int travellingTicks = Bee.this.random.nextInt(10); // CraftBukkit - SPIGOT-7495: Give Bees another chance and let them use their own random, avoid concurrency issues
         private static final int MAX_BLACKLISTED_TARGETS = 3;
         final List<BlockPos> blacklistedTargets = Lists.newArrayList();
         @Nullable
@@ -886,7 +_,7 @@
 
     public class BeeGoToKnownFlowerGoal extends Bee.BaseBeeGoal {
         private static final int MAX_TRAVELLING_TICKS = 2400;
-        int travellingTicks = Bee.this.level().random.nextInt(10);
+        int travellingTicks = Bee.this.random.nextInt(10); // CraftBukkit - SPIGOT-7495: Give Bees another chance and let them use their own random, avoid concurrency issues
 
         BeeGoToKnownFlowerGoal() {
             this.setFlags(EnumSet.of(Goal.Flag.MOVE));
@@ -983,7 +_,7 @@
                             }
                         }
 
-                        if (blockState1 != null) {
+                        if (blockState1 != null && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(Bee.this, blockPos, blockState1)) { // CraftBukkit
                             Bee.this.level().levelEvent(2011, blockPos, 15);
                             Bee.this.level().setBlockAndUpdate(blockPos, blockState1);
                             Bee.this.incrementNumCropsGrownSincePollination();
@@ -1007,7 +_,7 @@
         @Override
         protected void alertOther(Mob mob, LivingEntity target) {
             if (mob instanceof Bee && this.mob.hasLineOfSight(target)) {
-                mob.setTarget(target);
+                mob.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_ENTITY); // CraftBukkit - reason
             }
         }
     }
@@ -1165,7 +_,7 @@
                     Bee.this.dropFlower();
                     this.pollinating = false;
                     Bee.this.remainingCooldownBeforeLocatingNewFlower = 200;
-                } else {
+                } else if (Bee.this.savedFlowerPos != null) { // Paper - add null check since API can manipulate this
                     Vec3 vec3 = Vec3.atBottomCenterOf(Bee.this.savedFlowerPos).add(0.0, 0.6F, 0.0);
                     if (vec3.distanceTo(Bee.this.position()) > 1.0) {
                         this.hoverPos = vec3;
