This commit is contained in:
devreluije 2024-04-30 21:13:44 -06:00 committed by GitHub
commit a751940f40
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 55 additions and 11 deletions

View File

@ -194,6 +194,10 @@ public final class MinecraftServer {
return !isStarted(); return !isStarted();
} }
public static boolean isStopped() {
return serverProcess.isStopped();
}
/** /**
* Gets the chunk view distance of the server. * Gets the chunk view distance of the server.
* <p> * <p>

View File

@ -137,10 +137,29 @@ public interface ServerProcess extends Snapshotable {
void start(@NotNull SocketAddress socketAddress); void start(@NotNull SocketAddress socketAddress);
/**
* Request the server to stop
*/
void stop(); void stop();
/**
* Shutdown all sub processes
* <p>
* Order:
* <ul>
* {@link SchedulerManager#shutdown()}
* {@link ConnectionManager#shutdown()}
* {@link Server#stop()}
* {@link BenchmarkManager#disable()}
* {@link ThreadDispatcher#shutdown()}
* </ul>
*/
void shutdown();
boolean isAlive(); boolean isAlive();
boolean isStopped();
@ApiStatus.NonExtendable @ApiStatus.NonExtendable
interface Ticker { interface Ticker {
void tick(long nanoTime); void tick(long nanoTime);

View File

@ -71,6 +71,7 @@ final class ServerProcessImpl implements ServerProcess {
private final Ticker ticker; private final Ticker ticker;
private final AtomicBoolean started = new AtomicBoolean(); private final AtomicBoolean started = new AtomicBoolean();
private final AtomicBoolean stopping = new AtomicBoolean();
private final AtomicBoolean stopped = new AtomicBoolean(); private final AtomicBoolean stopped = new AtomicBoolean();
public ServerProcessImpl() throws IOException { public ServerProcessImpl() throws IOException {
@ -230,6 +231,13 @@ final class ServerProcessImpl implements ServerProcess {
@Override @Override
public void stop() { public void stop() {
if (!stopping.compareAndSet(false, true))
return;
LOGGER.info("Stopping " + MinecraftServer.getBrandName() + " server...");
}
@Override
public void shutdown() {
if (!stopped.compareAndSet(false, true)) if (!stopped.compareAndSet(false, true))
return; return;
LOGGER.info("Stopping " + MinecraftServer.getBrandName() + " server."); LOGGER.info("Stopping " + MinecraftServer.getBrandName() + " server.");
@ -242,9 +250,14 @@ final class ServerProcessImpl implements ServerProcess {
LOGGER.info(MinecraftServer.getBrandName() + " server stopped successfully."); LOGGER.info(MinecraftServer.getBrandName() + " server stopped successfully.");
} }
@Override
public boolean isStopped() {
return stopped.get();
}
@Override @Override
public boolean isAlive() { public boolean isAlive() {
return started.get() && !stopped.get(); return started.get() && !stopping.get() && !stopped.get();
} }
@Override @Override

View File

@ -23,6 +23,7 @@ public final class TickSchedulerThread extends MinestomThread {
public void run() { public void run() {
long ticks = 0; long ticks = 0;
long baseTime = System.nanoTime(); long baseTime = System.nanoTime();
while (serverProcess.isAlive()) { while (serverProcess.isAlive()) {
final long tickStart = System.nanoTime(); final long tickStart = System.nanoTime();
try { try {
@ -32,16 +33,20 @@ public final class TickSchedulerThread extends MinestomThread {
} }
ticks++; ticks++;
long nextTickTime = baseTime + ticks * TICK_TIME_NANOS; // don't wait next tick if server is stopping/stopped
waitUntilNextTick(nextTickTime); if (serverProcess.isAlive()) {
// Check if the server can not keep up with the tickrate long nextTickTime = baseTime + ticks * TICK_TIME_NANOS;
// if it gets too far behind, reset the ticks & baseTime waitUntilNextTick(nextTickTime);
// to avoid running too many ticks at once // Check if the server can not keep up with the tickrate
if (System.nanoTime() > nextTickTime + TICK_TIME_NANOS * ServerFlag.SERVER_MAX_TICK_CATCH_UP) { // if it gets too far behind, reset the ticks & baseTime
baseTime = System.nanoTime(); // to avoid running too many ticks at once
ticks = 0; if (System.nanoTime() > nextTickTime + TICK_TIME_NANOS * ServerFlag.SERVER_MAX_TICK_CATCH_UP) {
baseTime = System.nanoTime();
ticks = 0;
}
} }
} }
serverProcess.shutdown();
} }
private void waitUntilNextTick(long nextTickTimeNanos) { private void waitUntilNextTick(long nextTickTimeNanos) {

View File

@ -5,8 +5,7 @@ import org.junit.jupiter.api.Test;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assumptions.assumeTrue; import static org.junit.jupiter.api.Assumptions.assumeTrue;
public class ServerProcessTest { public class ServerProcessTest {
@ -21,6 +20,8 @@ public class ServerProcessTest {
assertDoesNotThrow(() -> process.get().start(new InetSocketAddress("localhost", 25565))); assertDoesNotThrow(() -> process.get().start(new InetSocketAddress("localhost", 25565)));
assertThrows(Exception.class, () -> process.get().start(new InetSocketAddress("localhost", 25566))); assertThrows(Exception.class, () -> process.get().start(new InetSocketAddress("localhost", 25566)));
assertDoesNotThrow(() -> process.get().stop()); assertDoesNotThrow(() -> process.get().stop());
assertFalse(() -> process.get().isAlive(), "Server is still alive");
assertDoesNotThrow(() -> process.get().shutdown());
} }
@Test @Test
@ -33,5 +34,7 @@ public class ServerProcessTest {
var ticker = process.ticker(); var ticker = process.ticker();
assertDoesNotThrow(() -> ticker.tick(System.currentTimeMillis())); assertDoesNotThrow(() -> ticker.tick(System.currentTimeMillis()));
assertDoesNotThrow(process::stop); assertDoesNotThrow(process::stop);
assertFalse(process::isAlive, "Server is still alive");
assertDoesNotThrow(process::shutdown);
} }
} }