From c184de4050e7c404fc7ea7f96e19e9ee360b37c9 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Sat, 12 Dec 2020 23:53:40 +0000
Subject: [PATCH] Limit auto recipe packets

---
 .../Limit-recipe-packets.patch                | 84 +++++++++++++++++++
 1 file changed, 84 insertions(+)
 create mode 100644 Spigot-Server-Patches/Limit-recipe-packets.patch

diff --git a/Spigot-Server-Patches/Limit-recipe-packets.patch b/Spigot-Server-Patches/Limit-recipe-packets.patch
new file mode 100644
index 0000000000..fb48547777
--- /dev/null
+++ b/Spigot-Server-Patches/Limit-recipe-packets.patch
@@ -0,0 +1,84 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Shane Freeder <theboyetronic@gmail.com>
+Date: Sat, 12 Dec 2020 23:45:28 +0000
+Subject: [PATCH] Limit recipe packets
+
+
+diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
++++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
+@@ -0,0 +0,0 @@ public class PaperConfig {
+         tabSpamLimit = getInt("settings.spam-limiter.tab-spam-limit", tabSpamLimit);
+     }
+ 
++    public static int autoRecipeIncrement = 1;
++    public static int autoRecipeLimit = 20;
++    private static void autoRecipieLimiters() {
++        autoRecipeIncrement = getInt("settings.spam-limiter.recipe-spam-increment", autoRecipeIncrement);
++        autoRecipeLimit = getInt("settings.spam-limiter.recipe-spam-limit", autoRecipeLimit);
++    }
++
+     public static boolean velocitySupport;
+     public static boolean velocityOnlineMode;
+     public static byte[] velocitySecretKey;
+diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/net/minecraft/server/PlayerConnection.java
++++ b/src/main/java/net/minecraft/server/PlayerConnection.java
+@@ -0,0 +0,0 @@
+ package net.minecraft.server;
+ 
++import com.destroystokyo.paper.PaperConfig;
+ import com.google.common.collect.Lists;
+ import com.google.common.primitives.Doubles;
+ import com.google.common.primitives.Floats;
+@@ -0,0 +0,0 @@ import java.util.function.Consumer;
+ import java.util.stream.Collectors;
+ import java.util.stream.Stream;
+ import javax.annotation.Nullable;
+-import org.apache.commons.lang3.StringEscapeUtils;
++
+ import org.apache.commons.lang3.StringUtils;
+ import org.apache.logging.log4j.LogManager;
+ import org.apache.logging.log4j.Logger;
+@@ -0,0 +0,0 @@ import org.apache.logging.log4j.Logger;
+ // CraftBukkit start
+ import java.util.concurrent.ExecutionException;
+ import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
++
++import org.bukkit.Bukkit;
+ import org.bukkit.Location;
+ import org.bukkit.craftbukkit.entity.CraftPlayer;
+ import org.bukkit.craftbukkit.event.CraftEventFactory;
+@@ -0,0 +0,0 @@ public class PlayerConnection implements PacketListenerPlayIn {
+     private volatile int chatThrottle;
+     private static final AtomicIntegerFieldUpdater chatSpamField = AtomicIntegerFieldUpdater.newUpdater(PlayerConnection.class, "chatThrottle");
+     private final java.util.concurrent.atomic.AtomicInteger tabSpamLimiter = new java.util.concurrent.atomic.AtomicInteger(); // Paper - configurable tab spam limits
++    private final java.util.concurrent.atomic.AtomicInteger recipeSpamPackets =  new java.util.concurrent.atomic.AtomicInteger(); // Paper - auto recipe limit
+     // CraftBukkit end
+     private int j;
+     private final Int2ShortMap k = new Int2ShortOpenHashMap();
+@@ -0,0 +0,0 @@ public class PlayerConnection implements PacketListenerPlayIn {
+         // CraftBukkit start
+         for (int spam; (spam = this.chatThrottle) > 0 && !chatSpamField.compareAndSet(this, spam, spam - 1); ) ;
+         if (tabSpamLimiter.get() > 0) tabSpamLimiter.getAndDecrement(); // Paper - split to seperate variable
++        if (recipeSpamPackets.get() > 0) recipeSpamPackets.getAndDecrement(); // Paper
+         /* Use thread-safe field access instead
+         if (this.chatThrottle > 0) {
+             --this.chatThrottle;
+@@ -0,0 +0,0 @@ public class PlayerConnection implements PacketListenerPlayIn {
+ 
+     @Override
+     public void a(PacketPlayInAutoRecipe packetplayinautorecipe) {
++        // Paper start
++        if (!Bukkit.isPrimaryThread()) {
++            if (recipeSpamPackets.addAndGet(PaperConfig.autoRecipeIncrement) > PaperConfig.autoRecipeLimit) {
++                minecraftServer.scheduleOnMain(() -> this.disconnect(new ChatMessage("disconnect.spam", new Object[0]))); // Paper
++                return;
++            }
++        }
++        // Paper end
+         PlayerConnectionUtils.ensureMainThread(packetplayinautorecipe, this, this.player.getWorldServer());
+         this.player.resetIdleTimer();
+         if (!this.player.isSpectator() && this.player.activeContainer.windowId == packetplayinautorecipe.b() && this.player.activeContainer.c(this.player) && this.player.activeContainer instanceof ContainerRecipeBook) {