diff --git a/Spigot-Server-Patches/Anti-Xray.patch b/Spigot-Server-Patches/Anti-Xray.patch index 4d7eacafe..f3343c55b 100644 --- a/Spigot-Server-Patches/Anti-Xray.patch +++ b/Spigot-Server-Patches/Anti-Xray.patch @@ -1079,7 +1079,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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 @@ -0,0 +0,0 @@ public class ChunkSection { return this.blockIds; } diff --git a/Spigot-Server-Patches/Implement-Chunk-Priority-Urgency-System-for-Chunks.patch b/Spigot-Server-Patches/Implement-Chunk-Priority-Urgency-System-for-Chunks.patch index 486aa4000..1ea230175 100644 --- a/Spigot-Server-Patches/Implement-Chunk-Priority-Urgency-System-for-Chunks.patch +++ b/Spigot-Server-Patches/Implement-Chunk-Priority-Urgency-System-for-Chunks.patch @@ -392,32 +392,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 for (int i = 0; i < this.inventory.getSize(); ++i) { ItemStack itemstack = this.inventory.getItem(i); -diff --git a/src/main/java/net/minecraft/server/LightEngineThreaded.java b/src/main/java/net/minecraft/server/LightEngineThreaded.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/LightEngineThreaded.java -+++ b/src/main/java/net/minecraft/server/LightEngineThreaded.java -@@ -0,0 +0,0 @@ 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(() -> { -+ // 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) { -@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/MCUtil.java diff --git a/Spigot-Server-Patches/Optimise-random-block-ticking.patch b/Spigot-Server-Patches/Optimise-random-block-ticking.patch index aa303c921..28e598f7b 100644 --- a/Spigot-Server-Patches/Optimise-random-block-ticking.patch +++ b/Spigot-Server-Patches/Optimise-random-block-ticking.patch @@ -135,7 +135,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 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; diff --git a/Spigot-Server-Patches/Optimize-Bit-Operations-by-inlining.patch b/Spigot-Server-Patches/Optimize-Bit-Operations-by-inlining.patch new file mode 100644 index 000000000..36fa57e57 --- /dev/null +++ b/Spigot-Server-Patches/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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/BlockPosition.java ++++ b/src/main/java/net/minecraft/server/BlockPosition.java +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/SectionPosition.java ++++ b/src/main/java/net/minecraft/server/SectionPosition.java +@@ -0,0 +0,0 @@ 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) { +@@ -0,0 +0,0 @@ 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) { +@@ -0,0 +0,0 @@ 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) { +@@ -0,0 +0,0 @@ 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) { +@@ -0,0 +0,0 @@ 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) { +@@ -0,0 +0,0 @@ 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) { +@@ -0,0 +0,0 @@ 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() { +@@ -0,0 +0,0 @@ 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/Optimize-Light-Engine.patch b/Spigot-Server-Patches/Optimize-Light-Engine.patch new file mode 100644 index 000000000..da2d2e06a --- /dev/null +++ b/Spigot-Server-Patches/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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/Block.java ++++ b/src/main/java/net/minecraft/server/Block.java +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java ++++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/IBlockData.java ++++ b/src/main/java/net/minecraft/server/IBlockData.java +@@ -0,0 +0,0 @@ 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); +@@ -0,0 +0,0 @@ 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() { +@@ -0,0 +0,0 @@ public class IBlockData extends BlockDataAbstract implements + return this.c == null || this.c.h; + } + +- public boolean g() { ++ public final boolean g() { // Paper + return this.e; + } + +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/LightEngineBlock.java ++++ b/src/main/java/net/minecraft/server/LightEngineBlock.java +@@ -0,0 +0,0 @@ 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; +@@ -0,0 +0,0 @@ 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 + } + } + } +@@ -0,0 +0,0 @@ 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); +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/LightEngineGraphSection.java ++++ b/src/main/java/net/minecraft/server/LightEngineGraphSection.java +@@ -0,0 +0,0 @@ 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 + } + } + } +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/LightEngineLayer.java ++++ b/src/main/java/net/minecraft/server/LightEngineLayer.java +@@ -0,0 +0,0 @@ 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); +@@ -0,0 +0,0 @@ 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) { +@@ -0,0 +0,0 @@ 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]; +@@ -0,0 +0,0 @@ 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(); +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/LightEngineSky.java ++++ b/src/main/java/net/minecraft/server/LightEngineSky.java +@@ -0,0 +0,0 @@ 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) { +@@ -0,0 +0,0 @@ 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 + } + } + } +@@ -0,0 +0,0 @@ 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; +@@ -0,0 +0,0 @@ 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); +@@ -0,0 +0,0 @@ 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; +@@ -0,0 +0,0 @@ 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); + } + +@@ -0,0 +0,0 @@ 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 + } + } + } +@@ -0,0 +0,0 @@ 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 + } + } + } +@@ -0,0 +0,0 @@ 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) { +@@ -0,0 +0,0 @@ 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); + +@@ -0,0 +0,0 @@ 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; +@@ -0,0 +0,0 @@ public abstract class LightEngineStorage> e + } + } + ++ // Paper start - moved above - Credit JellySquid for idea ++ /* + objectiterator = this.i.long2ObjectEntrySet().iterator(); + + while (objectiterator.hasNext()) { +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/LightEngineStorageArray.java ++++ b/src/main/java/net/minecraft/server/LightEngineStorageArray.java +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/LightEngineStorageSky.java ++++ b/src/main/java/net/minecraft/server/LightEngineStorageSky.java +@@ -0,0 +0,0 @@ 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 +@@ -0,0 +0,0 @@ public class LightEngineStorageSky extends LightEngineStorage> 52) & 15, (int) baseZ & 15); // Paper - y changed above + } else { + return 15; + } +@@ -0,0 +0,0 @@ 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; +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/LightEngineThreaded.java ++++ b/src/main/java/net/minecraft/server/LightEngineThreaded.java +@@ -0,0 +0,0 @@ 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(); +@@ -0,0 +0,0 @@ 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)); + } +@@ -0,0 +0,0 @@ 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) { +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java ++++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java +@@ -0,0 +0,0 @@ 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); diff --git a/Spigot-Server-Patches/Optimize-NibbleArray-to-use-pooled-buffers.patch b/Spigot-Server-Patches/Optimize-NibbleArray-to-use-pooled-buffers.patch index 8da92a2eb..eb07ae7bf 100644 --- a/Spigot-Server-Patches/Optimize-NibbleArray-to-use-pooled-buffers.patch +++ b/Spigot-Server-Patches/Optimize-NibbleArray-to-use-pooled-buffers.patch @@ -40,8 +40,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 protected void a(LightEngineLayer lightenginelayer, long i) { @@ -0,0 +0,0 @@ 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 @@ -59,7 +62,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.data.queueUpdate(i, ((NibbleArray) this.data.getUpdating(i)).b()); // Paper - avoid copying light data + NibbleArray updating = this.data.getUpdating(i); // Paper - pool nibbles + this.data.queueUpdate(i, new NibbleArray().markPoolSafe(updating.getCloneIfSet())); // Paper - avoid copying light data - pool safe clone -+ if (updating.cleaner != null) updating.cleaner.run(); // Paper ++ if (updating.cleaner != null) MCUtil.scheduleTask(2, updating.cleaner); // Paper - delay clean incase anything holding ref was still using it this.c(); } @@ -262,7 +265,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + 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/Optimize-isValidLocation-getType-and-getBlockData-fo.patch b/Spigot-Server-Patches/Optimize-isValidLocation-getType-and-getBlockData-fo.patch index c94911f65..6e2c4a75f 100644 --- a/Spigot-Server-Patches/Optimize-isValidLocation-getType-and-getBlockData-fo.patch +++ b/Spigot-Server-Patches/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. @@ -47,28 +48,60 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/ChunkEmpty.java ++++ b/src/main/java/net/minecraft/server/ChunkEmpty.java +@@ -0,0 +0,0 @@ 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); + }); + +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/ChunkSection.java +++ b/src/main/java/net/minecraft/server/ChunkSection.java @@ -0,0 +0,0 @@ public class ChunkSection { - private short nonEmptyBlockCount; + + 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,6 +109,87 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public ChunkSection(int i) { this(i, (short) 0, (short) 0, (short) 0); +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/DataPaletteBlock.java ++++ b/src/main/java/net/minecraft/server/DataPaletteBlock.java +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/IChunkAccess.java ++++ b/src/main/java/net/minecraft/server/IChunkAccess.java +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/ProtoChunk.java ++++ b/src/main/java/net/minecraft/server/ProtoChunk.java +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/ProtoChunkExtension.java ++++ b/src/main/java/net/minecraft/server/ProtoChunkExtension.java +@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/World.java diff --git a/Spigot-Server-Patches/Reduce-MutableInt-allocations-from-light-engine.patch b/Spigot-Server-Patches/Reduce-MutableInt-allocations-from-light-engine.patch index f0f1dcb60..4260a55e6 100644 --- a/Spigot-Server-Patches/Reduce-MutableInt-allocations-from-light-engine.patch +++ b/Spigot-Server-Patches/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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/LightEngineBlock.java +++ b/src/main/java/net/minecraft/server/LightEngineBlock.java +@@ -0,0 +0,0 @@ public final class LightEngineBlock extends LightEngineLayer= 15) { -@@ -0,0 +0,0 @@ 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) { -@@ -0,0 +0,0 @@ public final class LightEngineSky extends LightEngineLayer