mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-11 17:31:06 +01:00
1358d1e914
Upstream has released updates that appear 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: 881e06e5 PR-725: Add Item Unlimited Lifetime APIs CraftBukkit Changes: 74c08312 SPIGOT-6962: Call EntityChangeBlockEvent when when FallingBlockEntity starts to fall 64db5126 SPIGOT-6959: Make /loot command ignore empty items for spawn 2d760831 Increase outdated build delay 9ed7e4fb SPIGOT-6138, SPIGOT-6415: Don't call CreatureSpawnEvent after cross-dimensional travel fc4ad813 SPIGOT-6895: Trees grown with applyBoneMeal() don't fire the StructureGrowthEvent 59733a2e SPIGOT-6961: Actually return a copy of the ItemMeta Spigot Changes: ffceeae3 SPIGOT-6956: Drop unload queue patch as attempt at fixing stop issue e19ddabd PR-1011: Add Item Unlimited Lifetime APIs 34d40b0e SPIGOT-2942: give command fires PlayerDropItemEvent, cancelling it causes Item Duplication
182 lines
8.8 KiB
Diff
182 lines
8.8 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
|
Date: Mon, 6 Apr 2020 04:20:44 -0700
|
|
Subject: [PATCH] Execute chunk tasks mid-tick
|
|
|
|
This will help the server load chunks if tick times are high.
|
|
|
|
diff --git a/src/main/java/co/aikar/timings/MinecraftTimings.java b/src/main/java/co/aikar/timings/MinecraftTimings.java
|
|
index b27021a42cbed3f0648a8d0903d00d03922ae221..eada966d7f108a6081be7a848f5c1dfcb1eed676 100644
|
|
--- a/src/main/java/co/aikar/timings/MinecraftTimings.java
|
|
+++ b/src/main/java/co/aikar/timings/MinecraftTimings.java
|
|
@@ -45,6 +45,8 @@ public final class MinecraftTimings {
|
|
public static final Timing antiXrayUpdateTimer = Timings.ofSafe("anti-xray - update");
|
|
public static final Timing antiXrayObfuscateTimer = Timings.ofSafe("anti-xray - obfuscate");
|
|
|
|
+ public static final Timing midTickChunkTasks = Timings.ofSafe("Mid Tick Chunk Tasks");
|
|
+
|
|
private static final Map<Class<?>, String> taskNameCache = new MapMaker().weakKeys().makeMap();
|
|
|
|
private MinecraftTimings() {}
|
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
index 65d5d96a687712d87bbc61d85f80438811bae07d..a279368fe144bd41d15e5fe5e565412f8b4ef9f7 100644
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
@@ -1344,6 +1344,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
|
|
private boolean pollTaskInternal() {
|
|
if (super.pollTask()) {
|
|
+ this.executeMidTickTasks(); // Paper - execute chunk tasks mid tick
|
|
return true;
|
|
} else {
|
|
if (this.haveTime()) {
|
|
@@ -2665,4 +2666,74 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
}
|
|
}
|
|
// Paper end
|
|
+
|
|
+ // Paper start - execute chunk tasks mid tick
|
|
+ static final long CHUNK_TASK_QUEUE_BACKOFF_MIN_TIME = 25L * 1000L; // 25us
|
|
+ static final long MAX_CHUNK_EXEC_TIME = 1000L; // 1us
|
|
+
|
|
+ static final long TASK_EXECUTION_FAILURE_BACKOFF = 5L * 1000L; // 5us
|
|
+
|
|
+ private static long lastMidTickExecute;
|
|
+ private static long lastMidTickExecuteFailure;
|
|
+
|
|
+ private boolean tickMidTickTasks() {
|
|
+ // give all worlds a fair chance at by targetting them all.
|
|
+ // if we execute too many tasks, that's fine - we have logic to correctly handle overuse of allocated time.
|
|
+ boolean executed = false;
|
|
+ for (ServerLevel world : this.getAllLevels()) {
|
|
+ long currTime = System.nanoTime();
|
|
+ if (currTime - world.lastMidTickExecuteFailure <= TASK_EXECUTION_FAILURE_BACKOFF) {
|
|
+ continue;
|
|
+ }
|
|
+ if (!world.getChunkSource().pollTask()) {
|
|
+ // we need to back off if this fails
|
|
+ world.lastMidTickExecuteFailure = currTime;
|
|
+ } else {
|
|
+ executed = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return executed;
|
|
+ }
|
|
+
|
|
+ public final void executeMidTickTasks() {
|
|
+ org.spigotmc.AsyncCatcher.catchOp("mid tick chunk task execution");
|
|
+ long startTime = System.nanoTime();
|
|
+ if ((startTime - lastMidTickExecute) <= CHUNK_TASK_QUEUE_BACKOFF_MIN_TIME || (startTime - lastMidTickExecuteFailure) <= TASK_EXECUTION_FAILURE_BACKOFF) {
|
|
+ // it's shown to be bad to constantly hit the queue (chunk loads slow to a crawl), even if no tasks are executed.
|
|
+ // so, backoff to prevent this
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ co.aikar.timings.MinecraftTimings.midTickChunkTasks.startTiming();
|
|
+ try {
|
|
+ for (;;) {
|
|
+ boolean moreTasks = this.tickMidTickTasks();
|
|
+ long currTime = System.nanoTime();
|
|
+ long diff = currTime - startTime;
|
|
+
|
|
+ if (!moreTasks || diff >= MAX_CHUNK_EXEC_TIME) {
|
|
+ if (!moreTasks) {
|
|
+ lastMidTickExecuteFailure = currTime;
|
|
+ }
|
|
+
|
|
+ // note: negative values reduce the time
|
|
+ long overuse = diff - MAX_CHUNK_EXEC_TIME;
|
|
+ if (overuse >= (10L * 1000L * 1000L)) { // 10ms
|
|
+ // make sure something like a GC or dumb plugin doesn't screw us over...
|
|
+ overuse = 10L * 1000L * 1000L; // 10ms
|
|
+ }
|
|
+
|
|
+ double overuseCount = (double)overuse/(double)MAX_CHUNK_EXEC_TIME;
|
|
+ long extraSleep = (long)Math.round(overuseCount*CHUNK_TASK_QUEUE_BACKOFF_MIN_TIME);
|
|
+
|
|
+ lastMidTickExecute = currTime + extraSleep;
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ } finally {
|
|
+ co.aikar.timings.MinecraftTimings.midTickChunkTasks.stopTiming();
|
|
+ }
|
|
+ }
|
|
+ // Paper end - execute chunk tasks mid tick
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
index d5eb5a365c8e8cdcd8e9cf54918cc2fb383c6625..b73f49b9bf49dc2a08aa8ffece675df41c077412 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
@@ -1019,6 +1019,7 @@ public class ServerChunkCache extends ChunkSource {
|
|
iterator1 = shuffled.iterator();
|
|
}
|
|
|
|
+ int chunksTicked = 0; // Paper
|
|
try {
|
|
while (iterator1.hasNext()) {
|
|
LevelChunk chunk1 = iterator1.next();
|
|
@@ -1036,6 +1037,7 @@ public class ServerChunkCache extends ChunkSource {
|
|
|
|
if (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) {
|
|
this.level.tickChunk(chunk1, k);
|
|
+ if ((chunksTicked++ & 1) == 0) net.minecraft.server.MinecraftServer.getServer().executeMidTickTasks(); // Paper
|
|
}
|
|
}
|
|
// Paper start - optimise chunk tick iteration
|
|
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
index eace9e9c97fff7d02326805ce77cc75a650f9b6d..381a4283715290162f445265e61294256e6b3075 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
@@ -202,7 +202,9 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
private final StructureFeatureManager structureFeatureManager;
|
|
private final StructureCheck structureCheck;
|
|
private final boolean tickTime;
|
|
-
|
|
+ // Paper start - execute chunk tasks mid tick
|
|
+ public long lastMidTickExecuteFailure;
|
|
+ // Paper end - execute chunk tasks mid tick
|
|
|
|
// CraftBukkit start
|
|
private int tickPosition;
|
|
@@ -965,6 +967,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
if (fluid1.is(fluid)) {
|
|
fluid1.tick(this, pos);
|
|
}
|
|
+ MinecraftServer.getServer().executeMidTickTasks(); // Paper - exec chunk tasks during world tick
|
|
|
|
}
|
|
|
|
@@ -974,6 +977,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
if (iblockdata.is(block)) {
|
|
iblockdata.tick(this, pos, this.random);
|
|
}
|
|
+ MinecraftServer.getServer().executeMidTickTasks(); // Paper - exec chunk tasks during world tick
|
|
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
|
index 944519c4433710610ac5015d3d3de380d9ec39c9..06035b728a66a63582c34c85096bada1588bfaa6 100644
|
|
--- a/src/main/java/net/minecraft/world/level/Level.java
|
|
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
|
@@ -838,6 +838,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
|
// Spigot end
|
|
} else if (this.shouldTickBlocksAt(ChunkPos.asLong(tickingblockentity.getPos()))) {
|
|
tickingblockentity.tick();
|
|
+ // Paper start - execute chunk tasks during tick
|
|
+ if ((this.tileTickPosition & 7) == 0) {
|
|
+ MinecraftServer.getServer().executeMidTickTasks();
|
|
+ }
|
|
+ // Paper end - execute chunk tasks during tick
|
|
}
|
|
}
|
|
this.blockEntityTickers.removeAll(toRemove);
|
|
@@ -852,6 +857,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
|
public <T extends Entity> void guardEntityTick(Consumer<T> tickConsumer, T entity) {
|
|
try {
|
|
tickConsumer.accept(entity);
|
|
+ MinecraftServer.getServer().executeMidTickTasks(); // Paper - execute chunk tasks mid tick
|
|
} catch (Throwable throwable) {
|
|
if (throwable instanceof ThreadDeath) throw throwable; // Paper
|
|
// Paper start - Prevent tile entity and entity crashes
|