--- a/net/minecraft/world/level/block/SnifferEggBlock.java
+++ b/net/minecraft/world/level/block/SnifferEggBlock.java
@@ -61,12 +_,31 @@
         return this.getHatchLevel(state) == 2;
     }
 
+    // Paper start - Call BlockFadeEvent
+    private void rescheduleTick(ServerLevel level, BlockPos pos) {
+        int baseDelay = hatchBoost(level, pos) ? level.paperConfig().entities.sniffer.boostedHatchTime.or(BOOSTED_HATCH_TIME_TICKS) : level.paperConfig().entities.sniffer.hatchTime.or(REGULAR_HATCH_TIME_TICKS); // Paper - Configure sniffer egg hatch time
+        level.scheduleTick(pos, this, (baseDelay / 3) + level.random.nextInt(RANDOM_HATCH_OFFSET_TICKS));
+        // reschedule to avoid being stuck here and behave like the other calls (see #onPlace)
+    }
+    // Paper end - Call BlockFadeEvent
+
     @Override
     public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
         if (!this.isReadyToHatch(state)) {
+            // Paper start
+            if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, state.setValue(HATCH, this.getHatchLevel(state) + 1), 2)) {
+                this.rescheduleTick(level, pos);
+                return;
+            }
+            // Paper end
             level.playSound(null, pos, SoundEvents.SNIFFER_EGG_CRACK, SoundSource.BLOCKS, 0.7F, 0.9F + random.nextFloat() * 0.2F);
-            level.setBlock(pos, state.setValue(HATCH, this.getHatchLevel(state) + 1), 2);
         } else {
+            // Paper start - Call BlockFadeEvent
+            if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, state.getFluidState().createLegacyBlock()).isCancelled()) {
+                this.rescheduleTick(level, pos);
+                return;
+            }
+            // Paper end - Call BlockFadeEvent
             level.playSound(null, pos, SoundEvents.SNIFFER_EGG_HATCH, SoundSource.BLOCKS, 0.7F, 0.9F + random.nextFloat() * 0.2F);
             level.destroyBlock(pos, false);
             Sniffer sniffer = EntityType.SNIFFER.create(level, EntitySpawnReason.BREEDING);
@@ -74,7 +_,7 @@
                 Vec3 center = pos.getCenter();
                 sniffer.setBaby(true);
                 sniffer.snapTo(center.x(), center.y(), center.z(), Mth.wrapDegrees(level.random.nextFloat() * 360.0F), 0.0F);
-                level.addFreshEntity(sniffer);
+                level.addFreshEntity(sniffer, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EGG); // Paper - use correct spawn reason
             }
         }
     }
@@ -86,7 +_,7 @@
             level.levelEvent(3009, pos, 0);
         }
 
-        int i = flag ? 12000 : 24000;
+        int i = flag ? level.paperConfig().entities.sniffer.boostedHatchTime.or(BOOSTED_HATCH_TIME_TICKS) : level.paperConfig().entities.sniffer.hatchTime.or(REGULAR_HATCH_TIME_TICKS); // Paper
         int i1 = i / 3;
         level.gameEvent(GameEvent.BLOCK_PLACE, pos, GameEvent.Context.of(state));
         level.scheduleTick(pos, this, i1 + level.random.nextInt(300));
