3fd3544a36
The lighting queue spreads out the processing of light updates across multiple ticks based on how much free time the server has left at the end of the tick.
233 lines
10 KiB
Diff
233 lines
10 KiB
Diff
From 73b3ea1a73387e5a5a24366959c1c35caf7387e9 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 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..9020b1b 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<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;
|
|
@@ -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 6ae06a5..aa337cc 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<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) {
|
|
@@ -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 c5ce0c3..a1d8bc5 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
|
|
|