From d438c0dfa1b5b31fbb7c65e5b8675824847f541b Mon Sep 17 00:00:00 2001 From: Byteflux 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 3f4271c..5fdf051 100644 --- a/src/main/java/co/aikar/timings/SpigotTimings.java +++ b/src/main/java/co/aikar/timings/SpigotTimings.java @@ -17,6 +17,7 @@ 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 facb98c..e0e9a65 100644 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java @@ -166,4 +166,9 @@ 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 cde4124..3b5e8c2 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java @@ -44,6 +44,7 @@ public class Chunk { private int w; private ConcurrentLinkedQueue x; protected gnu.trove.map.hash.TObjectIntHashMap entityCount = new gnu.trove.map.hash.TObjectIntHashMap(); // 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; @@ -226,6 +227,22 @@ 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]) { @@ -476,7 +493,7 @@ public class Chunk { } else { if (flag) { this.initLighting(); - } else { + } else if (!world.paperConfig.queueLightUpdates) { // Paper int j1 = iblockdata.c(); int k1 = iblockdata1.c(); @@ -491,6 +508,28 @@ 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; @@ -1314,4 +1353,29 @@ 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 83857a6..4dd672a 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java @@ -284,6 +284,7 @@ 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 e9bb02f..d0fd638 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -47,6 +47,11 @@ 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(); @@ -113,6 +118,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs public final Thread primaryThread; public java.util.Queue processQueue = new java.util.concurrent.ConcurrentLinkedQueue(); public int autosavePeriod; + public final Queue lightingQueue = new LinkedList(); // Paper - Queued light updates // CraftBukkit end public MinecraftServer(OptionSet options, Proxy proxy, DataConverterManager dataconvertermanager, YggdrasilAuthenticationService yggdrasilauthenticationservice, MinecraftSessionService minecraftsessionservice, GameProfileRepository gameprofilerepository, UserCache usercache) { @@ -759,6 +765,35 @@ 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 f564b1a..cdb722d 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -378,7 +378,17 @@ 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(); } -- 2.7.1.windows.2