Paper/Spigot-Server-Patches/0484-Workaround-for-Client-Lag-Spikes-MC-162253.patch
Jake Potrebic 69c09cdb00
Updated Upstream (CraftBukkit) (#5607)
Upstream has released updates that appear to apply and compile correctly.
This update has not been tested by PaperMC and as with ANY update, please do your own testing

CraftBukkit Changes:
e1a6197e SPIGOT-5565: Animals still spawn from chunk gen when spawn-animals=false
2021-05-11 00:22:11 +01:00

120 lines
5.9 KiB
Diff

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).
diff --git a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
index b7bf5f7cf7f48be5d7c694de3deddab7a2d889d5..1d7891005c7e4ff0c7b817cda987b3bc263f7010 100644
--- a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
@@ -85,6 +85,7 @@ import net.minecraft.world.level.World;
import net.minecraft.world.level.chunk.Chunk;
import net.minecraft.world.level.chunk.ChunkConverter;
import net.minecraft.world.level.chunk.ChunkGenerator;
+import net.minecraft.world.level.chunk.ChunkSection;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.IChunkAccess;
import net.minecraft.world.level.chunk.ILightAccess;
@@ -2063,9 +2064,68 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
public final void sendChunk(EntityPlayer entityplayer, Packet<?>[] apacket, Chunk chunk) { this.a(entityplayer, apacket, chunk); } // Paper - OBFHELPER
private void a(EntityPlayer entityplayer, Packet<?>[] apacket, Chunk chunk) {
if (apacket[0] == null) {
+ // Paper start - add 8 for light fix workaround
+ if (apacket.length != 10) { // in case Plugins call sendChunk, resize
+ apacket = new Packet[10];
+ }
+ // Paper end
apacket[0] = new PacketPlayOutMapChunk(chunk, 65535, chunk.world.chunkPacketBlockController.shouldModify(entityplayer, chunk, 65535)); // Paper - Anti-Xray - Bypass
apacket[1] = new PacketPlayOutLightUpdate(chunk.getPos(), this.lightEngine, 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 Chunk neighbor = chunk.getRelativeNeighbourIfLoaded(x, z);
+ final int updateLightMask = lightMask & ~getCeilingLightMask(neighbor);
+
+ if (updateLightMask == 0) {
+ continue;
+ }
+
+ apacket[i] = new PacketPlayOutLightUpdate(new ChunkCoordIntPair(chunk.getPos().x + x, chunk.getPos().z + z), lightEngine, updateLightMask, 0, true);
+ }
+ }
+ }
+
+ final int viewDistance = playerViewDistanceBroadcastMap.getLastViewDistance(entityplayer);
+ final long lastPosition = playerViewDistanceBroadcastMap.getLastCoordinate(entityplayer);
+
+ 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 = apacket[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;
+ }
+ entityplayer.playerConnection.sendPacket(packet);
+ }
}
+ // Paper end - Fix MC-162253
entityplayer.a(chunk.getPos(), apacket[0], apacket[1]);
PacketDebug.a(this.world, chunk.getPos());
diff --git a/src/main/java/net/minecraft/world/level/chunk/Chunk.java b/src/main/java/net/minecraft/world/level/chunk/Chunk.java
index 90e895e9eac6158a28de4a30589bf7538e5ec9cc..34a9f7b2f998f77b1279516cd09397ab6c2ac1cc 100644
--- a/src/main/java/net/minecraft/world/level/chunk/Chunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/Chunk.java
@@ -280,7 +280,7 @@ public class Chunk implements IChunkAccess {
// 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 EntityPlayer)) {
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/ChunkSection.java
index 973aa060d6964c7d470bc7aff89b879daf1df153..8fe060c3b2ad0873f96218eb7d02cdff3279224e 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkSection.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkSection.java
@@ -107,6 +107,7 @@ public class ChunkSection {
return this.nonEmptyBlockCount == 0;
}
+ public static boolean isEmpty(@Nullable ChunkSection chunksection) { return a(chunksection) ; } // Paper - OBFHELPER
public static boolean a(@Nullable ChunkSection chunksection) {
return chunksection == Chunk.a || chunksection.c();
}