d617f95f05
Upstream has released updates that appears to apply and compile correctly.
This update has not been tested by PaperMC and as with ANY update, please do your own testing
Bukkit Changes:
310dc809 Add ServerLoadEvent
CraftBukkit Changes:
19d654bd
Add ServerLoadEvent
251 Zeilen
10 KiB
Diff
251 Zeilen
10 KiB
Diff
From daa5867fc7ca974cdb1bb4ff0505eab29fa2a6a8 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
|
|
|
|
This provides option to queue lighting updates to ensure they do not cause the server lag
|
|
|
|
diff --git a/src/main/java/co/aikar/timings/WorldTimingsHandler.java b/src/main/java/co/aikar/timings/WorldTimingsHandler.java
|
|
index 145cb274b0..eff9dcf54f 100644
|
|
--- a/src/main/java/co/aikar/timings/WorldTimingsHandler.java
|
|
+++ b/src/main/java/co/aikar/timings/WorldTimingsHandler.java
|
|
@@ -50,6 +50,8 @@ public class WorldTimingsHandler {
|
|
public final Timing worldSaveLevel;
|
|
public final Timing chunkSaveData;
|
|
|
|
+ public final Timing lightingQueueTimer;
|
|
+
|
|
public WorldTimingsHandler(World server) {
|
|
String name = server.worldData.getName() +" - ";
|
|
|
|
@@ -96,6 +98,8 @@ public class WorldTimingsHandler {
|
|
tracker2 = Timings.ofSafe(name + "tracker stage 2");
|
|
doTick = Timings.ofSafe(name + "doTick");
|
|
tickEntities = Timings.ofSafe(name + "tickEntities");
|
|
+
|
|
+ lightingQueueTimer = Timings.ofSafe(name + "Lighting Queue");
|
|
}
|
|
|
|
public static Timing getTickList(WorldServer worldserver, String timingsType) {
|
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
index 39d565db1f..f0d1ae630e 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
@@ -130,4 +130,10 @@ public class PaperWorldConfig {
|
|
netherVoidTopDamage = getBoolean( "nether-ceiling-void-damage", false );
|
|
log("Top of the nether void damage: " + netherVoidTopDamage);
|
|
}
|
|
+
|
|
+ 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 4622e92b05..d4bebddab0 100644
|
|
--- a/src/main/java/net/minecraft/server/Chunk.java
|
|
+++ b/src/main/java/net/minecraft/server/Chunk.java
|
|
@@ -90,6 +90,7 @@ public class Chunk implements IChunkAccess {
|
|
return removed;
|
|
}
|
|
}
|
|
+ final PaperLightingQueue.LightingQueue lightingQueue = new PaperLightingQueue.LightingQueue(this);
|
|
// Paper end
|
|
public boolean areNeighborsLoaded(final int radius) {
|
|
switch (radius) {
|
|
@@ -280,6 +281,13 @@ public class Chunk implements IChunkAccess {
|
|
private void g(boolean flag) {
|
|
this.world.methodProfiler.a("recheckGaps");
|
|
if (this.world.areChunksLoaded(new BlockPosition(this.locX * 16 + 8, 0, this.locZ * 16 + 8), 16)) {
|
|
+ this.runOrQueueLightUpdate(() -> recheckGaps(flag)); // Paper - Queue light update
|
|
+ }
|
|
+ }
|
|
+
|
|
+ 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.g[i + j * 16]) {
|
|
@@ -530,6 +538,7 @@ public class Chunk implements IChunkAccess {
|
|
if (flag1) {
|
|
this.initLighting();
|
|
} else {
|
|
+ this.runOrQueueLightUpdate(() -> { // Paper - Queue light update
|
|
int i1 = iblockdata.b(this.world, blockposition);
|
|
int j1 = iblockdata1.b(this.world, blockposition);
|
|
|
|
@@ -537,6 +546,7 @@ public class Chunk implements IChunkAccess {
|
|
if (i1 != j1 && (i1 < j1 || this.getBrightness(EnumSkyBlock.SKY, blockposition) > 0 || this.getBrightness(EnumSkyBlock.BLOCK, blockposition) > 0)) {
|
|
this.c(i, k);
|
|
}
|
|
+ }); // Paper
|
|
}
|
|
|
|
TileEntity tileentity;
|
|
@@ -1307,6 +1317,16 @@ public class Chunk implements IChunkAccess {
|
|
return this.D == 8;
|
|
}
|
|
|
|
+ // Paper start
|
|
+ public void runOrQueueLightUpdate(Runnable runnable) {
|
|
+ if (this.world.paperConfig.queueLightUpdates) {
|
|
+ lightingQueue.add(runnable);
|
|
+ } else {
|
|
+ runnable.run();
|
|
+ }
|
|
+ }
|
|
+ // Paper end
|
|
+
|
|
public static enum EnumTileEntityState {
|
|
|
|
IMMEDIATE, QUEUED, CHECK;
|
|
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
|
index 0034956af9..1379b574ef 100644
|
|
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
|
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
|
@@ -314,6 +314,7 @@ public class ChunkProviderServer implements IChunkProvider {
|
|
return false;
|
|
}
|
|
save = event.isSaveChunk();
|
|
+ chunk.lightingQueue.processUnload(); // Paper
|
|
|
|
// Update neighbor counts
|
|
for (int x = -2; x < 3; x++) {
|
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
index 13c6021ffa..30541dfa5a 100644
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
@@ -890,7 +890,7 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati
|
|
protected void a(BooleanSupplier booleansupplier) {
|
|
co.aikar.timings.TimingsManager.FULL_SERVER_TICK.startTiming(); // Paper
|
|
this.slackActivityAccountant.tickStarted(); // Spigot
|
|
- long i = SystemUtils.c();
|
|
+ long i = SystemUtils.c(); long startTime = i; // Paper
|
|
|
|
++this.ticks;
|
|
if (this.S) {
|
|
@@ -948,6 +948,7 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati
|
|
this.methodProfiler.e();
|
|
this.methodProfiler.e();
|
|
org.spigotmc.WatchdogThread.tick(); // Spigot
|
|
+ PaperLightingQueue.processQueue(startTime); // Paper
|
|
this.slackActivityAccountant.tickEnded(l); // Spigot
|
|
co.aikar.timings.TimingsManager.FULL_SERVER_TICK.stopTiming(); // Paper
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/PaperLightingQueue.java b/src/main/java/net/minecraft/server/PaperLightingQueue.java
|
|
new file mode 100644
|
|
index 0000000000..60562f1fd2
|
|
--- /dev/null
|
|
+++ b/src/main/java/net/minecraft/server/PaperLightingQueue.java
|
|
@@ -0,0 +1,92 @@
|
|
+package net.minecraft.server;
|
|
+
|
|
+import co.aikar.timings.Timing;
|
|
+import it.unimi.dsi.fastutil.objects.ObjectCollection;
|
|
+
|
|
+import java.util.ArrayDeque;
|
|
+
|
|
+class PaperLightingQueue {
|
|
+ private static final long MAX_TIME = (long) (1000000000 / 20 * .95);
|
|
+ private static int updatesThisTick;
|
|
+
|
|
+
|
|
+ static void processQueue(long curTime) {
|
|
+ updatesThisTick = 0;
|
|
+
|
|
+ final long startTime = System.nanoTime();
|
|
+ final long maxTickTime = MAX_TIME - (startTime - curTime);
|
|
+
|
|
+ START:
|
|
+ for (World world : MinecraftServer.getServer().getWorlds()) {
|
|
+ if (!world.paperConfig.queueLightUpdates) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ ObjectCollection<Chunk> loadedChunks = ((WorldServer) world).getChunkProviderServer().chunks.values();
|
|
+ for (Chunk chunk : loadedChunks.toArray(new Chunk[loadedChunks.size()])) {
|
|
+ if (chunk.lightingQueue.processQueue(startTime, maxTickTime)) {
|
|
+ break START;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ static class LightingQueue extends ArrayDeque<Runnable> {
|
|
+ final private Chunk chunk;
|
|
+
|
|
+ LightingQueue(Chunk chunk) {
|
|
+ super();
|
|
+ this.chunk = chunk;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Processes the lighting queue for this chunk
|
|
+ *
|
|
+ * @param startTime If start Time is 0, we will not limit execution time
|
|
+ * @param maxTickTime Maximum time to spend processing lighting updates
|
|
+ * @return true to abort processing furthur lighting updates
|
|
+ */
|
|
+ private boolean processQueue(long startTime, long maxTickTime) {
|
|
+ if (this.isEmpty()) {
|
|
+ return false;
|
|
+ }
|
|
+ try (Timing ignored = chunk.world.timings.lightingQueueTimer.startTiming()) {
|
|
+ Runnable lightUpdate;
|
|
+ while ((lightUpdate = this.poll()) != null) {
|
|
+ lightUpdate.run();
|
|
+ if (startTime > 0 && ++PaperLightingQueue.updatesThisTick % 10 == 0 && PaperLightingQueue.updatesThisTick > 10) {
|
|
+ if (System.nanoTime() - startTime > maxTickTime) {
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Flushes lighting updates to unload the chunk
|
|
+ */
|
|
+ void processUnload() {
|
|
+ if (!chunk.world.paperConfig.queueLightUpdates) {
|
|
+ return;
|
|
+ }
|
|
+ processQueue(0, 0); // No timeout
|
|
+
|
|
+ final int radius = 1; // TODO: bitflip, why should this ever be 2?
|
|
+ for (int x = chunk.locX - radius; x <= chunk.locX + radius; ++x) {
|
|
+ for (int z = chunk.locZ - radius; z <= chunk.locZ + radius; ++z) {
|
|
+ if (x == chunk.locX && z == chunk.locZ) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ Chunk neighbor = MCUtil.getLoadedChunkWithoutMarkingActive(chunk.world, x, z);
|
|
+ if (neighbor != null) {
|
|
+ neighbor.lightingQueue.processQueue(0, 0); // No timeout
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
|
|
index 929875340f..0fe8a97f24 100644
|
|
--- a/src/main/java/net/minecraft/server/World.java
|
|
+++ b/src/main/java/net/minecraft/server/World.java
|
|
@@ -335,7 +335,7 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
|
|
|
|
if (iblockdata2.b(this, blockposition) != iblockdata1.b(this, blockposition) || iblockdata2.e() != iblockdata1.e()) {
|
|
this.methodProfiler.a("checkLight");
|
|
- this.r(blockposition);
|
|
+ chunk.runOrQueueLightUpdate(() -> this.r(blockposition)); // Paper - Queue light update
|
|
this.methodProfiler.e();
|
|
}
|
|
|
|
--
|
|
2.18.0
|
|
|