--- a/net/minecraft/world/entity/animal/sniffer/Sniffer.java
+++ b/net/minecraft/world/entity/animal/sniffer/Sniffer.java
@@ -3,6 +3,7 @@
 import com.mojang.serialization.Dynamic;
 import io.netty.buffer.ByteBuf;
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
@@ -13,6 +14,7 @@
 import java.util.stream.Stream;
 import net.minecraft.core.BlockPos;
 import net.minecraft.core.GlobalPos;
+import net.minecraft.core.Holder;
 import net.minecraft.core.particles.BlockParticleOption;
 import net.minecraft.core.particles.ParticleTypes;
 import net.minecraft.network.codec.ByteBufCodecs;
@@ -34,6 +36,7 @@
 import net.minecraft.world.damagesource.DamageSource;
 import net.minecraft.world.entity.AgeableMob;
 import net.minecraft.world.entity.AnimationState;
+import net.minecraft.world.entity.Entity;
 import net.minecraft.world.entity.EntityDimensions;
 import net.minecraft.world.entity.EntityType;
 import net.minecraft.world.entity.Mob;
@@ -63,14 +66,14 @@
 import net.minecraft.world.phys.Vec3;
 
 public class Sniffer extends Animal {
+
     private static final int DIGGING_PARTICLES_DELAY_TICKS = 1700;
     private static final int DIGGING_PARTICLES_DURATION_TICKS = 6000;
     private static final int DIGGING_PARTICLES_AMOUNT = 30;
     private static final int DIGGING_DROP_SEED_OFFSET_TICKS = 120;
     private static final int SNIFFER_BABY_AGE_TICKS = 48000;
     private static final float DIGGING_BB_HEIGHT_OFFSET = 0.4F;
-    private static final EntityDimensions DIGGING_DIMENSIONS = EntityDimensions.scalable(EntityType.SNIFFER.getWidth(), EntityType.SNIFFER.getHeight() - 0.4F)
-        .withEyeHeight(0.81F);
+    private static final EntityDimensions DIGGING_DIMENSIONS = EntityDimensions.scalable(EntityType.SNIFFER.getWidth(), EntityType.SNIFFER.getHeight() - 0.4F).withEyeHeight(0.81F);
     private static final EntityDataAccessor<Sniffer.State> DATA_STATE = SynchedEntityData.defineId(Sniffer.class, EntityDataSerializers.SNIFFER_STATE);
     private static final EntityDataAccessor<Integer> DATA_DROP_SEED_AT_TICK = SynchedEntityData.defineId(Sniffer.class, EntityDataSerializers.INT);
     public final AnimationState feelingHappyAnimationState = new AnimationState();
@@ -80,7 +83,7 @@
     public final AnimationState risingAnimationState = new AnimationState();
 
     public static AttributeSupplier.Builder createAttributes() {
-        return Mob.createMobAttributes().add(Attributes.MOVEMENT_SPEED, 0.1F).add(Attributes.MAX_HEALTH, 14.0);
+        return Mob.createMobAttributes().add(Attributes.MOVEMENT_SPEED, 0.10000000149011612D).add(Attributes.MAX_HEALTH, 14.0D);
     }
 
     public Sniffer(EntityType<? extends Animal> type, Level world) {
@@ -94,8 +97,8 @@
     @Override
     protected void defineSynchedData(SynchedEntityData.Builder builder) {
         super.defineSynchedData(builder);
-        builder.define(DATA_STATE, Sniffer.State.IDLING);
-        builder.define(DATA_DROP_SEED_AT_TICK, 0);
+        builder.define(Sniffer.DATA_STATE, Sniffer.State.IDLING);
+        builder.define(Sniffer.DATA_DROP_SEED_AT_TICK, 0);
     }
 
     @Override
@@ -104,6 +107,7 @@
         if (this.isOnFire() || this.isInWater()) {
             this.setPathfindingMalus(PathType.WATER, 0.0F);
         }
+
     }
 
     @Override
@@ -113,7 +117,7 @@
 
     @Override
     public EntityDimensions getDefaultDimensions(Pose pose) {
-        return this.getState() == Sniffer.State.DIGGING ? DIGGING_DIMENSIONS.scale(this.getAgeScale()) : super.getDefaultDimensions(pose);
+        return this.getState() == Sniffer.State.DIGGING ? Sniffer.DIGGING_DIMENSIONS.scale(this.getAgeScale()) : super.getDefaultDimensions(pose);
     }
 
     public boolean isSearching() {
@@ -121,7 +125,7 @@
     }
 
     public boolean isTempted() {
-        return this.brain.getMemory(MemoryModuleType.IS_TEMPTED).orElse(false);
+        return (Boolean) this.brain.getMemory(MemoryModuleType.IS_TEMPTED).orElse(false);
     }
 
     public boolean canSniff() {
@@ -133,44 +137,46 @@
     }
 
     private BlockPos getHeadBlock() {
-        Vec3 vec3 = this.getHeadPosition();
-        return BlockPos.containing(vec3.x(), this.getY() + 0.2F, vec3.z());
+        Vec3 vec3d = this.getHeadPosition();
+
+        return BlockPos.containing(vec3d.x(), this.getY() + 0.20000000298023224D, vec3d.z());
     }
 
     private Vec3 getHeadPosition() {
-        return this.position().add(this.getForward().scale(2.25));
+        return this.position().add(this.getForward().scale(2.25D));
     }
 
     public Sniffer.State getState() {
-        return this.entityData.get(DATA_STATE);
+        return (Sniffer.State) this.entityData.get(Sniffer.DATA_STATE);
     }
 
     private Sniffer setState(Sniffer.State state) {
-        this.entityData.set(DATA_STATE, state);
+        this.entityData.set(Sniffer.DATA_STATE, state);
         return this;
     }
 
     @Override
     public void onSyncedDataUpdated(EntityDataAccessor<?> data) {
-        if (DATA_STATE.equals(data)) {
-            Sniffer.State state = this.getState();
+        if (Sniffer.DATA_STATE.equals(data)) {
+            Sniffer.State sniffer_state = this.getState();
+
             this.resetAnimations();
-            switch (state) {
-                case FEELING_HAPPY:
+            switch (sniffer_state.ordinal()) {
+                case 1:
                     this.feelingHappyAnimationState.startIfStopped(this.tickCount);
                     break;
-                case SCENTING:
+                case 2:
                     this.scentingAnimationState.startIfStopped(this.tickCount);
                     break;
-                case SNIFFING:
+                case 3:
                     this.sniffingAnimationState.startIfStopped(this.tickCount);
-                case SEARCHING:
+                case 4:
                 default:
                     break;
-                case DIGGING:
+                case 5:
                     this.diggingAnimationState.startIfStopped(this.tickCount);
                     break;
-                case RISING:
+                case 6:
                     this.risingAnimationState.startIfStopped(this.tickCount);
             }
 
@@ -189,28 +195,28 @@
     }
 
     public Sniffer transitionTo(Sniffer.State state) {
-        switch (state) {
-            case IDLING:
+        switch (state.ordinal()) {
+            case 0:
                 this.setState(Sniffer.State.IDLING);
                 break;
-            case FEELING_HAPPY:
+            case 1:
                 this.playSound(SoundEvents.SNIFFER_HAPPY, 1.0F, 1.0F);
                 this.setState(Sniffer.State.FEELING_HAPPY);
                 break;
-            case SCENTING:
+            case 2:
                 this.setState(Sniffer.State.SCENTING).onScentingStart();
                 break;
-            case SNIFFING:
+            case 3:
                 this.playSound(SoundEvents.SNIFFER_SNIFFING, 1.0F, 1.0F);
                 this.setState(Sniffer.State.SNIFFING);
                 break;
-            case SEARCHING:
+            case 4:
                 this.setState(Sniffer.State.SEARCHING);
                 break;
-            case DIGGING:
+            case 5:
                 this.setState(Sniffer.State.DIGGING).onDiggingStart();
                 break;
-            case RISING:
+            case 6:
                 this.playSound(SoundEvents.SNIFFER_DIGGING_STOP, 1.0F, 1.0F);
                 this.setState(Sniffer.State.RISING);
         }
@@ -224,8 +230,8 @@
     }
 
     private Sniffer onDiggingStart() {
-        this.entityData.set(DATA_DROP_SEED_AT_TICK, this.tickCount + 120);
-        this.level().broadcastEntityEvent(this, (byte)63);
+        this.entityData.set(Sniffer.DATA_DROP_SEED_AT_TICK, this.tickCount + 120);
+        this.level().broadcastEntityEvent(this, (byte) 63);
         return this;
     }
 
@@ -238,47 +244,45 @@
     }
 
     public Optional<BlockPos> calculateDigPosition() {
-        return IntStream.range(0, 5)
-            .mapToObj(i -> LandRandomPos.getPos(this, 10 + 2 * i, 3))
-            .filter(Objects::nonNull)
-            .map(BlockPos::containing)
-            .filter(pos -> this.level().getWorldBorder().isWithinBounds(pos))
-            .map(BlockPos::below)
-            .filter(this::canDig)
-            .findFirst();
+        return IntStream.range(0, 5).mapToObj((i) -> {
+            return LandRandomPos.getPos(this, 10 + 2 * i, 3);
+        }).filter(Objects::nonNull).map(BlockPos::containing).filter((blockposition) -> {
+            return this.level().getWorldBorder().isWithinBounds(blockposition);
+        }).map(BlockPos::below).filter(this::canDig).findFirst();
     }
 
     public boolean canDig() {
-        return !this.isPanicking()
-            && !this.isTempted()
-            && !this.isBaby()
-            && !this.isInWater()
-            && this.onGround()
-            && !this.isPassenger()
-            && this.canDig(this.getHeadBlock().below());
+        return !this.isPanicking() && !this.isTempted() && !this.isBaby() && !this.isInWater() && this.onGround() && !this.isPassenger() && this.canDig(this.getHeadBlock().below());
     }
 
     private boolean canDig(BlockPos pos) {
-        return this.level().getBlockState(pos).is(BlockTags.SNIFFER_DIGGABLE_BLOCK)
-            && this.getExploredPositions().noneMatch(globalPos -> GlobalPos.of(this.level().dimension(), pos).equals(globalPos))
-            && Optional.ofNullable(this.getNavigation().createPath(pos, 1)).map(Path::canReach).orElse(false);
+        return this.level().getBlockState(pos).is(BlockTags.SNIFFER_DIGGABLE_BLOCK) && this.getExploredPositions().noneMatch((globalpos) -> {
+            return GlobalPos.of(this.level().dimension(), pos).equals(globalpos);
+        }) && (Boolean) Optional.ofNullable(this.getNavigation().createPath(pos, 1)).map(Path::canReach).orElse(false);
     }
 
     private void dropSeed() {
-        if (!this.level().isClientSide() && this.entityData.get(DATA_DROP_SEED_AT_TICK) == this.tickCount) {
-            ServerLevel serverLevel = (ServerLevel)this.level();
-            LootTable lootTable = serverLevel.getServer().reloadableRegistries().getLootTable(BuiltInLootTables.SNIFFER_DIGGING);
-            LootParams lootParams = new LootParams.Builder(serverLevel)
-                .withParameter(LootContextParams.ORIGIN, this.getHeadPosition())
-                .withParameter(LootContextParams.THIS_ENTITY, this)
-                .create(LootContextParamSets.GIFT);
-            List<ItemStack> list = lootTable.getRandomItems(lootParams);
-            BlockPos blockPos = this.getHeadBlock();
+        if (!this.level().isClientSide() && (Integer) this.entityData.get(Sniffer.DATA_DROP_SEED_AT_TICK) == this.tickCount) {
+            ServerLevel worldserver = (ServerLevel) this.level();
+            LootTable loottable = worldserver.getServer().reloadableRegistries().getLootTable(BuiltInLootTables.SNIFFER_DIGGING);
+            LootParams lootparams = (new LootParams.Builder(worldserver)).withParameter(LootContextParams.ORIGIN, this.getHeadPosition()).withParameter(LootContextParams.THIS_ENTITY, this).create(LootContextParamSets.GIFT);
+            List<ItemStack> list = loottable.getRandomItems(lootparams);
+            BlockPos blockposition = this.getHeadBlock();
+            Iterator iterator = list.iterator();
 
-            for (ItemStack itemStack : list) {
-                ItemEntity itemEntity = new ItemEntity(serverLevel, (double)blockPos.getX(), (double)blockPos.getY(), (double)blockPos.getZ(), itemStack);
-                itemEntity.setDefaultPickUpDelay();
-                serverLevel.addFreshEntity(itemEntity);
+            while (iterator.hasNext()) {
+                ItemStack itemstack = (ItemStack) iterator.next();
+                ItemEntity entityitem = new ItemEntity(worldserver, (double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ(), itemstack);
+
+                // CraftBukkit start - handle EntityDropItemEvent
+                org.bukkit.event.entity.EntityDropItemEvent event = new org.bukkit.event.entity.EntityDropItemEvent(this.getBukkitEntity(), (org.bukkit.entity.Item) entityitem.getBukkitEntity());
+                org.bukkit.Bukkit.getPluginManager().callEvent(event);
+                if (event.isCancelled()) {
+                    continue;
+                }
+                // CraftBukkit end
+                entityitem.setDefaultPickUpDelay();
+                worldserver.addFreshEntity(entityitem);
             }
 
             this.playSound(SoundEvents.SNIFFER_DROP_SEED, 1.0F, 1.0F);
@@ -286,36 +290,37 @@
     }
 
     private Sniffer emitDiggingParticles(AnimationState diggingAnimationState) {
-        boolean bl = diggingAnimationState.getAccumulatedTime() > 1700L && diggingAnimationState.getAccumulatedTime() < 6000L;
-        if (bl) {
-            BlockPos blockPos = this.getHeadBlock();
-            BlockState blockState = this.level().getBlockState(blockPos.below());
-            if (blockState.getRenderShape() != RenderShape.INVISIBLE) {
-                for (int i = 0; i < 30; i++) {
-                    Vec3 vec3 = Vec3.atCenterOf(blockPos).add(0.0, -0.65F, 0.0);
-                    this.level().addParticle(new BlockParticleOption(ParticleTypes.BLOCK, blockState), vec3.x, vec3.y, vec3.z, 0.0, 0.0, 0.0);
+        boolean flag = diggingAnimationState.getAccumulatedTime() > 1700L && diggingAnimationState.getAccumulatedTime() < 6000L;
+
+        if (flag) {
+            BlockPos blockposition = this.getHeadBlock();
+            BlockState iblockdata = this.level().getBlockState(blockposition.below());
+
+            if (iblockdata.getRenderShape() != RenderShape.INVISIBLE) {
+                for (int i = 0; i < 30; ++i) {
+                    Vec3 vec3d = Vec3.atCenterOf(blockposition).add(0.0D, -0.6499999761581421D, 0.0D);
+
+                    this.level().addParticle(new BlockParticleOption(ParticleTypes.BLOCK, iblockdata), vec3d.x, vec3d.y, vec3d.z, 0.0D, 0.0D, 0.0D);
                 }
 
                 if (this.tickCount % 10 == 0) {
-                    this.level()
-                        .playLocalSound(
-                            this.getX(), this.getY(), this.getZ(), blockState.getSoundType().getHitSound(), this.getSoundSource(), 0.5F, 0.5F, false
-                        );
+                    this.level().playLocalSound(this.getX(), this.getY(), this.getZ(), iblockdata.getSoundType().getHitSound(), this.getSoundSource(), 0.5F, 0.5F, false);
                 }
             }
         }
 
         if (this.tickCount % 10 == 0) {
-            this.level().gameEvent(GameEvent.ENTITY_ACTION, this.getHeadBlock(), GameEvent.Context.of(this));
+            this.level().gameEvent((Holder) GameEvent.ENTITY_ACTION, this.getHeadBlock(), GameEvent.Context.of((Entity) this));
         }
 
         return this;
     }
 
     public Sniffer storeExploredPosition(BlockPos pos) {
-        List<GlobalPos> list = this.getExploredPositions().limit(20L).collect(Collectors.toList());
+        List<GlobalPos> list = (List) this.getExploredPositions().limit(20L).collect(Collectors.toList());
+
         list.add(0, GlobalPos.of(this.level().dimension(), pos));
-        this.getBrain().setMemory(MemoryModuleType.SNIFFER_EXPLORED_POSITIONS, list);
+        this.getBrain().setMemory(MemoryModuleType.SNIFFER_EXPLORED_POSITIONS, list); // CraftBukkit - decompile error
         return this;
     }
 
@@ -326,23 +331,33 @@
     @Override
     public void jumpFromGround() {
         super.jumpFromGround();
-        double d = this.moveControl.getSpeedModifier();
-        if (d > 0.0) {
-            double e = this.getDeltaMovement().horizontalDistanceSqr();
-            if (e < 0.01) {
-                this.moveRelative(0.1F, new Vec3(0.0, 0.0, 1.0));
+        double d0 = this.moveControl.getSpeedModifier();
+
+        if (d0 > 0.0D) {
+            double d1 = this.getDeltaMovement().horizontalDistanceSqr();
+
+            if (d1 < 0.01D) {
+                this.moveRelative(0.1F, new Vec3(0.0D, 0.0D, 1.0D));
             }
         }
+
     }
 
     @Override
     public void spawnChildFromBreeding(ServerLevel world, Animal other) {
-        ItemStack itemStack = new ItemStack(Items.SNIFFER_EGG);
-        ItemEntity itemEntity = new ItemEntity(world, this.position().x(), this.position().y(), this.position().z(), itemStack);
-        itemEntity.setDefaultPickUpDelay();
-        this.finalizeSpawnChildFromBreeding(world, other, null);
+        // Paper start - Add EntityFertilizeEggEvent event
+        final io.papermc.paper.event.entity.EntityFertilizeEggEvent result = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityFertilizeEggEvent(this, other);
+        if (result.isCancelled()) return;
+        // Paper end - Add EntityFertilizeEggEvent event
+
+        ItemStack itemstack = new ItemStack(Items.SNIFFER_EGG);
+        ItemEntity entityitem = new ItemEntity(world, this.position().x(), this.position().y(), this.position().z(), itemstack);
+
+        entityitem.setDefaultPickUpDelay();
+        this.finalizeSpawnChildFromBreeding(world, other, (AgeableMob) null, result.getExperience()); // Paper - Add EntityFertilizeEggEvent event
+        if (this.spawnAtLocation(entityitem) != null) { // Paper - Call EntityDropItemEvent
         this.playSound(SoundEvents.SNIFFER_EGG_PLOP, 1.0F, (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 0.5F);
-        world.addFreshEntity(itemEntity);
+        } // Paper - Call EntityDropItemEvent
     }
 
     @Override
@@ -353,11 +368,11 @@
 
     @Override
     public void tick() {
-        switch (this.getState()) {
-            case SEARCHING:
+        switch (this.getState().ordinal()) {
+            case 4:
                 this.playSearchingSound();
                 break;
-            case DIGGING:
+            case 5:
                 this.emitDiggingParticles(this.diggingAnimationState).dropSeed();
         }
 
@@ -366,20 +381,22 @@
 
     @Override
     public InteractionResult mobInteract(Player player, InteractionHand hand) {
-        ItemStack itemStack = player.getItemInHand(hand);
-        boolean bl = this.isFood(itemStack);
-        InteractionResult interactionResult = super.mobInteract(player, hand);
-        if (interactionResult.consumesAction() && bl) {
-            this.level().playSound(null, this, this.getEatingSound(itemStack), SoundSource.NEUTRAL, 1.0F, Mth.randomBetween(this.level().random, 0.8F, 1.2F));
+        ItemStack itemstack = player.getItemInHand(hand);
+        boolean flag = this.isFood(itemstack);
+        InteractionResult enuminteractionresult = super.mobInteract(player, hand);
+
+        if (enuminteractionresult.consumesAction() && flag) {
+            this.level().playSound((Player) null, (Entity) this, this.getEatingSound(itemstack), SoundSource.NEUTRAL, 1.0F, Mth.randomBetween(this.level().random, 0.8F, 1.2F));
         }
 
-        return interactionResult;
+        return enuminteractionresult;
     }
 
     private void playSearchingSound() {
         if (this.level().isClientSide() && this.tickCount % 20 == 0) {
             this.level().playLocalSound(this.getX(), this.getY(), this.getZ(), SoundEvents.SNIFFER_SEARCHING, this.getSoundSource(), 1.0F, 1.0F, false);
         }
+
     }
 
     @Override
@@ -419,7 +436,7 @@
 
     @Override
     public AgeableMob getBreedOffspring(ServerLevel world, AgeableMob entity) {
-        return EntityType.SNIFFER.create(world);
+        return (AgeableMob) EntityType.SNIFFER.create(world);
     }
 
     @Override
@@ -428,13 +445,14 @@
             return false;
         } else {
             Set<Sniffer.State> set = Set.of(Sniffer.State.IDLING, Sniffer.State.SCENTING, Sniffer.State.FEELING_HAPPY);
+
             return set.contains(this.getState()) && set.contains(sniffer.getState()) && super.canMate(other);
         }
     }
 
     @Override
     public AABB getBoundingBoxForCulling() {
-        return super.getBoundingBoxForCulling().inflate(0.6F);
+        return super.getBoundingBoxForCulling().inflate(0.6000000238418579D);
     }
 
     @Override
@@ -449,7 +467,7 @@
 
     @Override
     public Brain<Sniffer> getBrain() {
-        return (Brain<Sniffer>)super.getBrain();
+        return (Brain<Sniffer>) super.getBrain(); // CraftBukkit - decompile error
     }
 
     @Override
@@ -460,7 +478,7 @@
     @Override
     protected void customServerAiStep() {
         this.level().getProfiler().push("snifferBrain");
-        this.getBrain().tick((ServerLevel)this.level(), this);
+        this.getBrain().tick((ServerLevel) this.level(), this);
         this.level().getProfiler().popPush("snifferActivityUpdate");
         SnifferAi.updateActivity(this);
         this.level().getProfiler().pop();
@@ -474,20 +492,15 @@
     }
 
     public static enum State {
-        IDLING(0),
-        FEELING_HAPPY(1),
-        SCENTING(2),
-        SNIFFING(3),
-        SEARCHING(4),
-        DIGGING(5),
-        RISING(6);
+
+        IDLING(0), FEELING_HAPPY(1), SCENTING(2), SNIFFING(3), SEARCHING(4), DIGGING(5), RISING(6);
 
         public static final IntFunction<Sniffer.State> BY_ID = ByIdMap.continuous(Sniffer.State::id, values(), ByIdMap.OutOfBoundsStrategy.ZERO);
-        public static final StreamCodec<ByteBuf, Sniffer.State> STREAM_CODEC = ByteBufCodecs.idMapper(BY_ID, Sniffer.State::id);
+        public static final StreamCodec<ByteBuf, Sniffer.State> STREAM_CODEC = ByteBufCodecs.idMapper(Sniffer.State.BY_ID, Sniffer.State::id);
         private final int id;
 
-        private State(final int index) {
-            this.id = index;
+        private State(final int i) {
+            this.id = i;
         }
 
         public int id() {
