mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-06 02:42:14 +01:00
138 lines
6.9 KiB
Diff
138 lines
6.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/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||
|
index 738f1183ce663db7c67d2f0289823390a7f06a0e..8070acde38c47c364c1d26ec3b7d65da037554a5 100644
|
||
|
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||
|
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||
|
@@ -85,6 +85,7 @@ import net.minecraft.world.level.chunk.ChunkGenerator;
|
||
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||
|
import net.minecraft.world.level.chunk.ImposterProtoChunk;
|
||
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||
|
+import net.minecraft.world.level.chunk.LevelChunkSection;
|
||
|
import net.minecraft.world.level.chunk.LightChunkGetter;
|
||
|
import net.minecraft.world.level.chunk.ProtoChunk;
|
||
|
import net.minecraft.world.level.chunk.UpgradeData;
|
||
|
@@ -2018,7 +2019,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||
|
|
||
|
// Paper start
|
||
|
private static int getLightMask(final LevelChunk chunk) {
|
||
|
- final ChunkSection[] chunkSections = chunk.getSections();
|
||
|
+ final LevelChunkSection[] chunkSections = chunk.getSections();
|
||
|
int mask = 0;
|
||
|
|
||
|
for (int i = 0; i < chunkSections.length; ++i) {
|
||
|
@@ -2029,7 +2030,7 @@ Lightmasks have 18 bits, from the -1 (void) section until the 17th (air) section
|
||
|
Sections go from 0..16. Now whenever a section is not empty, it can potentially change lighting for the section itself, the section below and the section above, hence the bitmask 111b, which is 7d.
|
||
|
|
||
|
*/
|
||
|
- mask |= (ChunkSection.isEmpty(chunkSections[i]) ? 0 : 7) << i;
|
||
|
+ mask |= (LevelChunkSection.isEmpty(chunkSections[i]) ? 0 : 7) << i;
|
||
|
}
|
||
|
|
||
|
return mask;
|
||
|
@@ -2060,9 +2061,68 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
|
||
|
public final void sendChunk(ServerPlayer entityplayer, Packet<?>[] apacket, LevelChunk chunk) { this.playerLoadedChunk(entityplayer, apacket, chunk); } // Paper - OBFHELPER
|
||
|
private void playerLoadedChunk(ServerPlayer player, Packet<?>[] packets, LevelChunk chunk) {
|
||
|
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, 65535, chunk.world.chunkPacketBlockController.shouldModify(player, chunk, 65535)); // Paper - Anti-Xray - Bypass
|
||
|
packets[1] = new ClientboundLightUpdatePacket(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 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, updateLightMask, 0, true);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ 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 dbea2a4370ccf24a5084cdabeecbc81f206e910a..9b76dc15417eef420804e5184a6d684e1137a746 100644
|
||
|
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||
|
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
||
|
@@ -279,7 +279,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 ServerPlayer)) {
|
||
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||
|
index 5e7f6000df129100ef306703f325af9f60da8ae6..cc7d930c1fcd7157efc181d766e1639669f6eab9 100644
|
||
|
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||
|
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||
|
@@ -107,6 +107,7 @@ public class LevelChunkSection {
|
||
|
return this.nonEmptyBlockCount == 0;
|
||
|
}
|
||
|
|
||
|
+ public static boolean isEmpty(@Nullable LevelChunkSection chunksection) { return isEmpty(chunksection) ; } // Paper - OBFHELPER
|
||
|
public static boolean isEmpty(@Nullable LevelChunkSection section) {
|
||
|
return section == LevelChunk.EMPTY_SECTION || section.isEmpty();
|
||
|
}
|