From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MeFisto94 <MeFisto94@users.noreply.github.com>
Date: Tue, 12 May 2020 23:02:43 +0200
Subject: [PATCH] Workaround for Client Lag Spikes (MC-162253)

When crossing certain chunk boundaries, the client needlessly
calculates light maps for chunk neighbours. In some specific map
configurations, these calculations cause a 500ms+ freeze on the Client.

This patch basically serves as a workaround by sending light maps
to the client, so that it doesn't attempt to calculate them.
This mitigates the frametime impact to a minimum (but it's still there).

1.17 UPDATE NOTE: More or less untested, mapped version of the patch: https://paste.gg/p/anonymous/594123c7ce7d4d398d8834af6ba386d1

diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index d8f99f7f5ca0e1dbbb9b760af3a4b4f9c52ef6c7..f700ac973ebc3037a5a44eac3c9d505b98adce41 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -1906,9 +1906,68 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
 
     public void playerLoadedChunk(ServerPlayer player, Packet<?>[] packets, LevelChunk chunk) { // Paper - private -> public
         if (packets[0] == null) {
+            // Paper start - add 8 for light fix workaround
+            if (packets.length != 10) { // in case Plugins call sendChunk, resize
+                packets = new Packet[10];
+            }
+            // Paper end
             packets[0] = new ClientboundLevelChunkPacket(chunk);
             packets[1] = new ClientboundLightUpdatePacket(chunk.getPos(), this.lightEngine, (BitSet) null, (BitSet) null, true);
+
+            // Paper start - Fix MC-162253
+            final int lightMask = getLightMask(chunk);
+            int i = 1;
+            for (int x = -1; x <= 1; x++) {
+                for (int z = -1; z <= 1; z++) {
+                    if (x == 0 && z == 0) {
+                        continue;
+                    }
+
+                    ++i;
+
+                    if (!chunk.isNeighbourLoaded(x, z)) {
+                        continue;
+                    }
+
+                    final LevelChunk neighbor = chunk.getRelativeNeighbourIfLoaded(x, z);
+                    final int updateLightMask = lightMask & ~getCeilingLightMask(neighbor);
+
+                    if (updateLightMask == 0) {
+                        continue;
+                    }
+
+                    packets[i] = new ClientboundLightUpdatePacket(new ChunkPos(chunk.getPos().x + x, chunk.getPos().z + z), lightEngine, null, null, updateLightMask, 0, true); // TODO: This line needs updating
+                }
+            }
+        }
+
+        final int viewDistance = playerViewDistanceBroadcastMap.getLastViewDistance(player);
+        final long lastPosition = playerViewDistanceBroadcastMap.getLastCoordinate(player);
+
+        int j = 1;
+        for (int x = -1; x <= 1; x++) {
+            for (int z = -1; z <= 1; z++) {
+                if (x == 0 && z == 0) {
+                    continue;
+                }
+
+                ++j;
+
+                Packet<?> packet = packets[j];
+                if (packet == null) {
+                    continue;
+                }
+
+                final int distX = Math.abs(MCUtil.getCoordinateX(lastPosition) - (chunk.getPos().x + x));
+                final int distZ = Math.abs(MCUtil.getCoordinateZ(lastPosition) - (chunk.getPos().z + z));
+
+                if (Math.max(distX, distZ) > viewDistance) {
+                    continue;
+                }
+                player.connection.send(packet);
+            }
         }
+        // Paper end - Fix MC-162253
 
         player.trackChunk(chunk.getPos(), packets[0], packets[1]);
         DebugPackets.sendPoiPacketsForChunk(this.level, chunk.getPos());
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index a63dc77db41dab79f03ef7384da55c1cdeca5d98..7cced5d06f296fcdc1209a43e7b3d1d9b47c0b26 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -262,7 +262,7 @@ public class LevelChunk implements ChunkAccess {
 
                     // broadcast
                     Object[] backingSet = inRange.getBackingSet();
-                    Packet[] chunkPackets = new Packet[2];
+                    Packet[] chunkPackets = new Packet[10];
                     for (int index = 0, len = backingSet.length; index < len; ++index) {
                         Object temp = backingSet[index];
                         if (!(temp instanceof net.minecraft.server.level.ServerPlayer)) {
