Fix off by one error for scheduling block ticks (#4014)

Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>

Fixes #4015
This commit is contained in:
Spottedleaf 2020-07-27 22:19:11 -07:00 committed by GitHub
parent 5791e512b7
commit dafc7b8f8d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 54 additions and 34 deletions

View file

@ -42,7 +42,7 @@ sets the excessive tick delay to the specified ticks (defaults to
60 * 20 ticks, aka 60 seconds)
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
index bf86444c479f346e7d56f10a7c0ebefd62f08f59..8508b3e10e60a4ce36d471b1d3f7ffc836a6ddf7 100644
index f4a56028c21427d1164c5777285114a284b5643c..ee1a690c1b12f28a5282a61917d28deb3ca08f61 100644
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
@@ -349,6 +349,13 @@ public class PaperConfig {
@ -61,10 +61,10 @@ index bf86444c479f346e7d56f10a7c0ebefd62f08f59..8508b3e10e60a4ce36d471b1d3f7ffc8
ConfigurationSection section;
diff --git a/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java b/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java
new file mode 100644
index 0000000000000000000000000000000000000000..bbb042fec32ce5a4aecf1934ab6bed77c5134a7f
index 0000000000000000000000000000000000000000..e7624948ea4aa1a07d84ed3d295cfe2dd354fd14
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java
@@ -0,0 +1,624 @@
@@ -0,0 +1,628 @@
+package com.destroystokyo.paper.server.ticklist;
+
+import net.minecraft.server.MCUtil;
@ -137,7 +137,7 @@ index 0000000000000000000000000000000000000000..bbb042fec32ce5a4aecf1934ab6bed77
+ }
+ private int shortScheduledIndex;
+
+ private long nextTick;
+ private long currentTick;
+
+ private static final boolean WARN_ON_EXCESSIVE_DELAY = Boolean.getBoolean("paper.ticklist-warn-on-excessive-delay");
+ private static final long EXCESSIVE_DELAY_THRESHOLD = Long.getLong("paper.ticklist-excessive-delay-threshold", 60 * 20).longValue(); // 1 min dfl
@ -163,7 +163,7 @@ index 0000000000000000000000000000000000000000..bbb042fec32ce5a4aecf1934ab6bed77
+ this.timingCleanup = co.aikar.timings.WorldTimingsHandler.getTickList(world, timingsType + " - Cleanup"); // Paper
+ this.timingTicking = co.aikar.timings.WorldTimingsHandler.getTickList(world, timingsType + " - Ticking"); // Paper
+ this.timingFinished = co.aikar.timings.WorldTimingsHandler.getTickList(world, timingsType + " - Finish");
+ this.nextTick = this.world.getTime();
+ this.currentTick = this.world.getTime();
+ }
+
+ private void queueEntryForTick(final NextTickListEntry<T> entry, final ChunkProviderServer chunkProvider) {
@ -185,7 +185,7 @@ index 0000000000000000000000000000000000000000..bbb042fec32ce5a4aecf1934ab6bed77
+ }
+
+ private void addToSchedule(final NextTickListEntry<T> entry) {
+ long delay = entry.getTargetTick() - this.nextTick;
+ long delay = entry.getTargetTick() - (this.currentTick + 1);
+ if (delay < SHORT_SCHEDULE_TICK_THRESHOLD) {
+ if (delay < 0) {
+ // longScheduled orders by tick time, short scheduled does not
@ -246,7 +246,7 @@ index 0000000000000000000000000000000000000000..bbb042fec32ce5a4aecf1934ab6bed77
+ }
+ }
+
+ long delay = entry.getTargetTick() - this.nextTick;
+ long delay = entry.getTargetTick() - (this.currentTick + 1);
+ if (delay >= SHORT_SCHEDULE_TICK_THRESHOLD) {
+ this.longScheduled.remove(entry);
+ }
@ -266,7 +266,7 @@ index 0000000000000000000000000000000000000000..bbb042fec32ce5a4aecf1934ab6bed77
+ }
+
+ private void prepare() {
+ final long currentTick = this.nextTick;
+ final long currentTick = this.currentTick;
+
+ final ChunkProviderServer chunkProvider = this.world.getChunkProvider();
+
@ -334,15 +334,19 @@ index 0000000000000000000000000000000000000000..bbb042fec32ce5a4aecf1934ab6bed77
+ private boolean warnedAboutDesync;
+
+ @Override
+ public void tick() {
+ ++this.nextTick;
+ if (this.nextTick != this.world.getTime()) {
+ protected void nextTick() {
+ ++this.currentTick;
+ if (this.currentTick != this.world.getTime()) {
+ if (!this.warnedAboutDesync) {
+ this.warnedAboutDesync = true;
+ MinecraftServer.LOGGER.error("World tick desync detected! Expected " + this.nextTick + " ticks, but got " + this.world.getTime() + " ticks for world '" + this.world.getWorld().getName() + "'", new Throwable());
+ MinecraftServer.LOGGER.error("World tick desync detected! Expected " + this.currentTick + " ticks, but got " + this.world.getTime() + " ticks for world '" + this.world.getWorld().getName() + "'", new Throwable());
+ MinecraftServer.LOGGER.error("Preventing redstone from breaking by refusing to accept new tick time");
+ }
+ }
+ }
+
+ @Override
+ public void tick() {
+ final ChunkProviderServer chunkProvider = this.world.getChunkProvider();
+
+ this.world.getMethodProfiler().enter("cleaning");
@ -479,7 +483,7 @@ index 0000000000000000000000000000000000000000..bbb042fec32ce5a4aecf1934ab6bed77
+
+ @Override
+ public void schedule(BlockPosition blockPosition, T t, int i, TickListPriority tickListPriority) {
+ this.schedule(blockPosition, t, i + this.nextTick, tickListPriority);
+ this.schedule(blockPosition, t, i + this.currentTick, tickListPriority);
+ }
+
+ public void schedule(final NextTickListEntry<T> entry) {
@ -493,7 +497,7 @@ index 0000000000000000000000000000000000000000..bbb042fec32ce5a4aecf1934ab6bed77
+ }
+
+ if (WARN_ON_EXCESSIVE_DELAY) {
+ final long delay = entry.getTargetTick() - this.nextTick;
+ final long delay = entry.getTargetTick() - this.currentTick;
+ if (delay >= EXCESSIVE_DELAY_THRESHOLD) {
+ MinecraftServer.LOGGER.warn("Entry " + entry.toString() + " has been scheduled with an excessive delay of: " + delay, new Throwable());
+ }
@ -651,7 +655,7 @@ index 0000000000000000000000000000000000000000..bbb042fec32ce5a4aecf1934ab6bed77
+ // start copy from TickListServer // TODO check on update
+ List<NextTickListEntry<T>> list = this.getEntriesInChunk(chunkcoordintpair, false, true);
+
+ return TickListServer.serialize(this.getMinecraftKeyFrom, list, this.nextTick);
+ return TickListServer.serialize(this.getMinecraftKeyFrom, list, this.currentTick);
+ // end copy from TickListServer
+ }
+
@ -1069,12 +1073,17 @@ index f94234b0a247e378ff9056d6c418464d619a356b..8af1229c3da63a838b0bec1cafde1e41
}
diff --git a/src/main/java/net/minecraft/server/TickListServer.java b/src/main/java/net/minecraft/server/TickListServer.java
index 3b8f56c0f0507ebdd9ac20be70688b4c0cfe4cf8..149d2b4f929c11b8baf17163bbd6ff8220a95e86 100644
index 3b8f56c0f0507ebdd9ac20be70688b4c0cfe4cf8..3e148b7e99554a1abe257dd3c9acafb914e1ebc8 100644
--- a/src/main/java/net/minecraft/server/TickListServer.java
+++ b/src/main/java/net/minecraft/server/TickListServer.java
@@ -39,6 +39,11 @@ public class TickListServer<T> implements TickList<T> {
@@ -38,7 +38,16 @@ public class TickListServer<T> implements TickList<T> {
private final co.aikar.timings.Timing timingTicking; // Paper
// Paper end
+ // Paper start
+ protected void nextTick() {}
+ // Paper end
+
public void b() {
+ // Paper start - allow overriding
+ this.tick();
@ -1084,7 +1093,7 @@ index 3b8f56c0f0507ebdd9ac20be70688b4c0cfe4cf8..149d2b4f929c11b8baf17163bbd6ff82
int i = this.nextTickList.size();
if (false) { // CraftBukkit
@@ -106,10 +111,20 @@ public class TickListServer<T> implements TickList<T> {
@@ -106,10 +115,20 @@ public class TickListServer<T> implements TickList<T> {
@Override
public boolean b(BlockPosition blockposition, T t0) {
@ -1105,7 +1114,7 @@ index 3b8f56c0f0507ebdd9ac20be70688b4c0cfe4cf8..149d2b4f929c11b8baf17163bbd6ff82
int i = (chunkcoordintpair.x << 4) - 2;
int j = i + 16 + 2;
int k = (chunkcoordintpair.z << 4) - 2;
@@ -119,6 +134,11 @@ public class TickListServer<T> implements TickList<T> {
@@ -119,6 +138,11 @@ public class TickListServer<T> implements TickList<T> {
}
public List<NextTickListEntry<T>> a(StructureBoundingBox structureboundingbox, boolean flag, boolean flag1) {
@ -1117,7 +1126,7 @@ index 3b8f56c0f0507ebdd9ac20be70688b4c0cfe4cf8..149d2b4f929c11b8baf17163bbd6ff82
List<NextTickListEntry<T>> list = this.a((List) null, this.nextTickList, structureboundingbox, flag);
if (flag && list != null) {
@@ -158,6 +178,11 @@ public class TickListServer<T> implements TickList<T> {
@@ -158,6 +182,11 @@ public class TickListServer<T> implements TickList<T> {
}
public void a(StructureBoundingBox structureboundingbox, BlockPosition blockposition) {
@ -1129,7 +1138,7 @@ index 3b8f56c0f0507ebdd9ac20be70688b4c0cfe4cf8..149d2b4f929c11b8baf17163bbd6ff82
List<NextTickListEntry<T>> list = this.a(structureboundingbox, false, false);
Iterator iterator = list.iterator();
@@ -175,11 +200,17 @@ public class TickListServer<T> implements TickList<T> {
@@ -175,11 +204,17 @@ public class TickListServer<T> implements TickList<T> {
}
public NBTTagList a(ChunkCoordIntPair chunkcoordintpair) {
@ -1147,7 +1156,7 @@ index 3b8f56c0f0507ebdd9ac20be70688b4c0cfe4cf8..149d2b4f929c11b8baf17163bbd6ff82
private static <T> NBTTagList a(Function<T, MinecraftKey> function, Iterable<NextTickListEntry<T>> iterable, long i) {
NBTTagList nbttaglist = new NBTTagList();
Iterator iterator = iterable.iterator();
@@ -202,11 +233,21 @@ public class TickListServer<T> implements TickList<T> {
@@ -202,11 +237,21 @@ public class TickListServer<T> implements TickList<T> {
@Override
public boolean a(BlockPosition blockposition, T t0) {
@ -1169,7 +1178,7 @@ index 3b8f56c0f0507ebdd9ac20be70688b4c0cfe4cf8..149d2b4f929c11b8baf17163bbd6ff82
if (!this.a.test(t0)) {
this.a(new NextTickListEntry<>(blockposition, t0, (long) i + this.e.getTime(), ticklistpriority));
}
@@ -222,6 +263,11 @@ public class TickListServer<T> implements TickList<T> {
@@ -222,6 +267,11 @@ public class TickListServer<T> implements TickList<T> {
}
public int a() {
@ -1182,7 +1191,7 @@ index 3b8f56c0f0507ebdd9ac20be70688b4c0cfe4cf8..149d2b4f929c11b8baf17163bbd6ff82
}
}
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
index d41981a5dc4beb9d63f52abea5653067144be932..a8a843f76e4161bb1afb7b44a6cce933a8104001 100644
index d41981a5dc4beb9d63f52abea5653067144be932..eebd453bfaeb99b8fdf0d11ee8888f27ad2afff2 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -181,6 +181,15 @@ public class WorldServer extends World implements GeneratorAccessSeed {
@ -1229,3 +1238,14 @@ index d41981a5dc4beb9d63f52abea5653067144be932..a8a843f76e4161bb1afb7b44a6cce933
this.navigators = Sets.newHashSet();
this.L = new ObjectLinkedOpenHashSet();
this.Q = flag1;
@@ -526,7 +544,9 @@ public class WorldServer extends World implements GeneratorAccessSeed {
if (this.Q) {
long i = this.worldData.getTime() + 1L;
- this.worldDataServer.setTime(i);
+ this.worldDataServer.setTime(i); // Paper - diff on change, we want the below to be ran right after this
+ this.nextTickListBlock.nextTick(); // Paper
+ this.nextTickListFluid.nextTick(); // Paper
this.worldDataServer.t().a(this.server, i);
if (this.worldData.p().getBoolean(GameRules.DO_DAYLIGHT_CYCLE)) {
this.setDayTime(this.worldData.getDayTime() + 1L);

View file

@ -23,7 +23,7 @@ index c49d157b8ca25f9811bf64396c207b1c1d6e085d..e895bf811ce5d441541725ade48e3f07
private boolean locked = false;
@Override
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
index a8a843f76e4161bb1afb7b44a6cce933a8104001..815a668c60e6302940545259cce60e2dbe608464 100644
index eebd453bfaeb99b8fdf0d11ee8888f27ad2afff2..0e28e829474bea693550b3b2f0e72f97ff9bb10e 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -530,6 +530,7 @@ public class WorldServer extends World implements GeneratorAccessSeed {
@ -34,7 +34,7 @@ index a8a843f76e4161bb1afb7b44a6cce933a8104001..815a668c60e6302940545259cce60e2d
this.registerEntity(entity2);
}
@@ -1226,6 +1227,19 @@ public class WorldServer extends World implements GeneratorAccessSeed {
@@ -1228,6 +1229,19 @@ public class WorldServer extends World implements GeneratorAccessSeed {
public void unregisterEntity(Entity entity) {
org.spigotmc.AsyncCatcher.catchOp("entity unregister"); // Spigot
@ -54,7 +54,7 @@ index a8a843f76e4161bb1afb7b44a6cce933a8104001..815a668c60e6302940545259cce60e2d
// Spigot start
if ( entity instanceof EntityHuman )
{
@@ -1292,9 +1306,21 @@ public class WorldServer extends World implements GeneratorAccessSeed {
@@ -1294,9 +1308,21 @@ public class WorldServer extends World implements GeneratorAccessSeed {
private void registerEntity(Entity entity) {
org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot

View file

@ -15,10 +15,10 @@ Combine that with a buggy detail of the previous implementation of
the Dupe UUID patch, then this was the likely source of the "Ghost entities"
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
index 815a668c60e6302940545259cce60e2dbe608464..26f82291ded548f7d623668d95d74833d5211709 100644
index 0e28e829474bea693550b3b2f0e72f97ff9bb10e..0038ba4153ce3bb894968ce848f844800361c44a 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -1385,9 +1385,9 @@ public class WorldServer extends World implements GeneratorAccessSeed {
@@ -1387,9 +1387,9 @@ public class WorldServer extends World implements GeneratorAccessSeed {
}
private void removeEntityFromChunk(Entity entity) {

View file

@ -26,10 +26,10 @@ index 2542b24b0e1919fdc28417df718acd766deefd03..d4207cb622bf17314f77831c604c8ba9
EntityTypes<?> entitytypes = entity.getEntityType();
int i = entitytypes.getChunkRange() * 16;
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
index 26f82291ded548f7d623668d95d74833d5211709..3ebb6140b248925c53bc8912d4eeaced00d30fe2 100644
index 0038ba4153ce3bb894968ce848f844800361c44a..1fabe0a99e796f423adf4a6c51811b462745c537 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -1351,7 +1351,7 @@ public class WorldServer extends World implements GeneratorAccessSeed {
@@ -1353,7 +1353,7 @@ public class WorldServer extends World implements GeneratorAccessSeed {
}
}
@ -38,7 +38,7 @@ index 26f82291ded548f7d623668d95d74833d5211709..3ebb6140b248925c53bc8912d4eeaced
// CraftBukkit start - SPIGOT-5278
if (entity instanceof EntityDrowned) {
this.navigators.add(((EntityDrowned) entity).navigationWater);
@@ -1362,6 +1362,7 @@ public class WorldServer extends World implements GeneratorAccessSeed {
@@ -1364,6 +1364,7 @@ public class WorldServer extends World implements GeneratorAccessSeed {
this.navigators.add(((EntityInsentient) entity).getNavigation());
}
entity.valid = true; // CraftBukkit

View file

@ -1340,10 +1340,10 @@ index 35f4d2d9591e625ab0bbeab7b606761e74965eec..698d82dd736529a8cbfad5c6bed70ab9
this.a.a(t0);
this.f();
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
index 2b04577c153fc4563e59b67afee12411a5de5314..d048ee2313142ba4b0fae7ef2badb9f80614bb62 100644
index a54e3ed06a7a1757d3c4ce96b21bed0177e1fa86..63c119072968586fab05ce3990f7c83373736f33 100644
--- a/src/main/java/net/minecraft/server/WorldServer.java
+++ b/src/main/java/net/minecraft/server/WorldServer.java
@@ -707,6 +707,7 @@ public class WorldServer extends World implements GeneratorAccessSeed {
@@ -709,6 +709,7 @@ public class WorldServer extends World implements GeneratorAccessSeed {
}
gameprofilerfiller.exit();
timings.chunkTicksBlocks.stopTiming(); // Paper