Skip to content

Commit

Permalink
Fix and cleanup modern tick loop (#253)
Browse files Browse the repository at this point in the history
  • Loading branch information
uRyanxD authored Oct 28, 2024
1 parent 1413f4b commit 33e3e38
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 63 deletions.
97 changes: 59 additions & 38 deletions patches/server/0004-Backport-modern-tick-loop.patch
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ index 088beb22b53ddf77dc182dd5ac39e1086d5279aa..6434b8613971a228fb0074390d8223bf
Thread thread = new Thread("Server Infinisleeper") {
{
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 7d19ec833d61c2f75b5eb75d7eb291c7366a1a9a..eae936650fddd5ef418ee2ddd680d36e82045365 100644
index 7d19ec833d61c2f75b5eb75d7eb291c7366a1a9a..f411b611fc8b35fc60882d0123f01de49380b4b0 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -48,7 +48,7 @@ import org.bukkit.craftbukkit.Main;
Expand All @@ -243,13 +243,21 @@ index 7d19ec833d61c2f75b5eb75d7eb291c7366a1a9a..eae936650fddd5ef418ee2ddd680d36e

public static final Logger LOGGER = LogManager.getLogger();
public static final File a = new File("usercache.json");
@@ -117,7 +117,36 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
@@ -102,7 +102,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
private final UserCache Z;
protected final Queue<FutureTask<?>> j = new java.util.concurrent.ConcurrentLinkedQueue<FutureTask<?>>(); // Spigot, PAIL: Rename
private Thread serverThread;
- private long ab = az();
+ private long ab; // PandaSpigot - The az() initializer is redundant

// CraftBukkit start
public List<WorldServer> worlds = new ArrayList<WorldServer>();
@@ -117,7 +117,35 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
public int autosavePeriod;
// CraftBukkit end

- public MinecraftServer(OptionSet options, Proxy proxy, File file1) {
+ // PandaSpigot start - Modern tick loop
+ private long nextTickTime;
+ private long delayedTasksMaxNextTickTime;
+ private boolean mayHaveDelayedTasks;
+ private boolean forceTicks;
Expand All @@ -274,14 +282,14 @@ index 7d19ec833d61c2f75b5eb75d7eb291c7366a1a9a..eae936650fddd5ef418ee2ddd680d36e
+
+ public MinecraftServer(OptionSet options, Proxy proxy, File file1, Thread thread) {
+ super("Server");
+ this.nextTickTime = getMillis();
+ this.ab = az();
+ this.primaryThread = thread;
+ this.serverThread = thread;
+ // PandaSpigot end
io.netty.util.ResourceLeakDetector.setEnabled( false ); // Spigot - disable
this.e = proxy;
MinecraftServer.l = this;
@@ -154,7 +183,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
@@ -154,7 +182,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
}
Runtime.getRuntime().addShutdownHook(new org.bukkit.craftbukkit.util.ServerShutdownThread(this));

Expand All @@ -290,22 +298,14 @@ index 7d19ec833d61c2f75b5eb75d7eb291c7366a1a9a..eae936650fddd5ef418ee2ddd680d36e
}

public abstract PropertyManager getPropertyManager();
@@ -557,12 +586,21 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
}
@@ -558,11 +586,14 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
}
// PaperSpigot End
-
+

+ // PandaSpigot start - Modern tick loop
+ public static long getMillis() {
+ return getNanos() / 1000000L;
+ }
+ public static long getNanos() {
+ return System.nanoTime();
+ }
public void run() {
try {
+ this.serverStartTime = getNanos();
+ this.serverStartTime = az();
+ // PandaSpigot end
if (this.init()) {
this.ab = az();
Expand All @@ -314,7 +314,7 @@ index 7d19ec833d61c2f75b5eb75d7eb291c7366a1a9a..eae936650fddd5ef418ee2ddd680d36e

this.r.setMOTD(new ChatComponentText(this.motd));
this.r.setServerInfo(new ServerPing.ServerData("1.8.8", 47));
@@ -572,31 +610,21 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
@@ -572,31 +603,21 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
// PaperSpigot start - Further improve tick loop
Arrays.fill( recentTps, 20 );
//long lastTick = System.nanoTime(), catchupTime = 0, curTime, wait, tickSection = lastTick;
Expand All @@ -339,61 +339,61 @@ index 7d19ec833d61c2f75b5eb75d7eb291c7366a1a9a..eae936650fddd5ef418ee2ddd680d36e
- wait -= catchupTime;
- catchupTime -= catchupTime;
- }
- }
- if (wait > 0) {
- Thread.sleep(wait / 1000000);
- wait = TICK_TIME - (curTime - lastTick);
+ // PandaSpigot start - Modern tick loop
+ long i = ((curTime = System.nanoTime()) / (1000L * 1000L)) - this.nextTickTime; // Paper
+ if (i > 5000L && this.nextTickTime - this.lastOverloadWarning >= 30000L && ticks > 500) { // CraftBukkit
+ long i = ((curTime = System.nanoTime()) / (1000L * 1000L)) - ab;
+ if (i > 5000L && this.ab - this.lastOverloadWarning >= 30000L && ticks > 500) {
+ long j = i / 50L;
+ if (this.server.getWarnOnOverload()) // CraftBukkit
+ MinecraftServer.LOGGER.warn("Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", i, j);
+ this.nextTickTime += j * 50L;
+ this.lastOverloadWarning = this.nextTickTime;
+ this.ab += j * 50L;
+ this.lastOverloadWarning = this.ab;
}
- if (wait > 0) {
- Thread.sleep(wait / 1000000);
- wait = TICK_TIME - (curTime - lastTick);
- }
-
- catchupTime = Math.min(MAX_CATCHUP_BUFFER, catchupTime - wait);
-
if ( ++MinecraftServer.currentTick % SAMPLE_INTERVAL == 0 )
{
final long diff = curTime - tickSection;
@@ -613,8 +641,16 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
@@ -613,8 +634,16 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
}
lastTick = curTime;

- this.A();
- this.Q = true;
+ this.nextTickTime += 50L;
+ this.ab += 50L;
+ this.methodProfiler.a("tick");
+ this.A(this::haveTime);
+ this.methodProfiler.c("nextTickWait");
+ this.mayHaveDelayedTasks = true;
+ this.delayedTasksMaxNextTickTime = Math.max(getMillis() + 50L, this.nextTickTime);
+ this.delayedTasksMaxNextTickTime = Math.max(az() + 50L, this.ab);
+ this.waitUntilNextTick();
+ this.methodProfiler.b();
+ this.isReady = true;
+ // PandaSpigot end
}
// Spigot end
} else {
@@ -665,6 +701,62 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
@@ -665,6 +694,62 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
}

}
+ // PandaSpigot start - Modern tick loop
+ private boolean haveTime() {
+ if (isOversleep) return canOversleep();
+ return this.forceTicks || this.runningTask() || getMillis() < (this.mayHaveDelayedTasks ? this.delayedTasksMaxNextTickTime : this.nextTickTime);
+ return this.forceTicks || this.runningTask() || az() < (this.mayHaveDelayedTasks ? this.delayedTasksMaxNextTickTime : this.ab);
+ }
+
+ boolean isOversleep = false;
+ private boolean canOversleep() {
+ return this.mayHaveDelayedTasks && getMillis() < this.delayedTasksMaxNextTickTime;
+ return this.mayHaveDelayedTasks && az() < this.delayedTasksMaxNextTickTime;
+ }
+
+ private boolean canSleepForTickNoOversleep() {
+ return this.forceTicks || this.runningTask() || getMillis() < this.nextTickTime;
+ return this.forceTicks || this.runningTask() || az() < this.ab;
+ }
+
+ private void executeModerately() {
Expand Down Expand Up @@ -440,7 +440,7 @@ index 7d19ec833d61c2f75b5eb75d7eb291c7366a1a9a..eae936650fddd5ef418ee2ddd680d36e

private void a(ServerPing serverping) {
File file = this.d("server-icon.png");
@@ -698,9 +790,15 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
@@ -698,9 +783,15 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs

protected void z() {}

Expand All @@ -457,7 +457,7 @@ index 7d19ec833d61c2f75b5eb75d7eb291c7366a1a9a..eae936650fddd5ef418ee2ddd680d36e

++this.ticks;
if (this.T) {
@@ -744,6 +842,11 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
@@ -744,6 +835,11 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
SpigotTimings.worldSaveTimer.stopTiming(); // Spigot
}

Expand All @@ -469,31 +469,52 @@ index 7d19ec833d61c2f75b5eb75d7eb291c7366a1a9a..eae936650fddd5ef418ee2ddd680d36e
this.methodProfiler.a("tallying");
this.h[this.ticks % 100] = System.nanoTime() - i;
this.methodProfiler.b();
@@ -981,6 +1084,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
@@ -981,6 +1077,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
});
*/

+ /* // PandaSpigot start - comment out
DedicatedServer dedicatedserver = new DedicatedServer(options);

if (options.has("port")) {
@@ -1000,6 +1104,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
@@ -1000,6 +1097,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs

dedicatedserver.primaryThread.start();
// CraftBukkit end
+ */ // PandaSpigot end
} catch (Exception exception) {
MinecraftServer.LOGGER.fatal("Failed to start the minecraft server", exception);
}
@@ -1483,7 +1588,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
@@ -1483,7 +1581,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
}

