mirror of
https://github.com/Minestom/Minestom.git
synced 2025-02-16 04:11:39 +01:00
feat: improve server ticking accuracy, transition to Thread#sleep and… (#2054)
* feat: improve server ticking accuracy, transition to Thread#sleep and compensate for ticks that take too long * feat: use nano time instead of milliseconds and add compensation for the rare case of the server oversleeping
This commit is contained in:
parent
ceeab08a2a
commit
d04e9e3e71
@ -1,17 +1,18 @@
|
||||
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;
|
||||
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public final class TickSchedulerThread extends MinestomThread {
|
||||
private final ServerProcess serverProcess;
|
||||
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 long startTickNs = System.nanoTime();
|
||||
private long tick = 1;
|
||||
private final ServerProcess serverProcess;
|
||||
|
||||
public TickSchedulerThread(ServerProcess serverProcess) {
|
||||
super(MinecraftServer.THREAD_NAME_TICK_SCHEDULER);
|
||||
@ -20,7 +21,7 @@ public final class TickSchedulerThread extends MinestomThread {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final long tickNs = (long) (MinecraftServer.TICK_MS * 1e6);
|
||||
long timeOverslept = 0;
|
||||
while (serverProcess.isAlive()) {
|
||||
final long tickStart = System.nanoTime();
|
||||
try {
|
||||
@ -28,23 +29,31 @@ public final class TickSchedulerThread extends MinestomThread {
|
||||
} catch (Exception e) {
|
||||
serverProcess.exception().handleException(e);
|
||||
}
|
||||
fixTickRate(tickNs);
|
||||
|
||||
long tickEnd = System.nanoTime();
|
||||
long nextTickTime = tickEnd + TICK_TIME_NANOS - (tickEnd - tickStart) - timeOverslept;
|
||||
waitUntilNextTick(nextTickTime);
|
||||
timeOverslept = System.nanoTime() - nextTickTime;
|
||||
}
|
||||
}
|
||||
|
||||
private void fixTickRate(long tickNs) {
|
||||
long nextTickNs = startTickNs + (tickNs * tick);
|
||||
if (System.nanoTime() < nextTickNs) {
|
||||
while (true) {
|
||||
// Checks in every 1/10 ms to see if the current time has reached the next scheduled time.
|
||||
Thread.yield();
|
||||
LockSupport.parkNanos(100000);
|
||||
long currentNs = System.nanoTime();
|
||||
if (currentNs >= nextTickNs) {
|
||||
break;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
tick++;
|
||||
}
|
||||
|
||||
private void sleepThread(long time) {
|
||||
try {
|
||||
Thread.sleep(time);
|
||||
} catch (InterruptedException e) {
|
||||
serverProcess.exception().handleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user