From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MeFisto94 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: Line sending the light update packet needs updating, rest seems to be mostly fine 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)) {