2022-01-05 09:01:21 +01:00
|
|
|
package net.minestom.server.thread;
|
|
|
|
|
|
|
|
import net.minestom.server.MinecraftServer;
|
2024-03-27 08:14:40 +01:00
|
|
|
import net.minestom.server.ServerFlag;
|
2022-01-05 09:01:21 +01:00
|
|
|
import net.minestom.server.ServerProcess;
|
|
|
|
import org.jetbrains.annotations.ApiStatus;
|
|
|
|
|
|
|
|
@ApiStatus.Internal
|
|
|
|
public final class TickSchedulerThread extends MinestomThread {
|
2024-03-27 08:14:40 +01:00
|
|
|
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;
|
2022-01-05 09:01:21 +01:00
|
|
|
|
2024-03-27 08:14:40 +01:00
|
|
|
private final ServerProcess serverProcess;
|
2024-01-16 04:06:38 +01:00
|
|
|
|
2022-01-05 09:01:21 +01:00
|
|
|
public TickSchedulerThread(ServerProcess serverProcess) {
|
|
|
|
super(MinecraftServer.THREAD_NAME_TICK_SCHEDULER);
|
|
|
|
this.serverProcess = serverProcess;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2024-03-29 21:16:06 +01:00
|
|
|
long ticks = 0;
|
|
|
|
long baseTime = System.nanoTime();
|
2022-01-05 09:01:21 +01:00
|
|
|
while (serverProcess.isAlive()) {
|
|
|
|
final long tickStart = System.nanoTime();
|
|
|
|
try {
|
|
|
|
serverProcess.ticker().tick(tickStart);
|
|
|
|
} catch (Exception e) {
|
|
|
|
serverProcess.exception().handleException(e);
|
|
|
|
}
|
2024-03-27 08:14:40 +01:00
|
|
|
|
2024-03-29 21:16:06 +01:00
|
|
|
ticks++;
|
|
|
|
long nextTickTime = baseTime + ticks * TICK_TIME_NANOS;
|
2024-03-27 08:14:40 +01:00
|
|
|
waitUntilNextTick(nextTickTime);
|
2024-03-29 21:16:06 +01:00
|
|
|
// 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;
|
|
|
|
}
|
2022-01-05 09:01:21 +01:00
|
|
|
}
|
|
|
|
}
|
2023-09-12 17:00:28 +02:00
|
|
|
|
2024-03-27 08:14:40 +01:00
|
|
|
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);
|
2023-09-12 17:00:28 +02:00
|
|
|
}
|
|
|
|
}
|
2024-03-27 08:14:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private void sleepThread(long time) {
|
|
|
|
try {
|
|
|
|
Thread.sleep(time);
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
serverProcess.exception().handleException(e);
|
|
|
|
}
|
2023-09-12 17:00:28 +02:00
|
|
|
}
|
2022-01-05 09:01:21 +01:00
|
|
|
}
|