diff --git a/Spigot-Server-Patches/Avoid-hopper-searches-if-there-are-no-items.patch b/Spigot-Server-Patches/Avoid-hopper-searches-if-there-are-no-items.patch index c9f719e9d4..c1f9515739 100644 --- a/Spigot-Server-Patches/Avoid-hopper-searches-if-there-are-no-items.patch +++ b/Spigot-Server-Patches/Avoid-hopper-searches-if-there-are-no-items.patch @@ -18,16 +18,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java @@ -0,0 +0,0 @@ public class Chunk { - // Paper start - Asynchronous light updates - public AtomicInteger pendingLightUpdates = new AtomicInteger(); - public long lightUpdateTime; + protected gnu.trove.map.hash.TObjectIntHashMap<Class> entityCount = new gnu.trove.map.hash.TObjectIntHashMap<Class>(); // Spigot + public int lightUpdates; // Paper - Number of queued light updates for this chunk + ++ // Paper start + // Track the number of minecarts and items + // Keep this synced with entitySlices.add() and entitySlices.remove() + private final int[] itemCounts = new int[16]; + private final int[] inventoryEntityCounts = new int[16]; - // Paper end - ++ // Paper end ++ // CraftBukkit start - Neighbor loaded cache for chunk lighting and entity ticking + private int neighbors = 0x1 << 12; + @@ -0,0 +0,0 @@ public class Chunk { entity.ac = k; entity.ad = this.locZ; diff --git a/Spigot-Server-Patches/Change-implementation-of-tile-entity-removal-list.patch b/Spigot-Server-Patches/Change-implementation-of-tile-entity-removal-list.patch index d4148ea254..0218e03cf6 100644 --- a/Spigot-Server-Patches/Change-implementation-of-tile-entity-removal-list.patch +++ b/Spigot-Server-Patches/Change-implementation-of-tile-entity-removal-list.patch @@ -8,15 +8,18 @@ diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/m index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java -@@ -0,0 +0,0 @@ import org.bukkit.generator.ChunkGenerator; - import java.util.concurrent.ExecutorService; - import java.util.concurrent.Executors; - import java.util.HashMap; +@@ -0,0 +0,0 @@ import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; + import org.bukkit.generator.ChunkGenerator; + // CraftBukkit end + ++// Paper start +import java.util.Set; +import com.google.common.collect.Sets; - import com.google.common.util.concurrent.ThreadFactoryBuilder; - // Paper end ++// Paper end ++ + public abstract class World implements IBlockAccess { + private int a = 63; @@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess { } }; diff --git a/Spigot-Server-Patches/Configurable-async-light-updates.patch b/Spigot-Server-Patches/Configurable-async-light-updates.patch deleted file mode 100644 index d9bff60b85..0000000000 --- a/Spigot-Server-Patches/Configurable-async-light-updates.patch +++ /dev/null @@ -1,240 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Byteflux <byte@byteflux.net> -Date: Wed, 2 Mar 2016 00:52:31 -0600 -Subject: [PATCH] Configurable async light updates - - -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - - } - -+ public boolean useAsyncLighting; -+ private void useAsyncLighting() { -+ useAsyncLighting = false; //getBoolean( "use-async-lighting", false ); -+ log("World async lighting: " + useAsyncLighting); -+ } - } -diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/Chunk.java -+++ b/src/main/java/net/minecraft/server/Chunk.java -@@ -0,0 +0,0 @@ import java.util.Map; - import java.util.Random; - import java.util.concurrent.Callable; - import java.util.concurrent.ConcurrentLinkedQueue; -+import java.util.concurrent.atomic.AtomicInteger; // Paper -+ - import org.apache.logging.log4j.LogManager; - import org.apache.logging.log4j.Logger; - -@@ -0,0 +0,0 @@ public class Chunk { - private int w; - private ConcurrentLinkedQueue<BlockPosition> x; - protected gnu.trove.map.hash.TObjectIntHashMap<Class> entityCount = new gnu.trove.map.hash.TObjectIntHashMap<Class>(); // Spigot -+ // Paper start - Asynchronous light updates -+ public AtomicInteger pendingLightUpdates = new AtomicInteger(); -+ public long lightUpdateTime; -+ // Paper end - - // CraftBukkit start - Neighbor loaded cache for chunk lighting and entity ticking - private int neighbors = 0x1 << 12; -@@ -0,0 +0,0 @@ public class Chunk { - private void a(int i, int j, int k, int l) { - if (l > k && this.world.areChunksLoaded(new BlockPosition(i, 0, j), 16)) { - for (int i1 = k; i1 < l; ++i1) { -- this.world.c(EnumSkyBlock.SKY, new BlockPosition(i, i1, j)); -+ this.world.updateLight(EnumSkyBlock.SKY, new BlockPosition(i, i1, j)); - } - - this.r = true; -@@ -0,0 +0,0 @@ public class Chunk { - - public void b(boolean flag) { - if (this.l && !this.world.worldProvider.m() && !flag) { -- this.h(this.world.isClientSide); -+ this.recheckGaps(this.world.isClientSide); // Paper - Asynchronous lighting updates - } - - this.q = true; -@@ -0,0 +0,0 @@ public class Chunk { - - } - -+ /** -+ * Paper- Recheck gaps asynchronously -+ */ -+ public void recheckGaps(final boolean isClientSide) { -+ if (!world.paperConfig.useAsyncLighting) { -+ this.h(this.world.isClientSide); -+ return; -+ } -+ -+ world.lightingExecutor.submit(new Runnable() { -+ @Override -+ public void run() { -+ Chunk.this.h(isClientSide); -+ } -+ }); -+ } -+ - public boolean isReady() { - // Spigot Start - /* -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 implements IChunkProvider { - } - - public void queueUnload(int i, int j) { -+ // Paper start - Asynchronous lighting updates -+ Chunk chunk = chunks.get(LongHash.toLong(i, j)); -+ if (chunk != null && chunk.world.paperConfig.useAsyncLighting && (chunk.pendingLightUpdates.get() > 0 || chunk.world.getTime() - chunk.lightUpdateTime < 20)) { -+ return; -+ } -+ // Paper end - if (this.world.worldProvider.c(i, j)) { - // CraftBukkit start - this.unloadQueue.add(i, j); -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 -+++ b/src/main/java/net/minecraft/server/World.java -@@ -0,0 +0,0 @@ import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; - import org.bukkit.generator.ChunkGenerator; - // CraftBukkit end - -+// Paper start -+import java.util.concurrent.ExecutorService; -+import java.util.concurrent.Executors; -+import com.google.common.util.concurrent.ThreadFactoryBuilder; -+// Paper end -+ - public abstract class World implements IBlockAccess { - - private int a = 63; -@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess { - private org.spigotmc.TickLimiter entityLimiter; - private org.spigotmc.TickLimiter tileLimiter; - private int tileTickPosition; -+ public ExecutorService lightingExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("Paper - Lighting Thread").build()); // Paper - Asynchronous lighting updates - - public CraftWorld getWorld() { - return this.world; -@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess { - - if (!this.worldProvider.m()) { - for (i1 = k; i1 <= l; ++i1) { -- this.c(EnumSkyBlock.SKY, new BlockPosition(i, i1, j)); -+ this.updateLight(EnumSkyBlock.SKY, new BlockPosition(i, i1, j)); // Paper - Asynchronous lighting updates - } - } - -@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess { - boolean flag = false; - - if (!this.worldProvider.m()) { -- flag |= this.c(EnumSkyBlock.SKY, blockposition); -+ flag |= this.updateLight(EnumSkyBlock.SKY, blockposition); // Paper - Asynchronous lighting updates - } - -- flag |= this.c(EnumSkyBlock.BLOCK, blockposition); -+ flag |= this.updateLight(EnumSkyBlock.BLOCK, blockposition); // Paper - Asynchronous lighting updates - return flag; - } - -@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess { - } - } - -+ // Paper start - Asynchronous lighting updates - public boolean c(EnumSkyBlock enumskyblock, BlockPosition blockposition) { -+ return this.c(enumskyblock, blockposition, null, null); -+ } -+ -+ public boolean c(EnumSkyBlock enumskyblock, BlockPosition blockposition, Chunk chunk, List<Chunk> neighbors) { // Paper - // CraftBukkit start - Use neighbor cache instead of looking up -- Chunk chunk = this.getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4); -- if (chunk == null || !chunk.areNeighborsLoaded(1) /*!this.areChunksLoaded(blockposition, 17, false)*/) { -+ //Chunk chunk = this.getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4); -+ if (chunk == null /*|| !chunk.areNeighborsLoaded(1)*/ /*!this.areChunksLoaded(blockposition, 17, false)*/) { - // CraftBukkit end - return false; - } else { -@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess { - i = 0; - } - -+ // Paper start - Asynchronous light updates -+ if (chunk.world.paperConfig.useAsyncLighting) { -+ chunk.pendingLightUpdates.decrementAndGet(); -+ if (neighbors != null) { -+ for (Chunk neighbor : neighbors) { -+ neighbor.pendingLightUpdates.decrementAndGet(); -+ } -+ } -+ } -+ // Paper end -+ - this.methodProfiler.b(); - this.methodProfiler.a("checkedPosition < toCheckCount"); - -@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess { - } - } - -+ /** -+ * Paper - Asynchronous lighting updates -+ */ -+ public boolean updateLight(final EnumSkyBlock enumskyblock, final BlockPosition position) { -+ int x = position.getX(); -+ int z = position.getZ(); -+ final Chunk chunk = this.getChunkIfLoaded(x >> 4, z >> 4); -+ if (chunk == null || !chunk.areNeighborsLoaded(1)) { -+ return false; -+ } -+ -+ if (!chunk.world.paperConfig.useAsyncLighting) { -+ return this.c(enumskyblock, position, chunk, null); -+ } -+ -+ chunk.pendingLightUpdates.incrementAndGet(); -+ chunk.lightUpdateTime = chunk.world.getTime(); -+ -+ final List<Chunk> neighbors = new ArrayList<Chunk>(); -+ -+ for (int cx = (x >> 4) - 1; cx <= (x >> 4) + 1; ++cx) { -+ for (int cz = (z >> 4) - 1; cz <= (z >> 4) + 1; ++cz) { -+ if (cx != x >> 4 && cz != z >> 4) { -+ Chunk neighbor = this.getChunkIfLoaded(cx, cz); -+ if (neighbor != null) { -+ neighbor.pendingLightUpdates.incrementAndGet(); -+ neighbor.lightUpdateTime = chunk.world.getTime(); -+ neighbors.add(neighbor); -+ } -+ } -+ } -+ } -+ -+ if (!Bukkit.isPrimaryThread()) { -+ return this.c(enumskyblock, position, chunk, neighbors); -+ } -+ -+ lightingExecutor.submit(new Runnable() { -+ @Override -+ public void run() { -+ World.this.c(enumskyblock, position, chunk, neighbors); -+ } -+ }); -+ return true; -+ } -+ - public boolean a(boolean flag) { - return false; - } --- \ No newline at end of file diff --git a/Spigot-Server-Patches/Configurable-end-credits.patch b/Spigot-Server-Patches/Configurable-end-credits.patch index f51496b6e0..1a441f0553 100644 --- a/Spigot-Server-Patches/Configurable-end-credits.patch +++ b/Spigot-Server-Patches/Configurable-end-credits.patch @@ -9,8 +9,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java @@ -0,0 +0,0 @@ public class PaperWorldConfig { - useAsyncLighting = false; //getBoolean( "use-async-lighting", false ); - log("World async lighting: " + useAsyncLighting); + queueLightUpdates = getBoolean("queue-light-updates", false); + log("Lighting Queue enabled: " + queueLightUpdates); } + + public boolean disableEndCredits; diff --git a/Spigot-Server-Patches/Lighting-Queue.patch b/Spigot-Server-Patches/Lighting-Queue.patch new file mode 100644 index 0000000000..62df13fc4d --- /dev/null +++ b/Spigot-Server-Patches/Lighting-Queue.patch @@ -0,0 +1,231 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Byteflux <byte@byteflux.net> +Date: Wed, 2 Mar 2016 00:52:31 -0600 +Subject: [PATCH] Lighting Queue + + +diff --git a/src/main/java/co/aikar/timings/SpigotTimings.java b/src/main/java/co/aikar/timings/SpigotTimings.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/co/aikar/timings/SpigotTimings.java ++++ b/src/main/java/co/aikar/timings/SpigotTimings.java +@@ -0,0 +0,0 @@ public final class SpigotTimings { + public static final Timing timeUpdateTimer = Timings.ofSafe("Time Update"); + public static final Timing serverCommandTimer = Timings.ofSafe("Server Command"); + public static final Timing worldSaveTimer = Timings.ofSafe("World Save"); ++ public static final Timing lightingQueueTimer = Timings.ofSafe("Lighting Queue"); + + public static final Timing tickEntityTimer = Timings.ofSafe("## tickEntity"); + public static final Timing tickTileEntityTimer = Timings.ofSafe("## tickTileEntity"); +diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java ++++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +@@ -0,0 +0,0 @@ public class PaperWorldConfig { + + } + ++ public boolean queueLightUpdates; ++ private void queueLightUpdates() { ++ queueLightUpdates = getBoolean("queue-light-updates", false); ++ log("Lighting Queue enabled: " + queueLightUpdates); ++ } + } +diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/Chunk.java ++++ b/src/main/java/net/minecraft/server/Chunk.java +@@ -0,0 +0,0 @@ public class Chunk { + private int w; + private ConcurrentLinkedQueue<BlockPosition> x; + protected gnu.trove.map.hash.TObjectIntHashMap<Class> entityCount = new gnu.trove.map.hash.TObjectIntHashMap<Class>(); // Spigot ++ public int lightUpdates; // Paper - Number of queued light updates for this chunk + + // CraftBukkit start - Neighbor loaded cache for chunk lighting and entity ticking + private int neighbors = 0x1 << 12; +@@ -0,0 +0,0 @@ public class Chunk { + private void h(boolean flag) { + this.world.methodProfiler.a("recheckGaps"); + if (this.world.areChunksLoaded(new BlockPosition(this.locX * 16 + 8, 0, this.locZ * 16 + 8), 16)) { ++ // Paper start - Queue light update ++ if (!world.paperConfig.queueLightUpdates) { ++ recheckGaps(flag); ++ } else { ++ ++lightUpdates; ++ world.getServer().getServer().lightingQueue.add(() -> { ++ recheckGaps(flag); ++ --lightUpdates; ++ }); ++ } ++ } ++ } ++ ++ private void recheckGaps(boolean flag) { ++ if (true) { ++ // Paper end + for (int i = 0; i < 16; ++i) { + for (int j = 0; j < 16; ++j) { + if (this.h[i + j * 16]) { +@@ -0,0 +0,0 @@ public class Chunk { + } else { + if (flag) { + this.initLighting(); +- } else { ++ } else if (!world.paperConfig.queueLightUpdates) { // Paper + int j1 = iblockdata.c(); + int k1 = iblockdata1.c(); + +@@ -0,0 +0,0 @@ public class Chunk { + if (j1 != k1 && (j1 < k1 || this.getBrightness(EnumSkyBlock.SKY, blockposition) > 0 || this.getBrightness(EnumSkyBlock.BLOCK, blockposition) > 0)) { + this.d(i, k); + } ++ // Paper start - Queue light update ++ } else { ++ int j1 = iblockdata.c(); ++ int k1 = iblockdata1.c(); ++ ++ ++lightUpdates; ++ world.getServer().getServer().lightingQueue.add(() -> { ++ if (j1 > 0) { ++ if (j >= i1) { ++ this.c(i, j + 1, k); ++ } ++ } else if (j == i1 - 1) { ++ this.c(i, j, k); ++ } ++ ++ if (j1 != k1 && (j1 < k1 || this.getBrightness(EnumSkyBlock.SKY, blockposition) > 0 || this.getBrightness(EnumSkyBlock.BLOCK, blockposition) > 0)) { ++ this.d(i, k); ++ } ++ ++ --lightUpdates; ++ }); ++ // Paper end + } + + TileEntity tileentity; +@@ -0,0 +0,0 @@ public class Chunk { + + private EnumTileEntityState() {} + } ++ ++ // Paper start ++ public boolean hasLightUpdates() { ++ if (world.paperConfig.queueLightUpdates) { ++ if (lightUpdates > 0) { ++ return true; ++ } ++ ++ for (int x = locX - 2; x <= locX + 2; ++x) { ++ for (int z = locZ - 2; z <= locZ + 2; ++z) { ++ if ((x == 0 && z == 0) || (x == locX && z == locZ)) { ++ continue; ++ } ++ ++ Chunk chunk = world.getChunkIfLoaded(x, z); ++ if (chunk != null && chunk.lightUpdates > 0) { ++ return true; ++ } ++ } ++ } ++ } ++ ++ return false; ++ } ++ // Paper end + } +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 implements IChunkProvider { + long chunkcoordinates = this.unloadQueue.popFirst(); + Chunk chunk = this.chunks.get(chunkcoordinates); + if (chunk == null) continue; ++ if (chunk.hasLightUpdates()) continue; // Paper - Don't unload chunks with pending light updates. + + ChunkUnloadEvent event = new ChunkUnloadEvent(chunk.bukkitChunk); + server.getPluginManager().callEvent(event); +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -0,0 +0,0 @@ import org.bukkit.craftbukkit.CraftServer; + // CraftBukkit end + import co.aikar.timings.SpigotTimings; // Paper + ++// Paper start ++import java.util.LinkedList; ++import java.util.Queue; ++// Paper end ++ + public abstract class MinecraftServer implements Runnable, ICommandListener, IAsyncTaskHandler, IMojangStatistics { + + public static final Logger LOGGER = LogManager.getLogger(); +@@ -0,0 +0,0 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs + public final Thread primaryThread; + public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>(); + public int autosavePeriod; ++ public final Queue<Runnable> lightingQueue = new LinkedList<Runnable>(); // Paper - Queued light updates + // CraftBukkit end + + public MinecraftServer(OptionSet options, Proxy proxy, DataConverterManager dataconvertermanager, YggdrasilAuthenticationService yggdrasilauthenticationservice, MinecraftSessionService minecraftsessionservice, GameProfileRepository gameprofilerepository, UserCache usercache) { +@@ -0,0 +0,0 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs + + this.methodProfiler.b(); + this.methodProfiler.b(); ++ ++ // Paper start - Flush light updates ++ if (!lightingQueue.isEmpty()) { ++ SpigotTimings.lightingQueueTimer.startTiming(); ++ ++ int updatesThisTick = 0; ++ long cachedTime = System.currentTimeMillis(); ++ long startTime = cachedTime - (this.h[this.ticks % 100] / 1000000); ++ int maxTickTimeCap = MathHelper.floor((TICK_TIME / 1000000) * 0.8); ++ int maxTickTime = Math.max(0, (int) (maxTickTimeCap - (cachedTime - startTime))); ++ Runnable lightUpdate; ++ ++ while (maxTickTime > 0 && (lightUpdate = lightingQueue.poll()) != null) { ++ lightUpdate.run(); ++ if (++updatesThisTick % 10 == 0) { ++ long currentTime = System.currentTimeMillis(); ++ if (currentTime - cachedTime > maxTickTime) { ++ break; ++ } ++ ++ cachedTime = currentTime; ++ maxTickTime = Math.max(0, (int) (maxTickTimeCap - (currentTime - startTime))); ++ } ++ } ++ ++ SpigotTimings.lightingQueueTimer.stopTiming(); ++ } ++ // Paper end ++ + org.spigotmc.WatchdogThread.tick(); // Spigot + co.aikar.timings.TimingsManager.FULL_SERVER_TICK.stopTiming(); // Paper + } +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 ++++ b/src/main/java/net/minecraft/server/World.java +@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess { + } else { + if (iblockdata.c() != iblockdata1.c() || iblockdata.d() != iblockdata1.d()) { + this.methodProfiler.a("checkLight"); +- this.w(blockposition); ++ // Paper start - Queue light update ++ if (!paperConfig.queueLightUpdates) { ++ this.w(blockposition); ++ } else { ++ ++chunk.lightUpdates; ++ getMinecraftServer().lightingQueue.add(() -> { ++ this.w(blockposition); ++ --chunk.lightUpdates; ++ }); ++ } ++ // Paper end + this.methodProfiler.b(); + } + +-- \ No newline at end of file diff --git a/Spigot-Server-Patches/Optimize-Chunk-Unload-Queue.patch b/Spigot-Server-Patches/Optimize-Chunk-Unload-Queue.patch index 9a44a83bad..ef7d7c4b60 100644 --- a/Spigot-Server-Patches/Optimize-Chunk-Unload-Queue.patch +++ b/Spigot-Server-Patches/Optimize-Chunk-Unload-Queue.patch @@ -144,9 +144,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + continue; + } + // Paper end + if (chunk.hasLightUpdates()) continue; // Paper - Don't unload chunks with pending light updates. ChunkUnloadEvent event = new ChunkUnloadEvent(chunk.bukkitChunk); - server.getPluginManager().callEvent(event); @@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider { continue; } diff --git a/Spigot-Server-Patches/Optimize-explosions.patch b/Spigot-Server-Patches/Optimize-explosions.patch index cea94c8116..afbda3644a 100644 --- a/Spigot-Server-Patches/Optimize-explosions.patch +++ b/Spigot-Server-Patches/Optimize-explosions.patch @@ -139,19 +139,19 @@ diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/m index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java -@@ -0,0 +0,0 @@ import org.bukkit.generator.ChunkGenerator; - // Paper start - import java.util.concurrent.ExecutorService; - import java.util.concurrent.Executors; -+import java.util.HashMap; - import com.google.common.util.concurrent.ThreadFactoryBuilder; - // Paper end +@@ -0,0 +0,0 @@ import java.util.concurrent.Callable; + // CraftBukkit start + import com.google.common.collect.Maps; ++import java.util.HashMap; // Paper + import java.util.Map; + import org.bukkit.Bukkit; + import org.bukkit.block.BlockState; @@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess { + private org.spigotmc.TickLimiter entityLimiter; private org.spigotmc.TickLimiter tileLimiter; private int tileTickPosition; - public ExecutorService lightingExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("Paper - Lighting Thread").build()); // Paper - Asynchronous lighting updates -+ public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<Explosion.CacheKey, Float>(); // Paper - Optimize explosions ++ public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions public CraftWorld getWorld() { return this.world;