--- a/net/minecraft/stats/ServerRecipeBook.java
+++ b/net/minecraft/stats/ServerRecipeBook.java
@@ -29,7 +_,7 @@
     private static final Logger LOGGER = LogUtils.getLogger();
     private final ServerRecipeBook.DisplayResolver displayResolver;
     @VisibleForTesting
-    protected final Set<ResourceKey<Recipe<?>>> known = Sets.newIdentityHashSet();
+    public final Set<ResourceKey<Recipe<?>>> known = Sets.newIdentityHashSet();
     @VisibleForTesting
     protected final Set<ResourceKey<Recipe<?>>> highlight = Sets.newIdentityHashSet();
 
@@ -64,17 +_,21 @@
         for (RecipeHolder<?> recipeHolder : recipes) {
             ResourceKey<Recipe<?>> resourceKey = recipeHolder.id();
             if (!this.known.contains(resourceKey) && !recipeHolder.value().isSpecial()) {
+                // Paper start - PlayerRecipeDiscoverEvent event
+                final org.bukkit.event.player.PlayerRecipeDiscoverEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerRecipeListUpdateEvent(player, recipeHolder);
+                if (event.isCancelled()) continue;
+                // Paper end - PlayerRecipeDiscoverEvent event
                 this.add(resourceKey);
                 this.addHighlight(resourceKey);
                 this.displayResolver
                     .displaysForRecipe(
-                        resourceKey, entry -> list.add(new ClientboundRecipeBookAddPacket.Entry(entry, recipeHolder.value().showNotification(), true))
+                        resourceKey, entry -> list.add(new ClientboundRecipeBookAddPacket.Entry(entry, event.shouldShowNotification(), true)) // Paper - set notification from the event
                     );
                 CriteriaTriggers.RECIPE_UNLOCKED.trigger(player, recipeHolder);
             }
         }
 
-        if (!list.isEmpty()) {
+        if (!list.isEmpty() && player.connection != null) { // SPIGOT-4478 during PlayerLoginEvent
             player.connection.send(new ClientboundRecipeBookAddPacket(list, false));
         }
 
@@ -92,7 +_,7 @@
             }
         }
 
-        if (!list.isEmpty()) {
+        if (!list.isEmpty() && player.connection != null) { // SPIGOT-4478 during PlayerLoginEvent
             player.connection.send(new ClientboundRecipeBookRemovePacket(list));
         }
 
