mirror of
https://github.com/Minestom/Minestom.git
synced 2025-02-19 13:51:22 +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;
|
package net.minestom.server.thread;
|
||||||
|
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
|
import net.minestom.server.ServerFlag;
|
||||||
import net.minestom.server.ServerProcess;
|
import net.minestom.server.ServerProcess;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
import java.util.concurrent.locks.LockSupport;
|
|
||||||
|
|
||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
public final class TickSchedulerThread extends MinestomThread {
|
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 final ServerProcess serverProcess;
|
||||||
private long tick = 1;
|
|
||||||
|
|
||||||
public TickSchedulerThread(ServerProcess serverProcess) {
|
public TickSchedulerThread(ServerProcess serverProcess) {
|
||||||
super(MinecraftServer.THREAD_NAME_TICK_SCHEDULER);
|
super(MinecraftServer.THREAD_NAME_TICK_SCHEDULER);
|
||||||
@ -20,7 +21,7 @@ public final class TickSchedulerThread extends MinestomThread {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
final long tickNs = (long) (MinecraftServer.TICK_MS * 1e6);
|
long timeOverslept = 0;
|
||||||
while (serverProcess.isAlive()) {
|
while (serverProcess.isAlive()) {
|
||||||
final long tickStart = System.nanoTime();
|
final long tickStart = System.nanoTime();
|
||||||
try {
|
try {
|
||||||
@ -28,23 +29,31 @@ public final class TickSchedulerThread extends MinestomThread {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
serverProcess.exception().handleException(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) {
|
private void waitUntilNextTick(long nextTickTimeNanos) {
|
||||||
long nextTickNs = startTickNs + (tickNs * tick);
|
long currentTime;
|
||||||
if (System.nanoTime() < nextTickNs) {
|
while ((currentTime = System.nanoTime()) < nextTickTimeNanos) {
|
||||||
while (true) {
|
long remainingTime = nextTickTimeNanos - currentTime;
|
||||||
// Checks in every 1/10 ms to see if the current time has reached the next scheduled time.
|
// Sleep less the closer we are to the next tick
|
||||||
Thread.yield();
|
long remainingMilliseconds = remainingTime / 1_000_000L;
|
||||||
LockSupport.parkNanos(100000);
|
if (remainingMilliseconds >= SLEEP_THRESHOLD) {
|
||||||
long currentNs = System.nanoTime();
|
sleepThread(remainingMilliseconds / 2);
|
||||||
if (currentNs >= nextTickNs) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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