diff --git a/Spigot-Server-Patches/0072-Optimize-isValidLocation-getType-and-getBlockData-fo.patch b/Spigot-Server-Patches/0072-Optimize-isValidLocation-getType-and-getBlockData-fo.patch index d3bc6ddde..118ea94f0 100644 --- a/Spigot-Server-Patches/0072-Optimize-isValidLocation-getType-and-getBlockData-fo.patch +++ b/Spigot-Server-Patches/0072-Optimize-isValidLocation-getType-and-getBlockData-fo.patch @@ -1,7 +1,8 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Aikar Date: Thu, 3 Mar 2016 02:07:55 -0600 -Subject: [PATCH] Optimize isValidLocation, getType and getBlockData for inling +Subject: [PATCH] Optimize isValidLocation, getType and getBlockData for + inlining Hot methods, so reduce # of instructions for the method. @@ -31,10 +32,10 @@ index 3f09c24e1cd1bba2809b70b1fa6e89773537d834..7b05bb9edcd059a134cef12cc9fea570 public BaseBlockPosition(int i, int j, int k) { this.a = i; diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index b85e21202eb8bb9446989aa1d6889eed784762a4..324cd78f8c896d300d1e74acde3db6a81dab2b0d 100644 +index b85e21202eb8bb9446989aa1d6889eed784762a4..671bcc763c78114f38d2b9b0320d7b168a756e21 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java -@@ -307,12 +307,24 @@ public class Chunk implements IChunkAccess { +@@ -307,12 +307,27 @@ public class Chunk implements IChunkAccess { return this.sections; } @@ -47,28 +48,60 @@ index b85e21202eb8bb9446989aa1d6889eed784762a4..324cd78f8c896d300d1e74acde3db6a8 - int k = blockposition.getZ(); + return this.getBlockData(blockposition.getX(), blockposition.getY(), blockposition.getZ()); + } - ++ ++ public IBlockData getType(final int x, final int y, final int z) { ++ return getBlockData(x, y, z); ++ } + public final IBlockData getBlockData(final int x, final int y, final int z) { + // Method body / logic copied from below + final int i = y >> 4; -+ if (y >= 0 && i < this.sections.length && this.sections[i] != null) { -+ // Inlined ChunkSection.getType() and DataPaletteBlock.a(int,int,int) -+ return this.sections[i].blockIds.a((y & 15) << 8 | (z & 15) << 4 | x & 15); ++ if (y < 0 || i >= this.sections.length || this.sections[i] == null || this.sections[i].nonEmptyBlockCount == 0) { ++ return Blocks.AIR.getBlockData(); + } -+ return Blocks.AIR.getBlockData(); ++ // Inlined ChunkSection.getType() and DataPaletteBlock.a(int,int,int) ++ return this.sections[i].blockIds.a((y & 15) << 8 | (z & 15) << 4 | x & 15); + } -+ + + public IBlockData getBlockData_unused(int i, int j, int k) { + // Paper end if (this.world.P() == WorldType.DEBUG_ALL_BLOCK_STATES) { IBlockData iblockdata = null; +diff --git a/src/main/java/net/minecraft/server/ChunkEmpty.java b/src/main/java/net/minecraft/server/ChunkEmpty.java +index 82fdd3db6f698f8b77c8bbd1f17cb21980ecfeec..fd49438961451987bd102a85484be24b341d946b 100644 +--- a/src/main/java/net/minecraft/server/ChunkEmpty.java ++++ b/src/main/java/net/minecraft/server/ChunkEmpty.java +@@ -7,7 +7,7 @@ import javax.annotation.Nullable; + + public class ChunkEmpty extends Chunk { + +- private static final BiomeBase[] b = (BiomeBase[]) SystemUtils.a((Object) (new BiomeBase[BiomeStorage.a]), (abiomebase) -> { ++ private static final BiomeBase[] b = (BiomeBase[]) SystemUtils.a((new BiomeBase[BiomeStorage.a]), (abiomebase) -> { // Paper - decompile error + Arrays.fill(abiomebase, Biomes.PLAINS); + }); + +@@ -15,6 +15,11 @@ public class ChunkEmpty extends Chunk { + super(world, chunkcoordintpair, new BiomeStorage(ChunkEmpty.b)); + } + ++ // Paper start ++ @Override public IBlockData getType(int x, int y, int z) { ++ return Blocks.VOID_AIR.getBlockData(); ++ } ++ // Paper end + @Override + public IBlockData getType(BlockPosition blockposition) { + return Blocks.VOID_AIR.getBlockData(); diff --git a/src/main/java/net/minecraft/server/ChunkSection.java b/src/main/java/net/minecraft/server/ChunkSection.java -index 638b0e39798a3f75566fcf9ea48b81024e60b471..e056fbcb216977401fd2778fcd3ee7ed5f020214 100644 +index 638b0e39798a3f75566fcf9ea48b81024e60b471..e72d1386feb59e4a4c27466da96ffd29222bea18 100644 --- a/src/main/java/net/minecraft/server/ChunkSection.java +++ b/src/main/java/net/minecraft/server/ChunkSection.java -@@ -9,7 +9,7 @@ public class ChunkSection { - private short nonEmptyBlockCount; +@@ -6,10 +6,10 @@ public class ChunkSection { + + public static final DataPalette GLOBAL_PALETTE = new DataPaletteGlobal<>(Block.REGISTRY_ID, Blocks.AIR.getBlockData()); + private final int yPos; +- private short nonEmptyBlockCount; ++ short nonEmptyBlockCount; // Paper - package-private private short tickingBlockCount; private short e; - private final DataPaletteBlock blockIds; @@ -76,8 +109,89 @@ index 638b0e39798a3f75566fcf9ea48b81024e60b471..e056fbcb216977401fd2778fcd3ee7ed public ChunkSection(int i) { this(i, (short) 0, (short) 0, (short) 0); +@@ -23,8 +23,8 @@ public class ChunkSection { + this.blockIds = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, Block.REGISTRY_ID, GameProfileSerializer::d, GameProfileSerializer::a, Blocks.AIR.getBlockData()); + } + +- public IBlockData getType(int i, int j, int k) { +- return (IBlockData) this.blockIds.a(i, j, k); ++ public final IBlockData getType(int i, int j, int k) { // Paper ++ return this.blockIds.a(j << 8 | k << 4 | i); // Paper - inline + } + + public Fluid b(int i, int j, int k) { +diff --git a/src/main/java/net/minecraft/server/DataPaletteBlock.java b/src/main/java/net/minecraft/server/DataPaletteBlock.java +index d5f5a51872dfabdbb828b6c20d61893aed2efec7..3586fe065f21fbf1e71b602c372a690ef603f377 100644 +--- a/src/main/java/net/minecraft/server/DataPaletteBlock.java ++++ b/src/main/java/net/minecraft/server/DataPaletteBlock.java +@@ -125,7 +125,7 @@ public class DataPaletteBlock implements DataPaletteExpandable { + } + + public T a(int i, int j, int k) { +- return this.a(b(i, j, k)); ++ return this.a(j << 8 | k << 4 | i); // Paper - inline + } + + protected T a(int i) { +diff --git a/src/main/java/net/minecraft/server/IChunkAccess.java b/src/main/java/net/minecraft/server/IChunkAccess.java +index 6f25c37658e8e4b31fec2d9e8b69616f073e0b30..2de4796946e79c5fc7a36a1e26cbcad7bca6e12a 100644 +--- a/src/main/java/net/minecraft/server/IChunkAccess.java ++++ b/src/main/java/net/minecraft/server/IChunkAccess.java +@@ -13,6 +13,7 @@ import org.apache.logging.log4j.LogManager; + + public interface IChunkAccess extends IBlockAccess, IStructureAccess { + ++ IBlockData getType(final int x, final int y, final int z); // Paper + @Nullable + IBlockData setType(BlockPosition blockposition, IBlockData iblockdata, boolean flag); + +diff --git a/src/main/java/net/minecraft/server/ProtoChunk.java b/src/main/java/net/minecraft/server/ProtoChunk.java +index 39339fa27551b06a9bfd8ea67b1ec8c66726f488..51a5b9cb36c4325df8d1434dcf28d27abefdfede 100644 +--- a/src/main/java/net/minecraft/server/ProtoChunk.java ++++ b/src/main/java/net/minecraft/server/ProtoChunk.java +@@ -94,16 +94,18 @@ public class ProtoChunk implements IChunkAccess { + + @Override + public IBlockData getType(BlockPosition blockposition) { +- int i = blockposition.getY(); +- +- if (World.b(i)) { ++ return getType(blockposition.getX(), blockposition.getY(), blockposition.getZ()); ++ } ++ // Paper start ++ public IBlockData getType(final int x, final int y, final int z) { ++ if (y < 0 || y >= 256) { + return Blocks.VOID_AIR.getBlockData(); + } else { +- ChunkSection chunksection = this.getSections()[i >> 4]; +- +- return ChunkSection.a(chunksection) ? Blocks.AIR.getBlockData() : chunksection.getType(blockposition.getX() & 15, i & 15, blockposition.getZ() & 15); ++ ChunkSection chunksection = this.getSections()[y >> 4]; ++ return chunksection == Chunk.EMPTY_CHUNK_SECTION || chunksection.c() ? Blocks.AIR.getBlockData() : chunksection.getType(x & 15, y & 15, z & 15); + } + } ++ // Paper end + + @Override + public Fluid getFluid(BlockPosition blockposition) { +diff --git a/src/main/java/net/minecraft/server/ProtoChunkExtension.java b/src/main/java/net/minecraft/server/ProtoChunkExtension.java +index 01bf28dc34dd69dbcee5f470cc71ec2fbb2fcc12..b740e82622e282bdf543a84a559af69dd5b8568c 100644 +--- a/src/main/java/net/minecraft/server/ProtoChunkExtension.java ++++ b/src/main/java/net/minecraft/server/ProtoChunkExtension.java +@@ -26,6 +26,11 @@ public class ProtoChunkExtension extends ProtoChunk { + public IBlockData getType(BlockPosition blockposition) { + return this.a.getType(blockposition); + } ++ // Paper start ++ public final IBlockData getType(final int x, final int y, final int z) { ++ return this.a.getBlockData(x, y, z); ++ } ++ // Paper end + + @Override + public Fluid getFluid(BlockPosition blockposition) { diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java -index a721ad8addfd5a47608e304b372762d3ca89fa65..40a51633ed509ca7ae6131e11276f8f3cb7c03ce 100644 +index 7f1f0111373fa409e52894e59ac49d5278d0bd58..50c2c4b0dc6256d5fbc361ba9b89b4e17bef8acb 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -172,11 +172,11 @@ public abstract class World implements GeneratorAccess, AutoCloseable { diff --git a/Spigot-Server-Patches/0075-Configurable-Chunk-Inhabited-Time.patch b/Spigot-Server-Patches/0075-Configurable-Chunk-Inhabited-Time.patch index f94208b79..1f592a154 100644 --- a/Spigot-Server-Patches/0075-Configurable-Chunk-Inhabited-Time.patch +++ b/Spigot-Server-Patches/0075-Configurable-Chunk-Inhabited-Time.patch @@ -30,10 +30,10 @@ index 6ef0e1399e9ff260712db1a044068c125b1316d3..5872e6b171416686b11678ac9f65706b + } } diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index 324cd78f8c896d300d1e74acde3db6a81dab2b0d..f5298a2fa911a18a5d390666c92155dd618666c5 100644 +index 671bcc763c78114f38d2b9b0320d7b168a756e21..2c1570c89026a5dbbe76ab00c6a89919e566a5f6 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java -@@ -973,7 +973,7 @@ public class Chunk implements IChunkAccess { +@@ -976,7 +976,7 @@ public class Chunk implements IChunkAccess { @Override public long getInhabitedTime() { diff --git a/Spigot-Server-Patches/0117-Option-to-remove-corrupt-tile-entities.patch b/Spigot-Server-Patches/0117-Option-to-remove-corrupt-tile-entities.patch index a489238d8..d1ed80769 100644 --- a/Spigot-Server-Patches/0117-Option-to-remove-corrupt-tile-entities.patch +++ b/Spigot-Server-Patches/0117-Option-to-remove-corrupt-tile-entities.patch @@ -19,10 +19,10 @@ index 8cf3076f4e0d8d7e81158881c763f89ebda7e678..721eceeffc843da8b9da1ccc2d07f3bc + } } diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index f5298a2fa911a18a5d390666c92155dd618666c5..23bce1c192f6c354b7fe8858515be5f98a8fe6c3 100644 +index 2c1570c89026a5dbbe76ab00c6a89919e566a5f6..87e94693f6db07d1273854ad55e5f263f2f2239e 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java -@@ -633,6 +633,12 @@ public class Chunk implements IChunkAccess { +@@ -636,6 +636,12 @@ public class Chunk implements IChunkAccess { "Chunk coordinates: " + (this.loc.x * 16) + "," + (this.loc.z * 16)); e.printStackTrace(); ServerInternalException.reportInternalException(e); diff --git a/Spigot-Server-Patches/0255-Mark-chunk-dirty-anytime-entities-change-to-guarante.patch b/Spigot-Server-Patches/0255-Mark-chunk-dirty-anytime-entities-change-to-guarante.patch index f6d91a427..fd3744a59 100644 --- a/Spigot-Server-Patches/0255-Mark-chunk-dirty-anytime-entities-change-to-guarante.patch +++ b/Spigot-Server-Patches/0255-Mark-chunk-dirty-anytime-entities-change-to-guarante.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Mark chunk dirty anytime entities change to guarantee it diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index 23bce1c192f6c354b7fe8858515be5f98a8fe6c3..0b62004422108e126d80a879c203fab0455e1451 100644 +index 87e94693f6db07d1273854ad55e5f263f2f2239e..f0a8142b7477fde211b522e3982e614fc94e20f8 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java -@@ -515,6 +515,7 @@ public class Chunk implements IChunkAccess { +@@ -518,6 +518,7 @@ public class Chunk implements IChunkAccess { entity.chunkZ = this.loc.z; this.entities.add(entity); // Paper - per chunk entity list this.entitySlices[k].add(entity); @@ -17,7 +17,7 @@ index 23bce1c192f6c354b7fe8858515be5f98a8fe6c3..0b62004422108e126d80a879c203fab0 } @Override -@@ -542,6 +543,7 @@ public class Chunk implements IChunkAccess { +@@ -545,6 +546,7 @@ public class Chunk implements IChunkAccess { return; } entityCounts.decrement(entity.getMinecraftKeyString()); diff --git a/Spigot-Server-Patches/0256-Add-some-Debug-to-Chunk-Entity-slices.patch b/Spigot-Server-Patches/0256-Add-some-Debug-to-Chunk-Entity-slices.patch index 26646b857..0975e2af1 100644 --- a/Spigot-Server-Patches/0256-Add-some-Debug-to-Chunk-Entity-slices.patch +++ b/Spigot-Server-Patches/0256-Add-some-Debug-to-Chunk-Entity-slices.patch @@ -9,10 +9,10 @@ This should hopefully avoid duplicate entities ever being created if the entity was to end up in 2 different chunk slices diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index 0b62004422108e126d80a879c203fab0455e1451..4e7f3065694c8811d5c98bcda64ae32b220e0d7a 100644 +index f0a8142b7477fde211b522e3982e614fc94e20f8..9f369f932ca0a63bde246420cfde7949f3e78ca2 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java -@@ -506,6 +506,25 @@ public class Chunk implements IChunkAccess { +@@ -509,6 +509,25 @@ public class Chunk implements IChunkAccess { if (k >= this.entitySlices.length) { k = this.entitySlices.length - 1; } @@ -38,7 +38,7 @@ index 0b62004422108e126d80a879c203fab0455e1451..4e7f3065694c8811d5c98bcda64ae32b if (!entity.inChunk || entity.getCurrentChunk() != this) entityCounts.increment(entity.getMinecraftKeyString()); // Paper entity.inChunk = true; -@@ -515,6 +534,7 @@ public class Chunk implements IChunkAccess { +@@ -518,6 +537,7 @@ public class Chunk implements IChunkAccess { entity.chunkZ = this.loc.z; this.entities.add(entity); // Paper - per chunk entity list this.entitySlices[k].add(entity); @@ -46,7 +46,7 @@ index 0b62004422108e126d80a879c203fab0455e1451..4e7f3065694c8811d5c98bcda64ae32b this.markDirty(); // Paper } -@@ -539,6 +559,10 @@ public class Chunk implements IChunkAccess { +@@ -542,6 +562,10 @@ public class Chunk implements IChunkAccess { // Paper start if (entity.currentChunk != null && entity.currentChunk.get() == this) entity.setCurrentChunk(null); diff --git a/Spigot-Server-Patches/0261-Ignore-Dead-Entities-in-entityList-iteration.patch b/Spigot-Server-Patches/0261-Ignore-Dead-Entities-in-entityList-iteration.patch index 826dddb03..7a08644b2 100644 --- a/Spigot-Server-Patches/0261-Ignore-Dead-Entities-in-entityList-iteration.patch +++ b/Spigot-Server-Patches/0261-Ignore-Dead-Entities-in-entityList-iteration.patch @@ -23,10 +23,10 @@ index b839769ceae8932bb121a0b96fde1e7d129a1f63..5acad8e44f024d3ddf5ef4fd320460ac MutablePair> info = list.computeIfAbsent(key, k -> MutablePair.of(0, Maps.newHashMap())); ChunkCoordIntPair chunk = new ChunkCoordIntPair(e.getChunkX(), e.getChunkZ()); diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index 4e7f3065694c8811d5c98bcda64ae32b220e0d7a..5453eaae5b165a76b55a085d70081159b8e66770 100644 +index 9f369f932ca0a63bde246420cfde7949f3e78ca2..c84d90a9a0c67b5ff518ce3fbc21344c808a3cf1 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java -@@ -813,6 +813,7 @@ public class Chunk implements IChunkAccess { +@@ -816,6 +816,7 @@ public class Chunk implements IChunkAccess { while (iterator.hasNext()) { Entity entity1 = (Entity) iterator.next(); @@ -34,7 +34,7 @@ index 4e7f3065694c8811d5c98bcda64ae32b220e0d7a..5453eaae5b165a76b55a085d70081159 if (entity1.getBoundingBox().c(axisalignedbb) && entity1 != entity) { if (predicate == null || predicate.test(entity1)) { -@@ -850,6 +851,7 @@ public class Chunk implements IChunkAccess { +@@ -853,6 +854,7 @@ public class Chunk implements IChunkAccess { while (iterator.hasNext()) { T entity = (T) iterator.next(); // CraftBukkit - decompile error @@ -42,7 +42,7 @@ index 4e7f3065694c8811d5c98bcda64ae32b220e0d7a..5453eaae5b165a76b55a085d70081159 if ((entitytypes == null || entity.getEntityType() == entitytypes) && entity.getBoundingBox().c(axisalignedbb) && predicate.test(entity)) { list.add(entity); -@@ -871,6 +873,7 @@ public class Chunk implements IChunkAccess { +@@ -874,6 +876,7 @@ public class Chunk implements IChunkAccess { while (iterator.hasNext()) { T t0 = (T) iterator.next(); // CraftBukkit - decompile error diff --git a/Spigot-Server-Patches/0370-Duplicate-UUID-Resolve-Option.patch b/Spigot-Server-Patches/0370-Duplicate-UUID-Resolve-Option.patch index eba21c06a..932b7c428 100644 --- a/Spigot-Server-Patches/0370-Duplicate-UUID-Resolve-Option.patch +++ b/Spigot-Server-Patches/0370-Duplicate-UUID-Resolve-Option.patch @@ -81,10 +81,10 @@ index 4ba72275b965693f3650f9b4fb138d3320d1b88b..572679e4d1ca0d84a08a5c48542fa40d + } } diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index 5453eaae5b165a76b55a085d70081159b8e66770..4f05468590e30f4b11599d3841418c76519255e4 100644 +index c84d90a9a0c67b5ff518ce3fbc21344c808a3cf1..962f425bbb7165740e77664dc543f976ef3d9c4a 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java -@@ -495,6 +495,7 @@ public class Chunk implements IChunkAccess { +@@ -498,6 +498,7 @@ public class Chunk implements IChunkAccess { if (i != this.loc.x || j != this.loc.z) { Chunk.LOGGER.warn("Wrong location! ({}, {}) should be ({}, {}), {}", i, j, this.loc.x, this.loc.z, entity); entity.dead = true; diff --git a/Spigot-Server-Patches/0384-Anti-Xray.patch b/Spigot-Server-Patches/0384-Anti-Xray.patch index 459f84e4a..5ffe1e8ca 100644 --- a/Spigot-Server-Patches/0384-Anti-Xray.patch +++ b/Spigot-Server-Patches/0384-Anti-Xray.patch @@ -1008,10 +1008,10 @@ index 0000000000000000000000000000000000000000..2eff19f6aaa31245f80910c6fbb541e3 + } +} diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index 820033289cbeb782429b26b6bcabc3835b0101a3..b855589d978d06e9883daff97c9e702d5a9461cc 100644 +index dd3857bb6a002d8432ecbc6c6b52a39e5d55e6a6..08b3cbabc482d71862d90fcd9acd32d28f44a6e2 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java -@@ -419,7 +419,7 @@ public class Chunk implements IChunkAccess { +@@ -422,7 +422,7 @@ public class Chunk implements IChunkAccess { return null; } @@ -1043,7 +1043,7 @@ index 8e4b3e52cbc95e24b1d72aed9ec8c32b94a91561..d287ea55c550dbebbbc1d5f815296ae7 protochunk.a(biomestorage); object = protochunk; diff --git a/src/main/java/net/minecraft/server/ChunkSection.java b/src/main/java/net/minecraft/server/ChunkSection.java -index e056fbcb216977401fd2778fcd3ee7ed5f020214..eeb7eee925d31d1ed8e6bbd55888cb5ebe54afa2 100644 +index e72d1386feb59e4a4c27466da96ffd29222bea18..c180d44bed91c86838d3be8c19be954b4412534e 100644 --- a/src/main/java/net/minecraft/server/ChunkSection.java +++ b/src/main/java/net/minecraft/server/ChunkSection.java @@ -1,5 +1,6 @@ @@ -1079,7 +1079,7 @@ index e056fbcb216977401fd2778fcd3ee7ed5f020214..eeb7eee925d31d1ed8e6bbd55888cb5e + this.blockIds = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, Block.REGISTRY_ID, GameProfileSerializer::d, GameProfileSerializer::a, Blocks.AIR.getBlockData(), world == null ? null : world.chunkPacketBlockController.getPredefinedBlockData(world, chunk, this, initializeBlocks), initializeBlocks); // Paper - Anti-Xray - Add predefined block data } - public IBlockData getType(int i, int j, int k) { + public final IBlockData getType(int i, int j, int k) { // Paper @@ -132,10 +139,14 @@ public class ChunkSection { return this.blockIds; } @@ -1099,7 +1099,7 @@ index e056fbcb216977401fd2778fcd3ee7ed5f020214..eeb7eee925d31d1ed8e6bbd55888cb5e public int j() { diff --git a/src/main/java/net/minecraft/server/DataPaletteBlock.java b/src/main/java/net/minecraft/server/DataPaletteBlock.java -index 3da575929fcf878ebfe18e3240fac84325159225..abe86b4607e014e280e29daae6e1617763c53131 100644 +index 44310efd63b0a460e9dcdc1c8ad0abec78052061..a5ea0e34ec181ad9f98f9ee2f644c3ec1eb1cd3c 100644 --- a/src/main/java/net/minecraft/server/DataPaletteBlock.java +++ b/src/main/java/net/minecraft/server/DataPaletteBlock.java @@ -3,6 +3,7 @@ package net.minecraft.server; @@ -1338,7 +1338,7 @@ index ed3f3362b640746649455f8dd2255ac2da03df7c..f11ef84df85c1e7ada9c62247b7882f1 public void a(BlockPosition blockposition, PacketPlayInBlockDig.EnumPlayerDigType packetplayinblockdig_enumplayerdigtype, String s) { diff --git a/src/main/java/net/minecraft/server/ProtoChunk.java b/src/main/java/net/minecraft/server/ProtoChunk.java -index 39339fa27551b06a9bfd8ea67b1ec8c66726f488..deb7fb090196c4a33c0bb224f1c4e899aa3cd8c3 100644 +index 51a5b9cb36c4325df8d1434dcf28d27abefdfede..a78b240621e0407fff67b018224c39fc4f97f4e5 100644 --- a/src/main/java/net/minecraft/server/ProtoChunk.java +++ b/src/main/java/net/minecraft/server/ProtoChunk.java @@ -45,16 +45,24 @@ public class ProtoChunk implements IChunkAccess { @@ -1369,7 +1369,7 @@ index 39339fa27551b06a9bfd8ea67b1ec8c66726f488..deb7fb090196c4a33c0bb224f1c4e899 this.f = Maps.newEnumMap(HeightMap.Type.class); this.g = ChunkStatus.EMPTY; this.h = Maps.newHashMap(); -@@ -207,7 +215,7 @@ public class ProtoChunk implements IChunkAccess { +@@ -209,7 +217,7 @@ public class ProtoChunk implements IChunkAccess { public ChunkSection a(int i) { if (this.j[i] == Chunk.a) { @@ -1379,7 +1379,7 @@ index 39339fa27551b06a9bfd8ea67b1ec8c66726f488..deb7fb090196c4a33c0bb224f1c4e899 return this.j[i]; diff --git a/src/main/java/net/minecraft/server/ProtoChunkExtension.java b/src/main/java/net/minecraft/server/ProtoChunkExtension.java -index 01bf28dc34dd69dbcee5f470cc71ec2fbb2fcc12..caa18b046cd4231b1caa9c70e766ab60e11b3164 100644 +index b740e82622e282bdf543a84a559af69dd5b8568c..6db6e74886943559e3582c350ffae54857ad8b84 100644 --- a/src/main/java/net/minecraft/server/ProtoChunkExtension.java +++ b/src/main/java/net/minecraft/server/ProtoChunkExtension.java @@ -11,7 +11,7 @@ public class ProtoChunkExtension extends ProtoChunk { diff --git a/Spigot-Server-Patches/0389-Avoid-hopper-searches-if-there-are-no-items.patch b/Spigot-Server-Patches/0389-Avoid-hopper-searches-if-there-are-no-items.patch index fdbee1501..9e05dd85f 100644 --- a/Spigot-Server-Patches/0389-Avoid-hopper-searches-if-there-are-no-items.patch +++ b/Spigot-Server-Patches/0389-Avoid-hopper-searches-if-there-are-no-items.patch @@ -14,7 +14,7 @@ And since minecart hoppers are used _very_ rarely near we can avoid alot of sear Combined, this adds up a lot. diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index b855589d978d06e9883daff97c9e702d5a9461cc..9f0758aff6588736d500b6e202fc1a5f6a577e7f 100644 +index 08b3cbabc482d71862d90fcd9acd32d28f44a6e2..af9a195f6d0f966133577d00d30e8b4ad812aaeb 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java @@ -84,6 +84,10 @@ public class Chunk implements IChunkAccess { @@ -28,7 +28,7 @@ index b855589d978d06e9883daff97c9e702d5a9461cc..9f0758aff6588736d500b6e202fc1a5f // Paper end public Chunk(World world, ChunkCoordIntPair chunkcoordintpair, BiomeStorage biomestorage, ChunkConverter chunkconverter, TickList ticklist, TickList ticklist1, long i, @Nullable ChunkSection[] achunksection, @Nullable Consumer consumer) { -@@ -535,6 +539,13 @@ public class Chunk implements IChunkAccess { +@@ -538,6 +542,13 @@ public class Chunk implements IChunkAccess { entity.chunkZ = this.loc.z; this.entities.add(entity); // Paper - per chunk entity list this.entitySlices[k].add(entity); @@ -42,7 +42,7 @@ index b855589d978d06e9883daff97c9e702d5a9461cc..9f0758aff6588736d500b6e202fc1a5f entity.entitySlice = this.entitySlices[k]; // Paper this.markDirty(); // Paper } -@@ -567,6 +578,11 @@ public class Chunk implements IChunkAccess { +@@ -570,6 +581,11 @@ public class Chunk implements IChunkAccess { if (!this.entitySlices[i].remove(entity)) { return; } @@ -54,7 +54,7 @@ index b855589d978d06e9883daff97c9e702d5a9461cc..9f0758aff6588736d500b6e202fc1a5f entityCounts.decrement(entity.getMinecraftKeyString()); this.markDirty(); // Paper // Paper end -@@ -850,6 +866,14 @@ public class Chunk implements IChunkAccess { +@@ -853,6 +869,14 @@ public class Chunk implements IChunkAccess { for (int k = i; k <= j; ++k) { Iterator iterator = this.entitySlices[k].iterator(); // Spigot @@ -69,7 +69,7 @@ index b855589d978d06e9883daff97c9e702d5a9461cc..9f0758aff6588736d500b6e202fc1a5f while (iterator.hasNext()) { T entity = (T) iterator.next(); // CraftBukkit - decompile error if (entity.shouldBeRemoved) continue; // Paper -@@ -869,9 +893,29 @@ public class Chunk implements IChunkAccess { +@@ -872,9 +896,29 @@ public class Chunk implements IChunkAccess { i = MathHelper.clamp(i, 0, this.entitySlices.length - 1); j = MathHelper.clamp(j, 0, this.entitySlices.length - 1); diff --git a/Spigot-Server-Patches/0435-Optimise-random-block-ticking.patch b/Spigot-Server-Patches/0435-Optimise-random-block-ticking.patch index 54f41893c..f4822e3d6 100644 --- a/Spigot-Server-Patches/0435-Optimise-random-block-ticking.patch +++ b/Spigot-Server-Patches/0435-Optimise-random-block-ticking.patch @@ -111,10 +111,10 @@ index a3a376e35eaf17b128048bd26a22eef713e7d535..3fcfe416d26808fa1c9bfdc5b413b149 return this.d(baseblockposition.getX(), baseblockposition.getY(), baseblockposition.getZ()); } diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index 9f0758aff6588736d500b6e202fc1a5f6a577e7f..2cb0005909e9a77d2bd594cab0a75b259882cadb 100644 +index af9a195f6d0f966133577d00d30e8b4ad812aaeb..cfdf6ea55dedeaf6b96566b72ca0015350c13e92 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java -@@ -589,8 +589,8 @@ public class Chunk implements IChunkAccess { +@@ -592,8 +592,8 @@ public class Chunk implements IChunkAccess { this.entities.remove(entity); // Paper } @@ -126,7 +126,7 @@ index 9f0758aff6588736d500b6e202fc1a5f6a577e7f..2cb0005909e9a77d2bd594cab0a75b25 } diff --git a/src/main/java/net/minecraft/server/ChunkSection.java b/src/main/java/net/minecraft/server/ChunkSection.java -index eeb7eee925d31d1ed8e6bbd55888cb5ebe54afa2..64b625e988f6bb6dc7129b4cb70e266015ab0867 100644 +index c180d44bed91c86838d3be8c19be954b4412534e..4eb7c1a9b5afced4be79a263e6a918f39c4b51be 100644 --- a/src/main/java/net/minecraft/server/ChunkSection.java +++ b/src/main/java/net/minecraft/server/ChunkSection.java @@ -6,12 +6,14 @@ import javax.annotation.Nullable; @@ -135,7 +135,7 @@ index eeb7eee925d31d1ed8e6bbd55888cb5ebe54afa2..64b625e988f6bb6dc7129b4cb70e2660 public static final DataPalette GLOBAL_PALETTE = new DataPaletteGlobal<>(Block.REGISTRY_ID, Blocks.AIR.getBlockData()); - private final int yPos; + final int yPos; // Paper - private -> package-private - private short nonEmptyBlockCount; + short nonEmptyBlockCount; // Paper - package-private - private short tickingBlockCount; + short tickingBlockCount; // Paper - private -> package-private private short e; @@ -253,7 +253,7 @@ index f9680b6830c77f31e1eb8b6845dd6d58d04f624a..a61cffa3f494be5fea785a573b0faf05 + // Paper end } diff --git a/src/main/java/net/minecraft/server/DataPaletteBlock.java b/src/main/java/net/minecraft/server/DataPaletteBlock.java -index abe86b4607e014e280e29daae6e1617763c53131..c9a13c865b332a5b6dbea9f23c00b0c9d66f3798 100644 +index a5ea0e34ec181ad9f98f9ee2f644c3ec1eb1cd3c..81362de5430f9cd045ee7cbefa4a28e4c6bc0457 100644 --- a/src/main/java/net/minecraft/server/DataPaletteBlock.java +++ b/src/main/java/net/minecraft/server/DataPaletteBlock.java @@ -278,6 +278,14 @@ public class DataPaletteBlock implements DataPaletteExpandable { @@ -338,7 +338,7 @@ index 321eae23c575528788b1b575f17593580d6ba737..b19bbbbc81376177751396a2de9452ce public final SoundEffectType getStepSound() { return this.r(); } // Paper - OBFHELPER diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java -index d8eb8a59da36215334582ae73822e1fd4a5b2df1..ac8b21e69b198612427a81a16fc1a3ff0b0cb558 100644 +index dab9d36dfcda6f363fb78ad6be6a0306786945ae..6f7da0a79bbbb2be354796033baa498845aaea7c 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -1564,10 +1564,19 @@ public abstract class World implements GeneratorAccess, AutoCloseable { diff --git a/Spigot-Server-Patches/0445-Optimise-Chunk-getFluid.patch b/Spigot-Server-Patches/0445-Optimise-Chunk-getFluid.patch index be4fd91e1..d0174a7e1 100644 --- a/Spigot-Server-Patches/0445-Optimise-Chunk-getFluid.patch +++ b/Spigot-Server-Patches/0445-Optimise-Chunk-getFluid.patch @@ -8,10 +8,10 @@ faster on its own, however removing the try catch makes it easier to inline due to code size diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index 2cb0005909e9a77d2bd594cab0a75b259882cadb..234770236fdc8d37996fb8b7e0b4ed2491e31633 100644 +index cfdf6ea55dedeaf6b96566b72ca0015350c13e92..74d110874d0a9c1603d6b2d77753179ba49811ea 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java -@@ -382,17 +382,20 @@ public class Chunk implements IChunkAccess { +@@ -385,17 +385,20 @@ public class Chunk implements IChunkAccess { } public Fluid a(int i, int j, int k) { @@ -39,7 +39,7 @@ index 2cb0005909e9a77d2bd594cab0a75b259882cadb..234770236fdc8d37996fb8b7e0b4ed24 CrashReport crashreport = CrashReport.a(throwable, "Getting fluid state"); CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Block being got"); -@@ -401,6 +404,7 @@ public class Chunk implements IChunkAccess { +@@ -404,6 +407,7 @@ public class Chunk implements IChunkAccess { }); throw new ReportedException(crashreport); } @@ -48,7 +48,7 @@ index 2cb0005909e9a77d2bd594cab0a75b259882cadb..234770236fdc8d37996fb8b7e0b4ed24 // CraftBukkit start diff --git a/src/main/java/net/minecraft/server/ChunkSection.java b/src/main/java/net/minecraft/server/ChunkSection.java -index 64b625e988f6bb6dc7129b4cb70e266015ab0867..b7b06e082e59f8518be2036637385c7710d524ea 100644 +index 4eb7c1a9b5afced4be79a263e6a918f39c4b51be..f6df85c6bf27bfa7a16967259a6016c9473201a5 100644 --- a/src/main/java/net/minecraft/server/ChunkSection.java +++ b/src/main/java/net/minecraft/server/ChunkSection.java @@ -37,7 +37,7 @@ public class ChunkSection { diff --git a/Spigot-Server-Patches/0477-Optimise-entity-hard-collision-checking.patch b/Spigot-Server-Patches/0477-Optimise-entity-hard-collision-checking.patch index 67f18270d..fed43bd67 100644 --- a/Spigot-Server-Patches/0477-Optimise-entity-hard-collision-checking.patch +++ b/Spigot-Server-Patches/0477-Optimise-entity-hard-collision-checking.patch @@ -11,7 +11,7 @@ Less crammed entities are likely to show significantly less benefit. Effectively, this patch optimises crammed entity situations. diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index 234770236fdc8d37996fb8b7e0b4ed2491e31633..d73987ffc416f47eb6231013a76420bc71c34f0e 100644 +index 74d110874d0a9c1603d6b2d77753179ba49811ea..cf86ce24e12068d6ff7ae43cb1fd6fe665c24932 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java @@ -90,6 +90,54 @@ public class Chunk implements IChunkAccess { @@ -69,7 +69,7 @@ index 234770236fdc8d37996fb8b7e0b4ed2491e31633..d73987ffc416f47eb6231013a76420bc public Chunk(World world, ChunkCoordIntPair chunkcoordintpair, BiomeStorage biomestorage, ChunkConverter chunkconverter, TickList ticklist, TickList ticklist1, long i, @Nullable ChunkSection[] achunksection, @Nullable Consumer consumer) { this.sections = new ChunkSection[16]; this.e = Maps.newHashMap(); -@@ -542,7 +590,7 @@ public class Chunk implements IChunkAccess { +@@ -545,7 +593,7 @@ public class Chunk implements IChunkAccess { entity.chunkY = k; entity.chunkZ = this.loc.z; this.entities.add(entity); // Paper - per chunk entity list @@ -78,7 +78,7 @@ index 234770236fdc8d37996fb8b7e0b4ed2491e31633..d73987ffc416f47eb6231013a76420bc // Paper start if (entity instanceof EntityItem) { itemCounts[k]++; -@@ -579,7 +627,7 @@ public class Chunk implements IChunkAccess { +@@ -582,7 +630,7 @@ public class Chunk implements IChunkAccess { entity.entitySlice = null; entity.inChunk = false; } @@ -178,7 +178,7 @@ index 4157e50e4d99c029759bffcb48a8d645487554c8..5135308fb6137a34ed6fd061f0a210de return stream.filter(axisalignedbb1::c).map(VoxelShapes::a); diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java -index 42be4edb36200626913fa99b1e67956933022531..4dc03c27bba5cd2dd1d6cb2e82087ef834f41d81 100644 +index 8cf191ec7f7c825e3d0996b7e224956a569ab2ba..9f4268202653f6f0ebed49cd67ae691a8b18ccd2 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -1179,6 +1179,32 @@ public abstract class World implements GeneratorAccess, AutoCloseable { diff --git a/Spigot-Server-Patches/0504-Stop-copy-on-write-operations-for-updating-light-dat.patch b/Spigot-Server-Patches/0504-Stop-copy-on-write-operations-for-updating-light-dat.patch index 2edf60dc0..ede6c2717 100644 --- a/Spigot-Server-Patches/0504-Stop-copy-on-write-operations-for-updating-light-dat.patch +++ b/Spigot-Server-Patches/0504-Stop-copy-on-write-operations-for-updating-light-dat.patch @@ -63,7 +63,7 @@ index a3f919816eb2a742ed09b553995e6508684e5ea5..88277d23c36696fdd5363e41a130c9a4 } diff --git a/src/main/java/net/minecraft/server/LightEngineStorageArray.java b/src/main/java/net/minecraft/server/LightEngineStorageArray.java -index b978723a66d001f70325df0c7521025e079d7cfa..d441c4e4744d68b3d934ca6034c32966e486327a 100644 +index b978723a66d001f70325df0c7521025e079d7cfa..53199595da71a25710bd1ff8ee2868ee63edc0e1 100644 --- a/src/main/java/net/minecraft/server/LightEngineStorageArray.java +++ b/src/main/java/net/minecraft/server/LightEngineStorageArray.java @@ -8,10 +8,23 @@ public abstract class LightEngineStorageArray> e @@ -39,9 +39,12 @@ index 88277d23c36696fdd5363e41a130c9a443fac2c0..fa8039d38d5b3110fd85abf850248ba7 } protected void a(LightEngineLayer lightenginelayer, long i) { -@@ -319,7 +319,7 @@ public abstract class LightEngineStorage> e +@@ -317,9 +317,9 @@ public abstract class LightEngineStorage> e + + protected void a(long i, @Nullable NibbleArray nibblearray) { if (nibblearray != null) { - this.i.put(i, nibblearray); +- this.i.put(i, nibblearray); ++ NibbleArray remove = this.i.put(i, nibblearray); if (remove != null && remove.cleaner != null) remove.cleaner.run(); // Paper - clean up when removed } else { - this.i.remove(i); + NibbleArray remove = this.i.remove(i); if (remove != null && remove.cleaner != null) remove.cleaner.run(); // Paper - clean up when removed @@ -49,7 +52,7 @@ index 88277d23c36696fdd5363e41a130c9a443fac2c0..fa8039d38d5b3110fd85abf850248ba7 } diff --git a/src/main/java/net/minecraft/server/LightEngineStorageArray.java b/src/main/java/net/minecraft/server/LightEngineStorageArray.java -index d441c4e4744d68b3d934ca6034c32966e486327a..cc6d3f000e2ea1c519cd0342a67b545fa9d71871 100644 +index 53199595da71a25710bd1ff8ee2868ee63edc0e1..d5702b22f06ba4ad787fe2fcf788c3d4d147c927 100644 --- a/src/main/java/net/minecraft/server/LightEngineStorageArray.java +++ b/src/main/java/net/minecraft/server/LightEngineStorageArray.java @@ -33,7 +33,9 @@ public abstract class LightEngineStorageArray { @@ -262,7 +265,7 @@ index cd1ad45469aa163b9bc41774ae80adfa617fd97b..1946aae7424593100279834baa89c19f + public void onPacketDispatchFinish(EntityPlayer player, io.netty.channel.ChannelFuture future) { + if (remainingSends.decrementAndGet() <= 0) { + // incase of any race conditions, schedule this delayed -+ MCUtil.scheduleTask(1, () -> { ++ MCUtil.scheduleTask(5, () -> { + if (remainingSends.get() == 0) { + cleaner1.run(); + cleaner2.run(); diff --git a/Spigot-Server-Patches/0523-Reduce-MutableInt-allocations-from-light-engine.patch b/Spigot-Server-Patches/0523-Reduce-MutableInt-allocations-from-light-engine.patch index dde41cb73..2524f18f3 100644 --- a/Spigot-Server-Patches/0523-Reduce-MutableInt-allocations-from-light-engine.patch +++ b/Spigot-Server-Patches/0523-Reduce-MutableInt-allocations-from-light-engine.patch @@ -3,58 +3,48 @@ From: Spottedleaf Date: Mon, 27 Apr 2020 02:48:06 -0700 Subject: [PATCH] Reduce MutableInt allocations from light engine +We can abuse the fact light is single threaded and share an instance +per light engine instance diff --git a/src/main/java/net/minecraft/server/LightEngineBlock.java b/src/main/java/net/minecraft/server/LightEngineBlock.java -index 93a972605c26aa757b9c915876f847da04fcb496..c9e91eb4ef538485620aedaee4843b779fede809 100644 +index 93a972605c26aa757b9c915876f847da04fcb496..07fadc21ee12138b52cc77c50da536fec5b032f5 100644 --- a/src/main/java/net/minecraft/server/LightEngineBlock.java +++ b/src/main/java/net/minecraft/server/LightEngineBlock.java -@@ -37,7 +37,10 @@ public final class LightEngineBlock extends LightEngineLayer= 15) { -@@ -49,6 +52,10 @@ public final class LightEngineBlock extends LightEngineLayer= 15) { return k; } else { - MutableInt mutableint = new MutableInt(); -+ // Paper start - reduce mutableint allocations -+ MutableInt mutableint = com.destroystokyo.paper.util.pooled.PooledObjects.POOLED_MUTABLE_INTEGERS.acquire(); -+ try { -+ // Paper end - reduce mutableint allocations ++ //MutableInt mutableint = new MutableInt(); // Paper - share mutableint, single threaded IBlockData iblockdata = this.a(j, mutableint); if (mutableint.getValue() >= 15) { -@@ -85,6 +88,10 @@ public final class LightEngineSky extends LightEngineLayer { -+ // Paper start -+ IntSupplier defSupplier = this.d.c(chunkcoordintpair.pair()); -+ IntSupplier priority = () -> Math.max(defSupplier.getAsInt() - 1, 1); -+ // Paper end -+ this.a(chunkcoordintpair.x, chunkcoordintpair.z, priority, LightEngineThreaded.Update.PRE_UPDATE, SystemUtils.a(() -> { // Paper - boost light priority - ChunkSection[] achunksection = ichunkaccess.getSections(); - - for (int i = 0; i < 16; ++i) { -@@ -161,7 +165,7 @@ public class LightEngineThreaded extends LightEngine implements AutoCloseable { - super.b(chunkcoordintpair, false); - return ichunkaccess; - }, (runnable) -> { -- this.a(chunkcoordintpair.x, chunkcoordintpair.z, LightEngineThreaded.Update.POST_UPDATE, runnable); -+ this.a(chunkcoordintpair.x, chunkcoordintpair.z, priority, LightEngineThreaded.Update.POST_UPDATE, runnable); // Paper - boost light priority - }); - } - diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java index 0d1065688b19ceca9440bc8bf2bf65910f03fa46..8a349964578e07e5ed13f801c57de68459220da9 100644 --- a/src/main/java/net/minecraft/server/MCUtil.java diff --git a/Spigot-Server-Patches/0537-Optimize-Bit-Operations-by-inlining.patch b/Spigot-Server-Patches/0537-Optimize-Bit-Operations-by-inlining.patch new file mode 100644 index 000000000..541ecb700 --- /dev/null +++ b/Spigot-Server-Patches/0537-Optimize-Bit-Operations-by-inlining.patch @@ -0,0 +1,234 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 4 Jun 2020 02:24:49 -0400 +Subject: [PATCH] Optimize Bit Operations by inlining + +Inline bit operations and reduce instruction count to make these hot +operations faster + +diff --git a/src/main/java/net/minecraft/server/BlockPosition.java b/src/main/java/net/minecraft/server/BlockPosition.java +index 3bf17ccdaef21322b787db538d569e0bc614ef22..4c64798fbc50f4d8b08502ba865c5fde5c968e62 100644 +--- a/src/main/java/net/minecraft/server/BlockPosition.java ++++ b/src/main/java/net/minecraft/server/BlockPosition.java +@@ -75,38 +75,34 @@ public class BlockPosition extends BaseBlockPosition implements MinecraftSeriali + return dynamicops.createIntList(IntStream.of(new int[]{this.getX(), this.getY(), this.getZ()})); + } + ++ public static long getAdjacent(int baseX, int baseY, int baseZ, EnumDirection enumdirection) { return asLong(baseX + enumdirection.getAdjacentX(), baseY + enumdirection.getAdjacentY(), baseZ + enumdirection.getAdjacentZ()); } // Paper + public static long a(long i, EnumDirection enumdirection) { + return a(i, enumdirection.getAdjacentX(), enumdirection.getAdjacentY(), enumdirection.getAdjacentZ()); + } + + public static long a(long i, int j, int k, int l) { +- return a(b(i) + j, c(i) + k, d(i) + l); ++ return a((int) (i >> 38) + j, (int) ((i << 52) >> 52) + k, (int) ((i << 26) >> 38) + l); // Paper - simplify/inline + } + + public static int b(long i) { +- return (int) (i << 64 - BlockPosition.k - BlockPosition.c >> 64 - BlockPosition.c); ++ return (int) (i >> 38); // Paper - simplify/inline + } + + public static int c(long i) { +- return (int) (i << 64 - BlockPosition.f >> 64 - BlockPosition.f); ++ return (int) ((i << 52) >> 52); // Paper - simplify/inline + } + + public static int d(long i) { +- return (int) (i << 64 - BlockPosition.j - BlockPosition.d >> 64 - BlockPosition.d); ++ return (int) ((i << 26) >> 38); // Paper - simplify/inline + } + + public static BlockPosition fromLong(long i) { +- return new BlockPosition(b(i), c(i), d(i)); ++ return new BlockPosition((int) (i >> 38), (int) ((i << 52) >> 52), (int) ((i << 26) >> 38)); // Paper - simplify/inline + } + + public static long asLong(int x, int y, int z) { return a(x, y, z); } // Paper - OBFHELPER + public static long a(int i, int j, int k) { +- long l = 0L; +- +- l |= ((long) i & BlockPosition.g) << BlockPosition.k; +- l |= ((long) j & BlockPosition.h) << 0; +- l |= ((long) k & BlockPosition.i) << BlockPosition.j; +- return l; ++ return (((long) i & (long) 67108863) << 38) | (((long) j & (long) 4095)) | (((long) k & (long) 67108863) << 12); // Paper - inline constants and simplify + } + + public static long f(long i) { +diff --git a/src/main/java/net/minecraft/server/SectionPosition.java b/src/main/java/net/minecraft/server/SectionPosition.java +index ca3f63f5e5e4e926de562b4bfbbf72ad8a6b943f..c415736282de6d4d0f87135c24999c4bbf993901 100644 +--- a/src/main/java/net/minecraft/server/SectionPosition.java ++++ b/src/main/java/net/minecraft/server/SectionPosition.java +@@ -16,7 +16,7 @@ public class SectionPosition extends BaseBlockPosition { + } + + public static SectionPosition a(BlockPosition blockposition) { +- return new SectionPosition(a(blockposition.getX()), a(blockposition.getY()), a(blockposition.getZ())); ++ return new SectionPosition(blockposition.getX() >> 4, blockposition.getY() >> 4, blockposition.getZ() >> 4); // Paper + } + + public static SectionPosition a(ChunkCoordIntPair chunkcoordintpair, int i) { +@@ -28,7 +28,7 @@ public class SectionPosition extends BaseBlockPosition { + } + + public static SectionPosition a(long i) { +- return new SectionPosition(b(i), c(i), d(i)); ++ return new SectionPosition((int) (i >> 42), (int) (i << 44 >> 44), (int) (i << 22 >> 42)); // Paper + } + + public static long a(long i, EnumDirection enumdirection) { +@@ -36,7 +36,7 @@ public class SectionPosition extends BaseBlockPosition { + } + + public static long a(long i, int j, int k, int l) { +- return b(b(i) + j, c(i) + k, d(i) + l); ++ return (((long) ((int) (i >> 42) + j) & 4194303L) << 42) | (((long) ((int) (i << 44 >> 44) + k) & 1048575L)) | (((long) ((int) (i << 22 >> 42) + l) & 4194303L) << 20); // Simplify to reduce instruction count + } + + public static int a(int i) { +@@ -48,11 +48,7 @@ public class SectionPosition extends BaseBlockPosition { + } + + public static short b(BlockPosition blockposition) { +- int i = b(blockposition.getX()); +- int j = b(blockposition.getY()); +- int k = b(blockposition.getZ()); +- +- return (short) (i << 8 | k << 4 | j); ++ return (short) ((blockposition.x & 15) << 8 | (blockposition.z & 15) << 4 | blockposition.y & 15); // Paper - simplify/inline + } + + public static int c(int i) { +@@ -60,7 +56,7 @@ public class SectionPosition extends BaseBlockPosition { + } + + public static int b(long i) { +- return (int) (i << 0 >> 42); ++ return (int) (i >> 42); // Paper + } + + public static int c(long i) { +@@ -71,44 +67,46 @@ public class SectionPosition extends BaseBlockPosition { + return (int) (i << 22 >> 42); + } + +- public int a() { +- return this.getX(); ++ public final int a() { // Paper ++ return x; // Paper + } + +- public int b() { +- return this.getY(); ++ public final int b() { // Paper ++ return y; // Paper + } + +- public int c() { +- return this.getZ(); ++ public final int c() { // Paper ++ return z; // Paper + } + +- public int d() { +- return this.a() << 4; ++ public final int d() { // Paper ++ return x << 4; // Paper + } + +- public int e() { +- return this.b() << 4; ++ public final int e() { // Paper ++ return y << 4; // Paper + } + +- public int f() { +- return this.c() << 4; ++ public final int f() { // Paper ++ return z << 4; // Paper + } + +- public int g() { +- return (this.a() << 4) + 15; ++ public final int g() { // Paper ++ return (x << 4) + 15; // Paper + } + +- public int h() { +- return (this.b() << 4) + 15; ++ public final int h() { // Paper ++ return (y << 4) + 15; // Paper + } + +- public int r() { +- return (this.c() << 4) + 15; ++ public final int r() { // Paper ++ return (z << 4) + 15; // Paper + } + ++ public static long blockToSection(long i) { return e(i); } // Paper - OBFHELPER + public static long e(long i) { +- return b(a(BlockPosition.b(i)), a(BlockPosition.c(i)), a(BlockPosition.d(i))); ++ // b(a(BlockPosition.b(i)), a(BlockPosition.c(i)), a(BlockPosition.d(i))); ++ return (((long) (int) (i >> 42) & 4194303L) << 42) | (((long) (int) ((i << 52) >> 56) & 1048575L)) | (((long) (int) ((i << 26) >> 42) & 4194303L) << 20); // Simplify to reduce instruction count + } + + public static long f(long i) { +@@ -116,7 +114,7 @@ public class SectionPosition extends BaseBlockPosition { + } + + public BlockPosition s() { +- return new BlockPosition(c(this.a()), c(this.b()), c(this.c())); ++ return new BlockPosition(x << 4, y << 4, z << 4); // Paper + } + + public BlockPosition t() { +@@ -129,36 +127,30 @@ public class SectionPosition extends BaseBlockPosition { + return new ChunkCoordIntPair(this.a(), this.c()); + } + ++ // Paper start ++ public static long blockPosAsSectionLong(int i, int j, int k) { ++ return (((long) (i >> 4) & 4194303L) << 42) | (((long) (j >> 4) & 1048575L)) | (((long) (k >> 4) & 4194303L) << 20); ++ } ++ // Paper end ++ public static long asLong(int i, int j, int k) { return b(i, j, k); } // Paper - OBFHELPER + public static long b(int i, int j, int k) { +- long l = 0L; +- +- l |= ((long) i & 4194303L) << 42; +- l |= ((long) j & 1048575L) << 0; +- l |= ((long) k & 4194303L) << 20; +- return l; ++ return (((long) i & 4194303L) << 42) | (((long) j & 1048575L)) | (((long) k & 4194303L) << 20); // Paper - Simplify to reduce instruction count + } + + public long v() { +- return b(this.a(), this.b(), this.c()); ++ return (((long) x & 4194303L) << 42) | (((long) y & 1048575L)) | (((long) z & 4194303L) << 20); // Paper - Simplify to reduce instruction count + } + + public Stream w() { +- return BlockPosition.a(this.d(), this.e(), this.f(), this.g(), this.h(), this.r()); ++ return BlockPosition.a(x << 4, y << 4, z << 4, (x << 4) + 15, (y << 4) + 15, (z << 4) + 15); // Paper - simplify/inline + } + + public static Stream a(SectionPosition sectionposition, int i) { +- int j = sectionposition.a(); +- int k = sectionposition.b(); +- int l = sectionposition.c(); +- +- return a(j - i, k - i, l - i, j + i, k + i, l + i); ++ return a(sectionposition.x - i, sectionposition.y - i, sectionposition.z - i, sectionposition.x + i, sectionposition.y + i, sectionposition.z + i); // Paper - simplify/inline + } + + public static Stream b(ChunkCoordIntPair chunkcoordintpair, int i) { +- int j = chunkcoordintpair.x; +- int k = chunkcoordintpair.z; +- +- return a(j - i, 0, k - i, j + i, 15, k + i); ++ return a(chunkcoordintpair.x - i, 0, chunkcoordintpair.z - i, chunkcoordintpair.x + i, 15, chunkcoordintpair.z + i); // Paper - simplify/inline + } + + public static Stream a(final int i, final int j, final int k, final int l, final int i1, final int j1) { diff --git a/Spigot-Server-Patches/0538-Optimize-Light-Engine.patch b/Spigot-Server-Patches/0538-Optimize-Light-Engine.patch new file mode 100644 index 000000000..2fcb9c4f3 --- /dev/null +++ b/Spigot-Server-Patches/0538-Optimize-Light-Engine.patch @@ -0,0 +1,1213 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Thu, 4 Jun 2020 22:43:29 -0400 +Subject: [PATCH] Optimize Light Engine + +Massive update to light to improve performance and chunk loading/generation. + +1) Massive bit packing/unpacking optimizations and inlining. + A lot of performance has to do with constant packing and unpacking of bits. + We now inline a most bit operations, and re-use base x/y/z bits in many places. + This helps with cpu level processing to just do all the math at once instead + of having to jump in and out of function calls. + + This much logic also is likely over the JVM Inline limit for JIT too. +2) Applied a few of JellySquid's Phosphor mod optimizations such as + - ensuring we don't notify neighbor chunks when neighbor chunk doesn't need to be notified + - reduce hasLight checks in initializing light, and prob some more, they are tagged JellySquid where phosphor influence was used. +3) Optimize hot path accesses to getting updating chunk to have less branching +4) Optimize getBlock accesses to have less branching, and less unpacking +5) Have a separate urgent bucket for chunk light tasks. These tasks will always cut in line over non blocking light tasks. +6) Retain chunk priority while light tasks are enqueued. So if a task comes in at high priority but the queue is full + of tasks already at a lower priority, before the task was simply added to the end. Now it can cut in line to the front. + this applies for both urgent and non urgent tasks. +7) Buffer non urgent tasks even if queueUpdate is called multiple times to improve efficiency. +8) Fix NPE risk that crashes server in getting nibble data + +diff --git a/src/main/java/net/minecraft/server/Block.java b/src/main/java/net/minecraft/server/Block.java +index d051a54aa04326f84e211cd68ddd2bb209230770..bd7a92599b4182739aafef9eeaaf8665d2f9f954 100644 +--- a/src/main/java/net/minecraft/server/Block.java ++++ b/src/main/java/net/minecraft/server/Block.java +@@ -309,7 +309,7 @@ public class Block implements IMaterial { + return false; + } + +- @Deprecated ++ public final boolean canOcclude(IBlockData blockData) { return n(blockData); } @Deprecated // Paper - OBFHELPER + public final boolean n(IBlockData iblockdata) { + return this.j; + } +diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java +index 54e89c9cc6c47ff2c4f4dd5d4c22a391f8a3d6e0..ded57740a3dae8808dbe4c9d962a4f767e691b17 100644 +--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java ++++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java +@@ -1080,12 +1080,13 @@ public class ChunkProviderServer extends IChunkProvider { + if (ChunkProviderServer.this.tickDistanceManager()) { + return true; + } else { +- ChunkProviderServer.this.lightEngine.queueUpdate(); ++ //ChunkProviderServer.this.lightEngine.queueUpdate(); // Paper - move down + return super.executeNext() || execChunkTask; // Paper + } + } finally { + playerChunkMap.chunkLoadConversionCallbackExecutor.run(); // Paper - Add chunk load conversion callback executor to prevent deadlock due to recursion in the chunk task queue sorter + playerChunkMap.callbackExecutor.run(); ++ ChunkProviderServer.this.lightEngine.queueUpdate(); // Paper - always run, this is rate limited now + } + // CraftBukkit end + } +diff --git a/src/main/java/net/minecraft/server/IBlockData.java b/src/main/java/net/minecraft/server/IBlockData.java +index 296b41bf36ee1ace5bd9db2b810bf926b5f5278f..b39554faf235b6f81c86542673dfb4508d4c3e5a 100644 +--- a/src/main/java/net/minecraft/server/IBlockData.java ++++ b/src/main/java/net/minecraft/server/IBlockData.java +@@ -24,6 +24,7 @@ public class IBlockData extends BlockDataAbstract implements + private final boolean e; + private final boolean isAir; // Paper + private final boolean isTicking; // Paper ++ private final boolean canOcclude; // Paper + + public IBlockData(Block block, ImmutableMap, Comparable> immutablemap) { + super(block, immutablemap); +@@ -31,6 +32,7 @@ public class IBlockData extends BlockDataAbstract implements + this.e = block.o(this); + this.isAir = this.getBlock().isAir(this); // Paper + this.isTicking = this.getBlock().isTicking(this); // Paper ++ this.canOcclude = this.getBlock().canOcclude(this); // Paper + } + + public void c() { +@@ -83,7 +85,7 @@ public class IBlockData extends BlockDataAbstract implements + return this.c == null || this.c.h; + } + +- public boolean g() { ++ public final boolean g() { // Paper + return this.e; + } + +@@ -151,8 +153,8 @@ public class IBlockData extends BlockDataAbstract implements + return this.c != null ? this.c.c : this.getBlock().k(this, iblockaccess, blockposition); + } + +- public boolean o() { +- return this.c != null ? this.c.b : this.getBlock().n(this); ++ public final boolean o() { // Paper ++ return canOcclude; // Paper + } + + public VoxelShape getShape(IBlockAccess iblockaccess, BlockPosition blockposition) { +diff --git a/src/main/java/net/minecraft/server/LightEngineBlock.java b/src/main/java/net/minecraft/server/LightEngineBlock.java +index 07fadc21ee12138b52cc77c50da536fec5b032f5..86868bedc65948b00edc8a7b6f219b85cc8c6374 100644 +--- a/src/main/java/net/minecraft/server/LightEngineBlock.java ++++ b/src/main/java/net/minecraft/server/LightEngineBlock.java +@@ -13,9 +13,11 @@ public final class LightEngineBlock extends LightEngineLayer> 38); ++ int k = (int) ((i << 52) >> 52); ++ int l = (int) ((i << 26) >> 38); ++ // Paper end + IBlockAccess iblockaccess = this.a.c(j >> 4, l >> 4); + + return iblockaccess != null ? iblockaccess.h(this.f.d(j, k, l)) : 0; +@@ -30,25 +32,33 @@ public final class LightEngineBlock extends LightEngineLayer= 15) { + return k; + } else { +- int l = Integer.signum(BlockPosition.b(j) - BlockPosition.b(i)); +- int i1 = Integer.signum(BlockPosition.c(j) - BlockPosition.c(i)); +- int j1 = Integer.signum(BlockPosition.d(j) - BlockPosition.d(i)); ++ // Paper start - reuse math - credit to JellySquid for idea ++ int jx = (int) (j >> 38); ++ int jy = (int) ((j << 52) >> 52); ++ int jz = (int) ((j << 26) >> 38); ++ int ix = (int) (i >> 38); ++ int iy = (int) ((i << 52) >> 52); ++ int iz = (int) ((i << 26) >> 38); ++ int l = Integer.signum(jx - ix); ++ int i1 = Integer.signum(jy - iy); ++ int j1 = Integer.signum(jz - iz); ++ // Paper end + EnumDirection enumdirection = EnumDirection.a(l, i1, j1); + + if (enumdirection == null) { + return 15; + } else { + //MutableInt mutableint = new MutableInt(); // Paper - share mutableint, single threaded +- IBlockData iblockdata = this.a(j, mutableint); +- +- if (mutableint.getValue() >= 15) { ++ IBlockData iblockdata = this.getBlockOptimized(jx, jy, jz, mutableint); // Paper ++ int blockedLight = mutableint.getValue(); // Paper ++ if (blockedLight >= 15) { // Paper + return 15; + } else { +- IBlockData iblockdata1 = this.a(i, (MutableInt) null); ++ IBlockData iblockdata1 = this.getBlockOptimized(ix, iy, iz); // Paper + VoxelShape voxelshape = this.a(iblockdata1, i, enumdirection); + VoxelShape voxelshape1 = this.a(iblockdata, j, enumdirection.opposite()); + +- return VoxelShapes.b(voxelshape, voxelshape1) ? 15 : k + Math.max(1, mutableint.getValue()); ++ return VoxelShapes.b(voxelshape, voxelshape1) ? 15 : k + Math.max(1, blockedLight); // Paper + } + } + } +@@ -56,14 +66,19 @@ public final class LightEngineBlock extends LightEngineLayer> 38); ++ int y = (int) ((i << 52) >> 52); ++ int z = (int) ((i << 26) >> 38); ++ long k = SectionPosition.asLong(x >> 4, y >> 4, z >> 4); ++ // Paper end + EnumDirection[] aenumdirection = LightEngineBlock.e; + int l = aenumdirection.length; + + for (int i1 = 0; i1 < l; ++i1) { + EnumDirection enumdirection = aenumdirection[i1]; +- long j1 = BlockPosition.a(i, enumdirection); +- long k1 = SectionPosition.e(j1); ++ long j1 = BlockPosition.asLong(x + enumdirection.getAdjacentX(), y + enumdirection.getAdjacentY(), z + enumdirection.getAdjacentZ()); // Paper ++ long k1 = SectionPosition.asLong((x + enumdirection.getAdjacentX()) >> 4, (y + enumdirection.getAdjacentY()) >> 4, (z + enumdirection.getAdjacentZ()) >> 4); // Paper + + if (k == k1 || ((LightEngineStorageBlock) this.c).g(k1)) { + this.b(i, j1, j, flag); +@@ -88,27 +103,36 @@ public final class LightEngineBlock extends LightEngineLayer> 38); ++ int baseY = (int) ((i << 52) >> 52); ++ int baseZ = (int) ((i << 26) >> 38); ++ long j1 = (((long) (baseX >> 4) & 4194303L) << 42) | (((long) (baseY >> 4) & 1048575L)) | (((long) (baseZ >> 4) & 4194303L) << 20); ++ NibbleArray nibblearray = this.c.updating.getUpdatingOptimized(j1); ++ // Paper end + EnumDirection[] aenumdirection = LightEngineBlock.e; + int k1 = aenumdirection.length; + + for (int l1 = 0; l1 < k1; ++l1) { + EnumDirection enumdirection = aenumdirection[l1]; +- long i2 = BlockPosition.a(i, enumdirection); +- +- if (i2 != j) { +- long j2 = SectionPosition.e(i2); ++ // Paper start ++ int newX = baseX + enumdirection.getAdjacentX(); ++ int newY = baseY + enumdirection.getAdjacentY(); ++ int newZ = baseZ + enumdirection.getAdjacentZ(); ++ if (newX != baseX || newY != baseY || newZ != baseZ) { ++ long i2 = BlockPosition.asLong(newX, newY, newZ); ++ long j2 = SectionPosition.blockPosAsSectionLong(newX, newY, newZ); ++ // Paper end + NibbleArray nibblearray1; + + if (j1 == j2) { + nibblearray1 = nibblearray; + } else { +- nibblearray1 = ((LightEngineStorageBlock) this.c).a(j2, true); ++ nibblearray1 = ((LightEngineStorageBlock) this.c).updating.getUpdatingOptimized(j2); // Paper + } + + if (nibblearray1 != null) { +- int k2 = this.b(i2, i, this.a(nibblearray1, i2)); ++ int k2 = this.b(i2, i, this.getNibbleLightInverse(nibblearray1, newX, newY, newZ)); // Paper + + if (l > k2) { + l = k2; +diff --git a/src/main/java/net/minecraft/server/LightEngineGraphSection.java b/src/main/java/net/minecraft/server/LightEngineGraphSection.java +index 2eb37fb5796d423a70fa7321899a19b6625bbecc..13d067f48647dea63ef1bf3a2a3e0868074ba75f 100644 +--- a/src/main/java/net/minecraft/server/LightEngineGraphSection.java ++++ b/src/main/java/net/minecraft/server/LightEngineGraphSection.java +@@ -13,14 +13,20 @@ public abstract class LightEngineGraphSection extends LightEngineGraph { + + @Override + protected void a(long i, int j, boolean flag) { ++ // Paper start ++ int x = (int) (i >> 42); ++ int y = (int) (i << 44 >> 44); ++ int z = (int) (i << 22 >> 42); ++ // Paper end + for (int k = -1; k <= 1; ++k) { + for (int l = -1; l <= 1; ++l) { + for (int i1 = -1; i1 <= 1; ++i1) { +- long j1 = SectionPosition.a(i, k, l, i1); ++ if (k == 0 && l == 0 && i1 == 0) continue; // Paper ++ long j1 = (((long) (x + k) & 4194303L) << 42) | (((long) (y + l) & 1048575L)) | (((long) (z + i1) & 4194303L) << 20); // Paper + +- if (j1 != i) { ++ //if (j1 != i) { // Paper - checked above + this.b(i, j1, j, flag); +- } ++ //} // Paper + } + } + } +@@ -31,10 +37,15 @@ public abstract class LightEngineGraphSection extends LightEngineGraph { + protected int a(long i, long j, int k) { + int l = k; + ++ // Paper start ++ int x = (int) (i >> 42); ++ int y = (int) (i << 44 >> 44); ++ int z = (int) (i << 22 >> 42); ++ // Paper end + for (int i1 = -1; i1 <= 1; ++i1) { + for (int j1 = -1; j1 <= 1; ++j1) { + for (int k1 = -1; k1 <= 1; ++k1) { +- long l1 = SectionPosition.a(i, i1, j1, k1); ++ long l1 = (((long) (x + i1) & 4194303L) << 42) | (((long) (y + j1) & 1048575L)) | (((long) (z + k1) & 4194303L) << 20); // Paper + + if (l1 == i) { + l1 = Long.MAX_VALUE; +diff --git a/src/main/java/net/minecraft/server/LightEngineLayer.java b/src/main/java/net/minecraft/server/LightEngineLayer.java +index f72ff8495bcf704c15040676b95c51fecb72b73a..faa432779ec70c2c6b5fe7fe3523f171e26d3a5f 100644 +--- a/src/main/java/net/minecraft/server/LightEngineLayer.java ++++ b/src/main/java/net/minecraft/server/LightEngineLayer.java +@@ -11,9 +11,9 @@ public abstract class LightEngineLayer, S e + protected final EnumSkyBlock b; + protected final S c; + private boolean f; +- protected final BlockPosition.MutableBlockPosition d = new BlockPosition.MutableBlockPosition(); ++ protected final BlockPosition.MutableBlockPosition d = new BlockPosition.MutableBlockPosition(); protected final BlockPosition.MutableBlockPosition pos = d; // Paper + private final long[] g = new long[2]; +- private final IBlockAccess[] h = new IBlockAccess[2]; ++ private final IChunkAccess[] h = new IChunkAccess[2]; // Paper + + public LightEngineLayer(ILightAccess ilightaccess, EnumSkyBlock enumskyblock, S s0) { + super(16, 256, 8192); +@@ -33,7 +33,7 @@ public abstract class LightEngineLayer, S e + } + + @Nullable +- private IBlockAccess a(int i, int j) { ++ private IChunkAccess a(int i, int j) { // Paper + long k = ChunkCoordIntPair.pair(i, j); + + for (int l = 0; l < 2; ++l) { +@@ -42,7 +42,7 @@ public abstract class LightEngineLayer, S e + } + } + +- IBlockAccess iblockaccess = this.a.c(i, j); ++ IChunkAccess iblockaccess = (IChunkAccess) this.a.c(i, j); // Paper + + for (int i1 = 1; i1 > 0; --i1) { + this.g[i1] = this.g[i1 - 1]; +@@ -59,37 +59,64 @@ public abstract class LightEngineLayer, S e + Arrays.fill(this.h, (Object) null); + } + +- protected IBlockData a(long i, @Nullable MutableInt mutableint) { +- if (i == Long.MAX_VALUE) { +- if (mutableint != null) { +- mutableint.setValue(0); +- } +- +- return Blocks.AIR.getBlockData(); ++ // Paper start - unused, optimized versions below, comment out to detect changes ++// protected IBlockData a(long i, @Nullable MutableInt mutableint) { ++// if (i == Long.MAX_VALUE) { ++// if (mutableint != null) { ++// mutableint.setValue(0); ++// } ++// ++// return Blocks.AIR.getBlockData(); ++// } else { ++// int j = SectionPosition.a(BlockPosition.b(i)); ++// int k = SectionPosition.a(BlockPosition.d(i)); ++// IBlockAccess iblockaccess = this.a(j, k); ++// ++// if (iblockaccess == null) { ++// if (mutableint != null) { ++// mutableint.setValue(16); ++// } ++// ++// return Blocks.BEDROCK.getBlockData(); ++// } else { ++// this.d.g(i); ++// IBlockData iblockdata = iblockaccess.getType(this.d); ++// boolean flag = iblockdata.o() && iblockdata.g(); ++// ++// if (mutableint != null) { ++// mutableint.setValue(iblockdata.b(this.a.getWorld(), (BlockPosition) this.d)); ++// } ++// ++// return flag ? iblockdata : Blocks.AIR.getBlockData(); ++// } ++// } ++// } ++ // optimized method with less branching for when scenarios arent needed. ++ // avoid using mutable version if can ++ protected final IBlockData getBlockOptimized(int x, int y, int z, MutableInt mutableint) { ++ IChunkAccess iblockaccess = this.a(x >> 4, z >> 4); ++ ++ if (iblockaccess == null) { ++ mutableint.setValue(16); ++ return Blocks.BEDROCK.getBlockData(); + } else { +- int j = SectionPosition.a(BlockPosition.b(i)); +- int k = SectionPosition.a(BlockPosition.d(i)); +- IBlockAccess iblockaccess = this.a(j, k); +- +- if (iblockaccess == null) { +- if (mutableint != null) { +- mutableint.setValue(16); +- } +- +- return Blocks.BEDROCK.getBlockData(); +- } else { +- this.d.g(i); +- IBlockData iblockdata = iblockaccess.getType(this.d); +- boolean flag = iblockdata.o() && iblockdata.g(); +- +- if (mutableint != null) { +- mutableint.setValue(iblockdata.b(this.a.getWorld(), (BlockPosition) this.d)); +- } ++ this.pos.setValues(x, y, z); ++ IBlockData iblockdata = iblockaccess.getType(x, y, z); ++ mutableint.setValue(iblockdata.b(this.a.getWorld(), this.pos)); ++ return iblockdata.o() && iblockdata.g() ? iblockdata : Blocks.AIR.getBlockData(); ++ } ++ } ++ protected final IBlockData getBlockOptimized(int x, int y, int z) { ++ IChunkAccess iblockaccess = this.a(x >> 4, z >> 4); + +- return flag ? iblockdata : Blocks.AIR.getBlockData(); +- } ++ if (iblockaccess == null) { ++ return Blocks.BEDROCK.getBlockData(); ++ } else { ++ IBlockData iblockdata = iblockaccess.getType(x, y, z); ++ return iblockdata.o() && iblockdata.g() ? iblockdata : Blocks.AIR.getBlockData(); + } + } ++ // Paper end + + protected VoxelShape a(IBlockData iblockdata, long i, EnumDirection enumdirection) { + return iblockdata.o() ? iblockdata.a(this.a.getWorld(), this.d.g(i), enumdirection) : VoxelShapes.a(); +@@ -124,8 +151,9 @@ public abstract class LightEngineLayer, S e + return i == Long.MAX_VALUE ? 0 : 15 - this.c.i(i); + } + ++ protected int getNibbleLightInverse(NibbleArray nibblearray, int x, int y, int z) { return 15 - nibblearray.a(x & 15, y & 15, z & 15); } // Paper - x/y/z version of below + protected int a(NibbleArray nibblearray, long i) { +- return 15 - nibblearray.a(SectionPosition.b(BlockPosition.b(i)), SectionPosition.b(BlockPosition.c(i)), SectionPosition.b(BlockPosition.d(i))); ++ return 15 - nibblearray.a((int) (i >> 38) & 15, (int) ((i << 52) >> 52) & 15, (int) ((i << 26) >> 38) & 15); // Paper + } + + @Override +diff --git a/src/main/java/net/minecraft/server/LightEngineSky.java b/src/main/java/net/minecraft/server/LightEngineSky.java +index f0b57784006752e031800a12a1a3c1a5945c636b..3d508fdb0ea86fbe78891113776a1cb312df8dce 100644 +--- a/src/main/java/net/minecraft/server/LightEngineSky.java ++++ b/src/main/java/net/minecraft/server/LightEngineSky.java +@@ -29,21 +29,25 @@ public final class LightEngineSky extends LightEngineLayer= 15) { ++ // Paper start - use x/y/z and optimized block lookup ++ int jx = (int) (j >> 38); ++ int jy = (int) ((j << 52) >> 52); ++ int jz = (int) ((j << 26) >> 38); ++ IBlockData iblockdata = this.getBlockOptimized(jx, jy, jz, mutableint); ++ int blockedLight = mutableint.getValue(); ++ if (blockedLight >= 15) { ++ // Paper end + return 15; + } else { +- int l = BlockPosition.b(i); +- int i1 = BlockPosition.c(i); +- int j1 = BlockPosition.d(i); +- int k1 = BlockPosition.b(j); +- int l1 = BlockPosition.c(j); +- int i2 = BlockPosition.d(j); +- boolean flag = l == k1 && j1 == i2; +- int j2 = Integer.signum(k1 - l); +- int k2 = Integer.signum(l1 - i1); +- int l2 = Integer.signum(i2 - j1); ++ // Paper start - inline math ++ int ix = (int) (i >> 38); ++ int iy = (int) ((i << 52) >> 52); ++ int iz = (int) ((i << 26) >> 38); ++ boolean flag = ix == jx && iz == jz; ++ int j2 = Integer.signum(jx - ix); ++ int k2 = Integer.signum(jy - iy); ++ int l2 = Integer.signum(jz - iz); ++ // Paper end + EnumDirection enumdirection; + + if (i == Long.MAX_VALUE) { +@@ -52,7 +56,7 @@ public final class LightEngineSky extends LightEngineLayer l1; ++ boolean flag1 = i == Long.MAX_VALUE || flag && iy > jy; // Paper rename vars to iy > jy + +- return flag1 && k == 0 && mutableint.getValue() == 0 ? 0 : k + Math.max(1, mutableint.getValue()); ++ return flag1 && k == 0 && blockedLight == 0 ? 0 : k + Math.max(1, blockedLight); // Paper + } + } + } +@@ -92,8 +96,13 @@ public final class LightEngineSky extends LightEngineLayer> 38); ++ int baseY = (int) ((i << 52) >> 52); ++ int baseZ = (int) ((i << 26) >> 38); ++ long k = SectionPosition.blockPosAsSectionLong(baseX, baseY, baseZ); ++ int l = baseY; ++ // Paper end + int i1 = SectionPosition.b(l); + int j1 = SectionPosition.a(l); + int k1; +@@ -103,22 +112,28 @@ public final class LightEngineSky extends LightEngineLayer> 4; ++ int secY = baseY >> 4; ++ int secZ = baseZ >> 4; ++ for (l1 = 0; !((LightEngineStorageSky) this.c).g(SectionPosition.asLong(secX, secY + -l1 - 1, secZ)) && ((LightEngineStorageSky) this.c).a(j1 - l1 - 1); ++l1) { ++ // Paper end + ; + } + + k1 = l1; + } + +- long i2 = BlockPosition.a(i, 0, -1 - k1 * 16, 0); +- long j2 = SectionPosition.e(i2); ++ int newBaseY = baseY + -1 - k1 * 16; // Paper ++ long i2 = BlockPosition.asLong(baseX, newBaseY, baseZ); // Paper ++ long j2 = SectionPosition.blockPosAsSectionLong(baseX, newBaseY, baseZ); // Paper + + if (k == j2 || ((LightEngineStorageSky) this.c).g(j2)) { + this.b(i, i2, j, flag); + } + +- long k2 = BlockPosition.a(i, EnumDirection.UP); +- long l2 = SectionPosition.e(k2); ++ long k2 = BlockPosition.asLong(baseX, baseY + 1, baseZ); // Paper ++ long l2 = SectionPosition.blockPosAsSectionLong(baseX, baseY + 1, baseZ); // Paper + + if (k == l2 || ((LightEngineStorageSky) this.c).g(l2)) { + this.b(i, k2, j, flag); +@@ -133,8 +148,8 @@ public final class LightEngineSky extends LightEngineLayer> 38); ++ int baseY = (int) ((i << 52) >> 52); ++ int baseZ = (int) ((i << 26) >> 38); ++ long j1 = (((long) (baseX >> 4) & 4194303L) << 42) | (((long) (baseY >> 4) & 1048575L)) | (((long) (baseZ >> 4) & 4194303L) << 20); ++ NibbleArray nibblearray = this.c.updating.getUpdatingOptimized(j1); ++ // Paper end + EnumDirection[] aenumdirection = LightEngineSky.e; + int k1 = aenumdirection.length; + + for (int l1 = 0; l1 < k1; ++l1) { + EnumDirection enumdirection = aenumdirection[l1]; +- long i2 = BlockPosition.a(i, enumdirection); +- long j2 = SectionPosition.e(i2); ++ // Paper start ++ int newX = baseX + enumdirection.getAdjacentX(); ++ int newY = baseY + enumdirection.getAdjacentY(); ++ int newZ = baseZ + enumdirection.getAdjacentZ(); ++ long i2 = BlockPosition.asLong(newX, newY, newZ); ++ long j2 = SectionPosition.blockPosAsSectionLong(newX, newY, newZ); ++ // Paper end + NibbleArray nibblearray1; + + if (j1 == j2) { + nibblearray1 = nibblearray; + } else { +- nibblearray1 = ((LightEngineStorageSky) this.c).a(j2, true); ++ nibblearray1 = ((LightEngineStorageSky) this.c).updating.getUpdatingOptimized(j2); // Paper + } + + if (nibblearray1 != null) { + if (i2 != j) { +- int k2 = this.b(i2, i, this.a(nibblearray1, i2)); ++ int k2 = this.b(i2, i, this.getNibbleLightInverse(nibblearray1, newX, newY, newZ)); // Paper + + if (l > k2) { + l = k2; +@@ -206,7 +231,7 @@ public final class LightEngineSky extends LightEngineLayer> e + protected final LongSet c = new LongOpenHashSet(); + protected final LongSet d = new LongOpenHashSet(); + protected volatile M e_visible; protected final Object visibleUpdateLock = new Object(); // Paper - diff on change, should be "visible" - force compile fail on usage change +- protected final M f; // Paper - diff on change, should be "updating" ++ protected final M f; protected final M updating; // Paper - diff on change, should be "updating" + protected final LongSet g = new LongOpenHashSet(); +- protected final LongSet h = new LongOpenHashSet(); ++ protected final LongSet h = new LongOpenHashSet(); LongSet dirty = h; // Paper - OBFHELPER + protected final Long2ObjectMap i = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap()); + private final LongSet n = new LongOpenHashSet(); + private final LongSet o = new LongOpenHashSet(); + protected volatile boolean j; + + protected LightEngineStorage(EnumSkyBlock enumskyblock, ILightAccess ilightaccess, M m0) { +- super(3, 16, 256); ++ super(3, 256, 256); // Paper - bump expected size of level sets to improve collisions and reduce rehashing (seen a lot of it) + this.l = enumskyblock; + this.m = ilightaccess; +- this.f = m0; ++ this.f = m0; updating = m0; // Paper + this.e_visible = m0.b(); // Paper - avoid copying light data + this.e_visible.d(); // Paper - avoid copying light data + } + +- protected boolean g(long i) { +- return this.a(i, true) != null; ++ protected final boolean g(long i) { // Paper - final to help inlining ++ return this.updating.getUpdatingOptimized(i) != null; // Paper - inline to avoid branching + } + + @Nullable + protected NibbleArray a(long i, boolean flag) { + // Paper start - avoid copying light data + if (flag) { +- return this.a(this.f, i); ++ return this.updating.getUpdatingOptimized(i); + } else { + synchronized (this.visibleUpdateLock) { +- return this.a(this.e_visible, i); ++ return this.e_visible.lookup.apply(i); + } + } + // Paper end - avoid copying light data + } + + @Nullable +- protected NibbleArray a(M m0, long i) { ++ protected final NibbleArray a(M m0, long i) { // Paper + return m0.c(i); + } + +@@ -69,27 +69,56 @@ public abstract class LightEngineStorage> e + protected abstract int d(long i); + + protected int i(long i) { +- long j = SectionPosition.e(i); +- NibbleArray nibblearray = this.a(j, true); ++ // Paper start - reuse and inline math, use Optimized Updating path ++ final int x = (int) (i >> 38); ++ final int y = (int) ((i << 52) >> 52); ++ final int z = (int) ((i << 26) >> 38); ++ NibbleArray nibblearray = this.updating.getUpdatingOptimized((((long) (x >> 4) & 4194303L) << 42) | (((long) (y >> 4) & 1048575L)) | (((long) (z >> 4) & 4194303L) << 20)); ++ // BUG: Sometimes returns null and crashes, try to recover, but to prevent crash just return no light. ++ if (nibblearray == null) { ++ nibblearray = this.e_visible.lookup.apply((((long) (x >> 4) & 4194303L) << 42) | (((long) (y >> 4) & 1048575L)) | (((long) (z >> 4) & 4194303L) << 20)); ++ } ++ if (nibblearray == null) { ++ System.err.println("Null nibble, preventing crash " + BlockPosition.fromLong(i)); ++ return 0; ++ } + +- return nibblearray.a(SectionPosition.b(BlockPosition.b(i)), SectionPosition.b(BlockPosition.c(i)), SectionPosition.b(BlockPosition.d(i))); ++ return nibblearray.a(x & 15, y & 15, z & 15); // Paper - inline operations ++ // Paper end + } + + protected void b(long i, int j) { +- long k = SectionPosition.e(i); ++ // Paper start - cache part of the math done in loop below ++ int x = (int) (i >> 38); ++ int y = (int) ((i << 52) >> 52); ++ int z = (int) ((i << 26) >> 38); ++ long k = SectionPosition.asLong(x >> 4, y >> 4, z >> 4); ++ // Paper end + + if (this.g.add(k)) { + this.f.a(k); + } + + NibbleArray nibblearray = this.a(k, true); +- +- nibblearray.a(SectionPosition.b(BlockPosition.b(i)), SectionPosition.b(BlockPosition.c(i)), SectionPosition.b(BlockPosition.d(i)), j); +- +- for (int l = -1; l <= 1; ++l) { +- for (int i1 = -1; i1 <= 1; ++i1) { +- for (int j1 = -1; j1 <= 1; ++j1) { +- this.h.add(SectionPosition.e(BlockPosition.a(i, i1, j1, l))); ++ nibblearray.a(x & 15, y & 15, z & 15, j); // Paper - use already calculated x/y/z ++ ++ // Paper start - credit to JellySquid for a major optimization here: ++ /* ++ * An extremely important optimization is made here in regards to adding items to the pending notification set. The ++ * original implementation attempts to add the coordinate of every chunk which contains a neighboring block position ++ * even though a huge number of loop iterations will simply map to block positions within the same updating chunk. ++ * ++ * Our implementation here avoids this by pre-calculating the min/max chunk coordinates so we can iterate over only ++ * the relevant chunk positions once. This reduces what would always be 27 iterations to just 1-8 iterations. ++ * ++ * @reason Use faster implementation ++ * @author JellySquid ++ */ ++ for (int z2 = (z - 1) >> 4; z2 <= (z + 1) >> 4; ++z2) { ++ for (int x2 = (x - 1) >> 4; x2 <= (x + 1) >> 4; ++x2) { ++ for (int y2 = (y - 1) >> 4; y2 <= (y + 1) >> 4; ++y2) { ++ this.dirty.add(SectionPosition.asLong(x2, y2, z2)); ++ // Paper end + } + } + } +@@ -121,17 +150,23 @@ public abstract class LightEngineStorage> e + } + + if (k >= 2 && j != 2) { +- if (this.o.contains(i)) { +- this.o.remove(i); +- } else { ++ if (!this.o.remove(i)) { // Paper - remove useless contains - credit to JellySquid ++ //this.o.remove(i); // Paper ++ //} else { // Pape + this.f.a(i, this.j(i)); + this.g.add(i); + this.k(i); + +- for (int l = -1; l <= 1; ++l) { +- for (int i1 = -1; i1 <= 1; ++i1) { +- for (int j1 = -1; j1 <= 1; ++j1) { +- this.h.add(SectionPosition.e(BlockPosition.a(i, i1, j1, l))); ++ // Paper start - reuse x/y/z and only notify valid chunks - Credit to JellySquid (See above method for notes) ++ int x = (int) (i >> 38); ++ int y = (int) ((i << 52) >> 52); ++ int z = (int) ((i << 26) >> 38); ++ ++ for (int z2 = (z - 1) >> 4; z2 <= (z + 1) >> 4; ++z2) { ++ for (int x2 = (x - 1) >> 4; x2 <= (x + 1) >> 4; ++x2) { ++ for (int y2 = (y - 1) >> 4; y2 <= (y + 1) >> 4; ++y2) { ++ this.dirty.add(SectionPosition.asLong(x2, y2, z2)); ++ // Paper end + } + } + } +@@ -157,9 +192,9 @@ public abstract class LightEngineStorage> e + return SectionPosition.e(j) == i; + }); + } else { +- int j = SectionPosition.c(SectionPosition.b(i)); +- int k = SectionPosition.c(SectionPosition.c(i)); +- int l = SectionPosition.c(SectionPosition.d(i)); ++ int j = (int) (i >> 42) << 4; // Paper - inline ++ int k = (int) (i << 44 >> 44) << 4; // Paper - inline ++ int l = (int) (i << 22 >> 42) << 4; // Paper - inline + + for (int i1 = 0; i1 < 16; ++i1) { + for (int j1 = 0; j1 < 16; ++j1) { +@@ -186,7 +221,7 @@ public abstract class LightEngineStorage> e + NibbleArray nibblearray; + + while (longiterator.hasNext()) { +- i = (Long) longiterator.next(); ++ i = longiterator.nextLong(); // Paper + this.a(lightenginelayer, i); + NibbleArray nibblearray1 = (NibbleArray) this.i.remove(i); + +@@ -204,48 +239,56 @@ public abstract class LightEngineStorage> e + longiterator = this.o.iterator(); + + while (longiterator.hasNext()) { +- i = (Long) longiterator.next(); ++ i = longiterator.nextLong(); // Paper + this.l(i); + } + + this.o.clear(); + this.j = false; +- ObjectIterator objectiterator = this.i.long2ObjectEntrySet().iterator(); ++ ObjectIterator> objectiterator = Long2ObjectMaps.fastIterator(this.i); // Paper + + Entry entry; + long j; + ++ NibbleArray test = null; // Paper ++ LongSet propagating = new LongOpenHashSet(); // Paper - credit JellySquid for idea to move this up + while (objectiterator.hasNext()) { + entry = (Entry) objectiterator.next(); + j = entry.getLongKey(); +- if (this.g(j)) { ++ if ((test = this.updating.getUpdatingOptimized(j)) != null) { // Paper - dont look up nibble twice + nibblearray = (NibbleArray) entry.getValue(); +- if (this.f.c(j) != nibblearray) { ++ if (test != nibblearray) { // Paper + this.a(lightenginelayer, j); + this.f.a(j, nibblearray); + this.g.add(j); + } ++ if (!flag1) propagating.add(j); // Paper ++ objectiterator.remove(); // Paper + } + } + + this.f.c(); +- if (!flag1) { +- longiterator = this.i.keySet().iterator(); ++ if (!flag1) {// Paper - diff on change, change propagating add a few lines up ++ longiterator = propagating.iterator(); // Paper + + while (longiterator.hasNext()) { +- i = (Long) longiterator.next(); +- if (this.g(i)) { +- int k = SectionPosition.c(SectionPosition.b(i)); +- int l = SectionPosition.c(SectionPosition.c(i)); +- int i1 = SectionPosition.c(SectionPosition.d(i)); ++ // Paper start ++ i = longiterator.nextLong(); ++ if (true) { // don't check hasLight, this iterator is filtered already ++ int baseX = (int) (i >> 42); ++ int baseY = (int) (i << 44 >> 44); ++ int baseZ = (int) (i << 22 >> 42); ++ int k = baseX << 4; ++ int l = baseY << 4; ++ int i1 = baseZ << 4; ++ // Paper end + EnumDirection[] aenumdirection = LightEngineStorage.k; + int j1 = aenumdirection.length; + + for (int k1 = 0; k1 < j1; ++k1) { + EnumDirection enumdirection = aenumdirection[k1]; +- long l1 = SectionPosition.a(i, enumdirection); +- +- if (!this.i.containsKey(l1) && this.g(l1)) { ++ long l1 = SectionPosition.asLong(baseX + enumdirection.getAdjacentX(), baseY + enumdirection.getAdjacentY(), baseZ + enumdirection.getAdjacentZ()); // Paper - avoid unpacking ++ if (!propagating.contains(l1) && this.g(l1)) { // Paper - use propagating + for (int i2 = 0; i2 < 16; ++i2) { + for (int j2 = 0; j2 < 16; ++j2) { + long k2; +@@ -287,6 +330,8 @@ public abstract class LightEngineStorage> e + } + } + ++ // Paper start - moved above - Credit JellySquid for idea ++ /* + objectiterator = this.i.long2ObjectEntrySet().iterator(); + + while (objectiterator.hasNext()) { +@@ -295,7 +340,8 @@ public abstract class LightEngineStorage> e + if (this.g(j)) { + objectiterator.remove(); + } +- } ++ }*/ ++ // Paper end + + } + } +diff --git a/src/main/java/net/minecraft/server/LightEngineStorageArray.java b/src/main/java/net/minecraft/server/LightEngineStorageArray.java +index d5702b22f06ba4ad787fe2fcf788c3d4d147c927..5e397b9195b2b86c76c0c7cc4102ab4eef46071a 100644 +--- a/src/main/java/net/minecraft/server/LightEngineStorageArray.java ++++ b/src/main/java/net/minecraft/server/LightEngineStorageArray.java +@@ -43,6 +43,25 @@ public abstract class LightEngineStorageArray> 38); ++ int baseY = (int) ((i << 52) >> 52); ++ int baseZ = (int) ((i << 26) >> 38); ++ long j = (((long) (baseX >> 4) & 4194303L) << 42) | (((long) (baseY >> 4) & 1048575L)) | (((long) (baseZ >> 4) & 4194303L) << 20); ++ // Paper end + NibbleArray nibblearray = this.a(j, false); + +- return nibblearray == null ? 0 : nibblearray.a(SectionPosition.b(BlockPosition.b(i)), SectionPosition.b(BlockPosition.c(i)), SectionPosition.b(BlockPosition.d(i))); ++ return nibblearray == null ? 0 : nibblearray.a(baseX & 15, baseY & 15, baseZ & 15); // Paper + } + + public static final class a extends LightEngineStorageArray { +diff --git a/src/main/java/net/minecraft/server/LightEngineStorageSky.java b/src/main/java/net/minecraft/server/LightEngineStorageSky.java +index 097f58e9ac3f4096d3b9dad75b6ebe76021fa92c..5ccd81bd0d49052fe84d4f34e29774f0cc2dd732 100644 +--- a/src/main/java/net/minecraft/server/LightEngineStorageSky.java ++++ b/src/main/java/net/minecraft/server/LightEngineStorageSky.java +@@ -22,7 +22,12 @@ public class LightEngineStorageSky extends LightEngineStorage> 38); ++ int baseY = (int) ((i << 52) >> 52); ++ int baseZ = (int) ((i << 26) >> 38); ++ long j = (((long) (baseX >> 4) & 4194303L) << 42) | (((long) (baseY >> 4) & 1048575L)) | (((long) (baseZ >> 4) & 4194303L) << 20); ++ // Paper end + int k = SectionPosition.c(j); + synchronized (this.visibleUpdateLock) { // Paper - avoid copying light data + LightEngineStorageSky.a lightenginestoragesky_a = (LightEngineStorageSky.a) this.e_visible; // Paper - avoid copying light data - must be after lock acquire +@@ -43,7 +48,7 @@ public class LightEngineStorageSky extends LightEngineStorage> 52) & 15, (int) baseZ & 15); // Paper - y changed above + } else { + return 15; + } +@@ -162,7 +167,7 @@ public class LightEngineStorageSky extends LightEngineStorage> 42) << 4; // Paper ++ int baseY = (int) (i << 44 >> 44) << 4; // Paper ++ int baseZ = (int) (i << 22 >> 42) << 4; // Paper + j = this.c(i); + if (j != 2 && !this.n.contains(i) && this.l.add(i)) { + int l; +@@ -197,10 +205,10 @@ public class LightEngineStorageSky extends LightEngineStorage> 42) << 4; // Paper ++ int baseY = (int) (i << 44 >> 44) << 4; // Paper ++ int baseZ = (int) (i << 22 >> 42) << 4; // Paper + if (this.l.remove(i) && this.g(i)) { + for (j = 0; j < 16; ++j) { + for (k = 0; k < 16; ++k) { +- long l3 = BlockPosition.a(SectionPosition.c(SectionPosition.b(i)) + j, SectionPosition.c(SectionPosition.c(i)) + 16 - 1, SectionPosition.c(SectionPosition.d(i)) + k); ++ long l3 = BlockPosition.a(baseX + j, baseY + 16 - 1, baseZ + k); // Paper + + lightenginelayer.a(Long.MAX_VALUE, l3, 15, false); + } +diff --git a/src/main/java/net/minecraft/server/LightEngineThreaded.java b/src/main/java/net/minecraft/server/LightEngineThreaded.java +index 8776799de033f02b0f87e9ea7e4a4ce912e94dd4..72cc711d6c2645aed44f208ee44f8702d64c5af8 100644 +--- a/src/main/java/net/minecraft/server/LightEngineThreaded.java ++++ b/src/main/java/net/minecraft/server/LightEngineThreaded.java +@@ -15,8 +15,70 @@ public class LightEngineThreaded extends LightEngine implements AutoCloseable { + + private static final Logger LOGGER = LogManager.getLogger(); + private final ThreadedMailbox b; +- private final ObjectList> c = new ObjectArrayList(); +- private final PlayerChunkMap d; ++ // Paper start - add urgent queue, switch to ArrayDeque ++ private long nextNonUrgent = 0; ++ private boolean shouldPollNonUrgent() { ++ return urgent.isEmpty() && !c.isEmpty() && (this.c.size() >= this.f || System.nanoTime() > nextNonUrgent); ++ } ++ ++ private boolean shouldPollUrgent() { ++ return (super.a() || !urgent.isEmpty()); ++ } ++ ++ private IntSupplier getChunkPrioritySupplier(ChunkCoordIntPair coords) { ++ return getChunkMap().getPrioritySupplier(coords.pair()); ++ } ++ private static final int MAX_PRIORITIES = PlayerChunkMap.GOLDEN_TICKET + 2; ++ private static class LightQueueBucket extends java.util.ArrayDeque> { ++ public LightQueueBucket() { ++ super(64); ++ } ++ } ++ // Retain the chunks priority level for queued light tasks ++ private static class LightQueue { ++ ++ private int size = 0; ++ private int lowestPriority = MAX_PRIORITIES; ++ private final LightQueueBucket[] buckets = new LightQueueBucket[MAX_PRIORITIES]; ++ ++ private LightQueue() { ++ for (int i = 0; i < buckets.length; i++) { ++ buckets[i] = new LightQueueBucket(); ++ } ++ } ++ ++ public final void add(int priority, LightEngineThreaded.Update type, Runnable run) { ++ this.size++; ++ if (lowestPriority > priority) { ++ lowestPriority = priority; ++ } ++ this.buckets[priority].add(new Pair<>(type, run)); ++ } ++ ++ public final boolean isEmpty() { ++ return this.size == 0; ++ } ++ ++ public final int size() { ++ return this.size; ++ } ++ ++ public Pair poll() { ++ for (; lowestPriority < MAX_PRIORITIES; lowestPriority++) { ++ Pair entry = buckets[lowestPriority].pollFirst(); ++ if (entry != null) { ++ this.size--; ++ return entry; ++ } ++ } ++ return null; ++ } ++ } ++ ++ private final LightQueue urgent = new LightQueue(); ++ private final LightQueue c = new LightQueue(); ++ // Paper end ++ private final PlayerChunkMap d; private PlayerChunkMap getChunkMap() { return d; } // Paper - OBFHELPER + private final Mailbox> e; + private volatile int f = 5; + private final AtomicBoolean g = new AtomicBoolean(); +@@ -110,11 +172,14 @@ public class LightEngineThreaded extends LightEngine implements AutoCloseable { + } + + private void a(int i, int j, IntSupplier intsupplier, LightEngineThreaded.Update lightenginethreaded_update, Runnable runnable) { ++ // Paper start ++ scheduleLightTask(i, j, intsupplier, lightenginethreaded_update, runnable, false); ++ } ++ private void scheduleLightTask(int i, int j, IntSupplier intsupplier, LightEngineThreaded.Update lightenginethreaded_update, Runnable runnable, boolean urgent) { + this.e.a(ChunkTaskQueueSorter.a(() -> { // Paper - decompile error +- this.c.add(Pair.of(lightenginethreaded_update, runnable)); +- if (this.c.size() >= this.f) { +- this.b(); +- } ++ (urgent ? this.urgent : this.c).add(intsupplier.getAsInt(), lightenginethreaded_update, runnable); ++ if (shouldPollUrgent() || shouldPollNonUrgent()) queueUpdate(); ++ // Paper end + + }, ChunkCoordIntPair.pair(i, j), intsupplier)); + } +@@ -134,7 +199,7 @@ public class LightEngineThreaded extends LightEngine implements AutoCloseable { + ChunkCoordIntPair chunkcoordintpair = ichunkaccess.getPos(); + + ichunkaccess.b(false); +- this.a(chunkcoordintpair.x, chunkcoordintpair.z, LightEngineThreaded.Update.PRE_UPDATE, SystemUtils.a(() -> { ++ this.scheduleLightTask(chunkcoordintpair.x, chunkcoordintpair.z, getChunkPrioritySupplier(chunkcoordintpair), LightEngineThreaded.Update.PRE_UPDATE, SystemUtils.a(() -> { // Paper + ChunkSection[] achunksection = ichunkaccess.getSections(); + + for (int i = 0; i < 16; ++i) { +@@ -155,51 +220,58 @@ public class LightEngineThreaded extends LightEngine implements AutoCloseable { + this.d.c(chunkcoordintpair); + }, () -> { + return "lightChunk " + chunkcoordintpair + " " + flag; +- })); ++ }), true); // Paper - urgent flag + return CompletableFuture.supplyAsync(() -> { + ichunkaccess.b(true); + super.b(chunkcoordintpair, false); + return ichunkaccess; + }, (runnable) -> { +- this.a(chunkcoordintpair.x, chunkcoordintpair.z, LightEngineThreaded.Update.POST_UPDATE, runnable); ++ this.scheduleLightTask(chunkcoordintpair.x, chunkcoordintpair.z, getChunkPrioritySupplier(chunkcoordintpair), LightEngineThreaded.Update.POST_UPDATE, runnable, true); // Paper ++ queueUpdate(); // Paper + }); + } + + public void queueUpdate() { +- if ((!this.c.isEmpty() || super.a()) && this.g.compareAndSet(false, true)) { ++ if ((shouldPollUrgent() || shouldPollNonUrgent()) && this.g.compareAndSet(false, true)) { // Paper - level check is now in shouldPollUrgent + this.b.a((() -> { // Paper - decompile error +- this.b(); ++ // Paper start ++ if (shouldPollUrgent()) { ++ do { ++ this.runQueue(true); ++ } while (shouldPollUrgent()); ++ } else if (shouldPollNonUrgent()) this.runQueue(false); // don't loop non urgent as urgent might come in ++ // Paper end + this.g.set(false); ++ queueUpdate(); // Paper - if we still have work to do, do it! + })); + } + + } + + private void b() { +- int i = Math.min(this.c.size(), this.f); +- ObjectListIterator> objectlistiterator = this.c.iterator(); +- +- Pair pair; +- int j; +- +- for (j = 0; objectlistiterator.hasNext() && j < i; ++j) { +- pair = (Pair) objectlistiterator.next(); +- if (pair.getFirst() == LightEngineThreaded.Update.PRE_UPDATE) { +- ((Runnable) pair.getSecond()).run(); ++ // Paper start - replace impl, use more effecient deque, avoid single removes (iterator.remove() which does a lot of copying) ++ runQueue(!this.urgent.isEmpty()); ++ } ++ private void runQueue(boolean urgent) { ++ LightQueue col = urgent ? this.urgent : c; ++ java.util.List> pre = new java.util.ArrayList<>(); ++ java.util.List> post = new java.util.ArrayList<>(); ++ int i = Math.min(col.size(), 8); // process small batches so chunks can progress without waiting for everything ++ Pair pair; ++ while (i-- > 0 && (pair = col.poll()) != null) { ++ if (pair.getFirst() == Update.PRE_UPDATE) { ++ pre.add(pair); ++ } else { ++ post.add(pair); + } + } + +- objectlistiterator.back(j); ++ pre.forEach(entry -> entry.getSecond().run()); + super.a(Integer.MAX_VALUE, true, true); ++ post.forEach(entry -> entry.getSecond().run()); + +- for (j = 0; objectlistiterator.hasNext() && j < i; ++j) { +- pair = (Pair) objectlistiterator.next(); +- if (pair.getFirst() == LightEngineThreaded.Update.POST_UPDATE) { +- ((Runnable) pair.getSecond()).run(); +- } +- +- objectlistiterator.remove(); +- } ++ if (!urgent && this.c.isEmpty()) nextNonUrgent = System.nanoTime() + (50 * 1000000); ++ // Paper end + + } + +diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java +index c5b5aaf4dd087dc87ecef08be4c8170f10e96b54..a9b9719ecd0c4b0d0dcf58f3374680e55a819470 100644 +--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java ++++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java +@@ -630,6 +630,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + // Paper end + } + ++ protected final IntSupplier getPrioritySupplier(long i) { return c(i); } // Paper - OBFHELPER + protected IntSupplier c(long i) { + return () -> { + PlayerChunk playerchunk = this.getVisibleChunk(i);