Minestom/src/main/java/net/minestom/server/thread/TickSchedulerThread.java

67 lines
2.4 KiB
Java

package net.minestom.server.thread;
import net.minestom.server.MinecraftServer;
import net.minestom.server.ServerFlag;
import net.minestom.server.ServerProcess;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Internal
public final class TickSchedulerThread extends MinestomThread {
private static final long TICK_TIME_NANOS = 1_000_000_000L / ServerFlag.SERVER_TICKS_PER_SECOND;
// Windows has an issue with periodically being unable to sleep for < ~16ms at a time
private static final long SLEEP_THRESHOLD = System.getProperty("os.name", "")
.toLowerCase().startsWith("windows") ? 17 : 2;
private final ServerProcess serverProcess;
public TickSchedulerThread(ServerProcess serverProcess) {
super(MinecraftServer.THREAD_NAME_TICK_SCHEDULER);
this.serverProcess = serverProcess;
}
@Override
public void run() {
long ticks = 0;
long baseTime = System.nanoTime();
while (serverProcess.isAlive()) {
final long tickStart = System.nanoTime();
try {
serverProcess.ticker().tick(tickStart);
} catch (Exception e) {
serverProcess.exception().handleException(e);
}
ticks++;
long nextTickTime = baseTime + ticks * TICK_TIME_NANOS;
waitUntilNextTick(nextTickTime);
// Check if the server can not keep up with the tickrate
// if it gets too far behind, reset the ticks & baseTime
// to avoid running too many ticks at once
if (System.nanoTime() > nextTickTime + TICK_TIME_NANOS * ServerFlag.SERVER_MAX_TICK_CATCH_UP) {
baseTime = System.nanoTime();
ticks = 0;
}
}
}
private void waitUntilNextTick(long nextTickTimeNanos) {
long currentTime;
while ((currentTime = System.nanoTime()) < nextTickTimeNanos) {
long remainingTime = nextTickTimeNanos - currentTime;
// Sleep less the closer we are to the next tick
long remainingMilliseconds = remainingTime / 1_000_000L;
if (remainingMilliseconds >= SLEEP_THRESHOLD) {
sleepThread(remainingMilliseconds / 2);
}
}
}
private void sleepThread(long time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
serverProcess.exception().handleException(e);
}
}
}