From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 27 Nov 2018 21:18:06 -0500
Subject: [PATCH] Handle Large Packets disconnecting client

If a players inventory is too big to send in a single packet,
split the inventory set into multiple packets instead.

diff --git a/src/main/java/net/minecraft/server/NetworkManager.java b/src/main/java/net/minecraft/server/NetworkManager.java
index 046196d54df35ceafb8bc477e740e1dc834345d5..d4aad8a5b7dd8ee837fa7f9b70271e0554bb04e1 100644
--- a/src/main/java/net/minecraft/server/NetworkManager.java
+++ b/src/main/java/net/minecraft/server/NetworkManager.java
@@ -97,6 +97,15 @@ public class NetworkManager extends SimpleChannelInboundHandler<Packet<?>> {
     }
 
     public void exceptionCaught(ChannelHandlerContext channelhandlercontext, Throwable throwable) {
+        // Paper start
+        if (throwable instanceof io.netty.handler.codec.EncoderException && throwable.getCause() instanceof PacketEncoder.PacketTooLargeException) {
+            if (((PacketEncoder.PacketTooLargeException) throwable.getCause()).getPacket().packetTooLarge(this)) {
+                return;
+            } else {
+                throwable = throwable.getCause();
+            }
+        }
+        // Paper end
         if (throwable instanceof SkipEncodeException) {
             NetworkManager.LOGGER.debug("Skipping packet due to errors", throwable.getCause());
         } else {
diff --git a/src/main/java/net/minecraft/server/Packet.java b/src/main/java/net/minecraft/server/Packet.java
index 601d4d0fa2a0b3e90f81aed55a2d3473c66c7875..2d8e6a2f4a0c3c5d74a647d7164b0028781d3bf5 100644
--- a/src/main/java/net/minecraft/server/Packet.java
+++ b/src/main/java/net/minecraft/server/Packet.java
@@ -10,6 +10,12 @@ public interface Packet<T extends PacketListener> {
 
     void a(T t0);
 
+    // Paper start
+    default boolean packetTooLarge(NetworkManager manager) {
+        return false;
+    }
+    // Paper end
+
     default boolean a() {
         return false;
     }
diff --git a/src/main/java/net/minecraft/server/PacketEncoder.java b/src/main/java/net/minecraft/server/PacketEncoder.java
index 63c4dbd327beb7b6ab42eb44650d68accd3b0de6..b0cfef52cbb5e23beae528668e4e98cedecf603c 100644
--- a/src/main/java/net/minecraft/server/PacketEncoder.java
+++ b/src/main/java/net/minecraft/server/PacketEncoder.java
@@ -49,7 +49,31 @@ public class PacketEncoder extends MessageToByteEncoder<Packet<?>> {
                         throw throwable;
                     }
                 }
+
+                // Paper start
+                int packetLength = bytebuf.readableBytes();
+                if (packetLength > MAX_PACKET_SIZE) {
+                    throw new PacketTooLargeException(packet, packetLength);
+                }
+                // Paper end
             }
         }
     }
+
+    // Paper start
+    private static int MAX_PACKET_SIZE = 2097152;
+
+    public static class PacketTooLargeException extends RuntimeException {
+        private final Packet<?> packet;
+
+        PacketTooLargeException(Packet<?> packet, int packetLength) {
+            super("PacketTooLarge - " + packet.getClass().getSimpleName() + " is " + packetLength + ". Max is " + MAX_PACKET_SIZE);
+            this.packet = packet;
+        }
+
+        public Packet<?> getPacket() {
+            return packet;
+        }
+    }
+    // Paper end
 }
diff --git a/src/main/java/net/minecraft/server/PacketPlayOutMapChunk.java b/src/main/java/net/minecraft/server/PacketPlayOutMapChunk.java
index 1fcbbd698a7e1b9ae3e8b5fa0328b85c43019bea..a0b87f89df77ba8ac6ce3f135d4f3a34ed2b3543 100644
--- a/src/main/java/net/minecraft/server/PacketPlayOutMapChunk.java
+++ b/src/main/java/net/minecraft/server/PacketPlayOutMapChunk.java
@@ -79,7 +79,7 @@ public class PacketPlayOutMapChunk implements Packet<PacketListenerPlayOut> {
 
         int i = packetdataserializer.i();
 
-        if (i > 2097152) {
+        if (i > 2097152) { // Paper - if this changes, update PacketEncoder
             throw new RuntimeException("Chunk Packet trying to allocate too much memory on read.");
         } else {
             this.f = new byte[i];
diff --git a/src/main/java/net/minecraft/server/PacketPlayOutWindowItems.java b/src/main/java/net/minecraft/server/PacketPlayOutWindowItems.java
index f7c3655671cb75a7e78796bcddc3cfd9817e2b90..631234324d5c53015b3cef21b20bb3211e335af8 100644
--- a/src/main/java/net/minecraft/server/PacketPlayOutWindowItems.java
+++ b/src/main/java/net/minecraft/server/PacketPlayOutWindowItems.java
@@ -9,6 +9,15 @@ public class PacketPlayOutWindowItems implements Packet<PacketListenerPlayOut> {
     private int a;
     private List<ItemStack> b;
 
+    //Paper start
+    @Override
+    public boolean packetTooLarge(NetworkManager manager) {
+        for (int i = 0 ; i < this.b.size() ; i++) {
+            manager.sendPacket(new PacketPlayOutSetSlot(this.a, i, this.b.get(i)));
+        }
+        return true;
+    }
+    // Paper end
     public PacketPlayOutWindowItems() {}
 
     public PacketPlayOutWindowItems(int i, NonNullList<ItemStack> nonnulllist) {