mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-03 05:26:50 +01:00
0ea3083817
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 Bukkit Changes: 1e843b72 #510: Add NamespacedKey#fromString() to fetch from user input a4d18241 #581: Add methods to modify despawn delay for wandering villagers CraftBukkit Changes: 0cd8f19f #802: Add methods to modify despawn delay for wandering villagers d5c5d998 SPIGOT-6362: ConcurrentModificationException: null --> Server Crash 8c7d69fe SPIGOT-5228: Entities that are removed during chunk unloads are not properly removed from the chunk.
155 lines
7.1 KiB
Diff
155 lines
7.1 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/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
|
|
index 0347dca5d2e40ba078d3f256e17f69ee7f0265cc..3bcd63a754538ccfc5965207a8fc79faa31925c0 100644
|
|
--- a/src/main/java/net/minecraft/server/Chunk.java
|
|
+++ b/src/main/java/net/minecraft/server/Chunk.java
|
|
@@ -234,7 +234,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/server/ChunkSection.java b/src/main/java/net/minecraft/server/ChunkSection.java
|
|
index 39572cdce691a459cb9df0cc064fbf7bde83a99e..e52df8096e399c84ff8a2637fdd65ea57d9001d0 100644
|
|
--- a/src/main/java/net/minecraft/server/ChunkSection.java
|
|
+++ b/src/main/java/net/minecraft/server/ChunkSection.java
|
|
@@ -100,6 +100,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();
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
|
index 1685d6f9f497455636dbcef057db48f9d4039be4..e38c9a8f4bf017db9f296bffcd029f9603ee82f6 100644
|
|
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
|
@@ -1959,12 +1959,112 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
|
|
|
|
}
|
|
|
|
+ // Paper start
|
|
+ private static int getLightMask(final Chunk chunk) {
|
|
+ final ChunkSection[] chunkSections = chunk.getSections();
|
|
+ int mask = 0;
|
|
+
|
|
+ for (int i = 0; i < chunkSections.length; ++i) {
|
|
+ /*
|
|
+
|
|
+
|
|
+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;
|
|
+ }
|
|
+
|
|
+ return mask;
|
|
+ }
|
|
+
|
|
+ private static int getCeilingLightMask(final Chunk chunk) {
|
|
+ int mask = getLightMask(chunk);
|
|
+
|
|
+ /*
|
|
+ It is similar to get highest bit, it would turn an 001010 into an 001111 so basically the highest bit and all below.
|
|
+ We then invert this, so we'd have 110000 and compare that to the "main" chunk.
|
|
+ This is because the bug only appears when the current chunks lightmaps are higher than those of the neighbors, thus we can omit sending neighbors which are lower than the current chunks lights.
|
|
+
|
|
+ so TLDR is that getCeilingLightMask returns a light mask with all bits set below the highest affected section. We could also count the number of leading zeros and invert them, somehow.
|
|
+ @TODO: Implement Leafs suggestion
|
|
+ either use Integer#numberOfLeadingZeros or document what this bithack is supposed to be doing then
|
|
+ */
|
|
+ mask |= mask >> 1;
|
|
+ mask |= mask >> 2;
|
|
+ mask |= mask >> 4;
|
|
+ mask |= mask >> 8;
|
|
+ mask |= mask >> 16;
|
|
+
|
|
+ return mask;
|
|
+ }
|
|
+ // Paper end
|
|
+
|
|
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());
|