public static long az() {
- return System.currentTimeMillis();
+ return getMillis(); // PandaSpigot - Modern tick loop
+ return SystemUtils.getMonotonicMillis(); // PandaSpigot - Modern tick loop
}

public int getIdleTimeout() {
diff --git a/src/main/java/net/minecraft/server/SystemUtils.java b/src/main/java/net/minecraft/server/SystemUtils.java
index e65ffc1566784f8a35a4a620514375b9077ce247..0c23e540a300590f967a681a3a8cf65bfc4f1377 100644
--- a/src/main/java/net/minecraft/server/SystemUtils.java
+++ b/src/main/java/net/minecraft/server/SystemUtils.java
@@ -6,6 +6,16 @@ import org.apache.logging.log4j.Logger;

public class SystemUtils {

+ // PandaSpigot start - Modern Tick Loop
+ public static long getMonotonicMillis() {
+ return getMonotonicNanos() / 1000000L;
+ }
+
+ public static long getMonotonicNanos() {
+ return System.nanoTime();
+ }
+ // PandaSpigot end
+
public static <V> V a(FutureTask<V> futuretask, Logger logger) {
try {
futuretask.run();
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
index c936219196ea403a9d247ad6c8c0ffee79411da2..5c980fe2907d2ff01be793ab0654ab198f46e519 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ Subject: [PATCH] Consolidate flush calls for entity tracker packets
Most server packets seem to be sent from here, so try to avoid expensive flush calls from them.

diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index eae936650fddd5ef418ee2ddd680d36e82045365..06e023994050a07d2efed174b1fbd8f1eddcd231 100644
index 15202423fba6a0661222a00be2c0aa1b5d64e906..7e6bad78c9b7a05d1def63a77610fd6c332b8c85 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -963,7 +963,26 @@ public abstract class MinecraftServer extends com.hpfxd.pandaspigot.tickloop.Ree
@@ -956,7 +956,26 @@ public abstract class MinecraftServer extends com.hpfxd.pandaspigot.tickloop.Ree
this.methodProfiler.b();
this.methodProfiler.a("tracker");
worldserver.timings.tracker.startTiming(); // Spigot
Expand Down
4 changes: 2 additions & 2 deletions patches/server/0017-Optimize-World-Time-Updates.patch
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ the updates per world, so that we can re-use the same packet
object for every player unless they have per-player time enabled.

diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 06e023994050a07d2efed174b1fbd8f1eddcd231..8f394d5fe6f0f0640a942f15ae69582bfd70b4c8 100644
index 7e6bad78c9b7a05d1def63a77610fd6c332b8c85..f213f9db49acb9efff02178556d6eec969f4d9c1 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -899,12 +899,24 @@ public abstract class MinecraftServer extends com.hpfxd.pandaspigot.tickloop.Ree
@@ -892,12 +892,24 @@ public abstract class MinecraftServer extends com.hpfxd.pandaspigot.tickloop.Ree

SpigotTimings.timeUpdateTimer.startTiming(); // Spigot
// Send time updates to everyone, it will get the right time from the world the player is in.
Expand Down
4 changes: 2 additions & 2 deletions patches/server/0018-Configurable-time-update-frequency.patch
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ index 3dd3d0702c17541083d0d365ca46e93602105bce..b5f16e8cab9e43ad7597b2ea5bc92139
public KnockbackConfig knockback;

diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 8f394d5fe6f0f0640a942f15ae69582bfd70b4c8..b7decb879f530345b82722aeb1294864feecd2c2 100644
index f213f9db49acb9efff02178556d6eec969f4d9c1..eafa8ca822b79c8f31e43b484ce27b500a979bf5 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -906,7 +906,7 @@ public abstract class MinecraftServer extends com.hpfxd.pandaspigot.tickloop.Ree
@@ -899,7 +899,7 @@ public abstract class MinecraftServer extends com.hpfxd.pandaspigot.tickloop.Ree
long worldTime = world.getTime();
final PacketPlayOutUpdateTime worldPacket = new PacketPlayOutUpdateTime(worldTime, dayTime, doDaylight);
for (EntityHuman entityhuman : world.players) {
Expand Down
4 changes: 2 additions & 2 deletions patches/server/0023-EntityMoveEvent.patch
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ index 72c7e6fc8bb0a71877d6759af44d39030bcf51f5..1353a791235ae3b820072fa80ef60c3c

protected void doTick() {}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index b7decb879f530345b82722aeb1294864feecd2c2..66d4c410c2bcc345bf09e07a63de7534064524d2 100644
index eafa8ca822b79c8f31e43b484ce27b500a979bf5..5a0cf1ba4d7f7fbc9b62a60201682244e5dd56ff 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -926,6 +926,7 @@ public abstract class MinecraftServer extends com.hpfxd.pandaspigot.tickloop.Ree
@@ -919,6 +919,7 @@ public abstract class MinecraftServer extends com.hpfxd.pandaspigot.tickloop.Ree

// if (i == 0 || this.getAllowNether()) {
WorldServer worldserver = this.worlds.get(i);
Expand Down
6 changes: 3 additions & 3 deletions patches/server/0030-Cleanup-allocated-favicon-ByteBuf.patch
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@ Cleanups a bytebuffer which was allocated during the encoding of the
favicon to be sent to the client.

diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index f6d1510fc16fc48be221cc7bb5968a132a2b9752..faf566f647d161160c6c01ae4fa500f38dc61b8c 100644
index 5a0cf1ba4d7f7fbc9b62a60201682244e5dd56ff..348c63892aef13e70f38cbc7989c0b4d994873b9 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -763,6 +763,7 @@ public abstract class MinecraftServer extends com.hpfxd.pandaspigot.tickloop.Ree
@@ -756,6 +756,7 @@ public abstract class MinecraftServer extends com.hpfxd.pandaspigot.tickloop.Ree

if (file.isFile()) {
ByteBuf bytebuf = Unpooled.buffer();
+ ByteBuf bytebuf1 = null; // PandaSpigot - cleanup favicon bytebuf

try {
BufferedImage bufferedimage = ImageIO.read(file);
@@ -770,13 +771,14 @@ public abstract class MinecraftServer extends com.hpfxd.pandaspigot.tickloop.Ree
@@ -763,13 +764,14 @@ public abstract class MinecraftServer extends com.hpfxd.pandaspigot.tickloop.Ree
Validate.validState(bufferedimage.getWidth() == 64, "Must be 64 pixels wide", new Object[0]);
Validate.validState(bufferedimage.getHeight() == 64, "Must be 64 pixels high", new Object[0]);
ImageIO.write(bufferedimage, "PNG", new ByteBufOutputStream(bytebuf));
Expand Down
4 changes: 2 additions & 2 deletions patches/server/0035-Optimize-Network-Queue.patch
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ index 0000000000000000000000000000000000000000..c8540d16defdc633113b504616794f44
+ }
+}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index b784f8174b94c6fab41ed3262009383a2ffba3cc..26f1e07cefd54afe3df1b8ce8e4d58b26619c8d3 100644
index e6466f470adddbaf438b98c559a27d5d13bccacd..6392695bf426536709967f744d511ed9de823a96 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -100,7 +100,7 @@ public abstract class MinecraftServer extends com.hpfxd.pandaspigot.tickloop.Ree
Expand All @@ -55,5 +55,5 @@ index b784f8174b94c6fab41ed3262009383a2ffba3cc..26f1e07cefd54afe3df1b8ce8e4d58b2
- protected final Queue<FutureTask<?>> j = new java.util.concurrent.ConcurrentLinkedQueue<FutureTask<?>>(); // Spigot, PAIL: Rename
+ protected final Queue<FutureTask<?>> j = new com.destroystokyo.paper.utils.CachedSizeConcurrentLinkedQueue<>(); // Spigot, PAIL: Rename // PandaSpigot - Make size() constant-time
private Thread serverThread;
private long ab = az();
private long ab; // PandaSpigot - The az() initializer is redundant

4 changes: 2 additions & 2 deletions patches/server/0036-Backport-PlayerProfile-API.patch
Original file line number Diff line number Diff line change
Expand Up @@ -320,10 +320,10 @@ index 9034e1ad7a013c7288e68322a65798e40d8b851d..86ab9994079c6e18e3aed885db4171d0
public EntityFishingHook hookedFish;
public boolean affectsSpawning = true; // PaperSpigot
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 0f893196390e04f8c512f401612c5d455e25bec1..75716099df3c3afc9e5857258ed6d1b271c4b957 100644
index 8cfc553b059db22a2deb4c86210edb705d41e2ac..ad16adf4dc9775bc7c2553d6a67b4ff08f52cc1d 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1641,6 +1641,7 @@ public abstract class MinecraftServer extends com.hpfxd.pandaspigot.tickloop.Ree
@@ -1634,6 +1634,7 @@ public abstract class MinecraftServer extends com.hpfxd.pandaspigot.tickloop.Ree
return true;
}

Expand Down
Loading

0 comments on commit 33e3e38

Please sign in to comment.