diff --git a/registry/src/main/java/nl/andrewl/aos2registryapi/ServerRegistry.java b/registry/src/main/java/nl/andrewl/aos2registryapi/ServerRegistry.java index 21176c4..3437dcd 100644 --- a/registry/src/main/java/nl/andrewl/aos2registryapi/ServerRegistry.java +++ b/registry/src/main/java/nl/andrewl/aos2registryapi/ServerRegistry.java @@ -73,7 +73,6 @@ public class ServerRegistry { @Scheduled(fixedRate = 1, timeUnit = TimeUnit.MINUTES, initialDelay = 1) public void purgeOldServers() { - log.info("Purging old servers."); Queue removalQueue = new LinkedList<>(); final Instant cutoff = Instant.now().minus(SERVER_TIMEOUT); for (var entry : servers.entrySet()) { diff --git a/server/pom.xml b/server/pom.xml index cd0cc6d..16de56c 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -33,6 +33,12 @@ jansi 2.4.0 + + + com.google.code.gson + gson + 2.9.1 + diff --git a/server/src/main/java/nl/andrewl/aos2_server/ClientCommunicationHandler.java b/server/src/main/java/nl/andrewl/aos2_server/ClientCommunicationHandler.java index 144d054..2b0554f 100644 --- a/server/src/main/java/nl/andrewl/aos2_server/ClientCommunicationHandler.java +++ b/server/src/main/java/nl/andrewl/aos2_server/ClientCommunicationHandler.java @@ -107,6 +107,11 @@ public class ClientCommunicationHandler { socket.close(); return; } + if (server.getPlayerManager().getPlayers().size() >= server.getConfig().maxPlayers) { + Net.write(new ConnectRejectMessage("Server is full."), out); + socket.close(); + return; + } // Try to set the TCP timeout back to 0 now that we've got the correct request. socket.setSoTimeout(0); diff --git a/server/src/main/java/nl/andrewl/aos2_server/RegistryUpdater.java b/server/src/main/java/nl/andrewl/aos2_server/RegistryUpdater.java new file mode 100644 index 0000000..6798561 --- /dev/null +++ b/server/src/main/java/nl/andrewl/aos2_server/RegistryUpdater.java @@ -0,0 +1,59 @@ +package nl.andrewl.aos2_server; + +import com.google.gson.Gson; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; + +/** + * Component that sends regular updates to any configured server registries. + */ +public class RegistryUpdater { + private final Server server; + private final HttpClient httpClient; + + public RegistryUpdater(Server server) { + this.server = server; + this.httpClient = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(3)) + .build(); + } + + public void sendUpdates() { + var cfg = server.getConfig(); + if ( + cfg.registries != null && + cfg.registries.length > 0 && + cfg.name != null && !cfg.name.isBlank() + ) { + Map data = new HashMap<>(); + data.put("port", cfg.port); + data.put("name", cfg.name); + data.put("description", cfg.description); + data.put("maxPlayers", cfg.maxPlayers); + data.put("currentPlayers", server.getPlayerManager().getPlayers().size()); + String json = new Gson().toJson(data); + for (String registryUrl : server.getConfig().registries) { + HttpRequest req = HttpRequest.newBuilder(URI.create(registryUrl + "/servers")) + .POST(HttpRequest.BodyPublishers.ofString(json)) + .header("Content-Type", "application/json") + .timeout(Duration.ofSeconds(3)) + .build(); + try { + var resp = httpClient.send(req, HttpResponse.BodyHandlers.ofString()); + if (resp.statusCode() != 200) { + System.err.println("Error response when sending registry update to " + registryUrl + ": " + resp.statusCode() + " " + resp.body()); + } + } catch (IOException | InterruptedException e) { + System.err.println("An error occurred while sending registry update to " + registryUrl + ": " + e.getMessage()); + } + } + } + } +} diff --git a/server/src/main/java/nl/andrewl/aos2_server/Server.java b/server/src/main/java/nl/andrewl/aos2_server/Server.java index 9743afb..c757690 100644 --- a/server/src/main/java/nl/andrewl/aos2_server/Server.java +++ b/server/src/main/java/nl/andrewl/aos2_server/Server.java @@ -24,7 +24,10 @@ import java.net.*; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import java.util.concurrent.Executors; import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; /** * The central server, which mainly contains all the different managers and @@ -83,11 +86,15 @@ public class Server implements Runnable { running = true; new Thread(new UdpReceiver(datagramSocket, this::handleUdpMessage)).start(); new Thread(worldUpdater).start(); + ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); + var registryUpdater = new RegistryUpdater(this); + executorService.scheduleAtFixedRate(registryUpdater::sendUpdates, 0, 90, TimeUnit.SECONDS); System.out.printf("Started AoS2 Server on TCP/UDP port %d; now accepting connections.%n", serverSocket.getLocalPort()); while (running) { acceptClientConnection(); } System.out.println("Shutting down the server."); + executorService.shutdown(); playerManager.deregisterAll(); worldUpdater.shutdown(); datagramSocket.close(); // Shuts down the UdpReceiver. diff --git a/server/src/main/java/nl/andrewl/aos2_server/config/ServerConfig.java b/server/src/main/java/nl/andrewl/aos2_server/config/ServerConfig.java index be30a50..26c2d7c 100644 --- a/server/src/main/java/nl/andrewl/aos2_server/config/ServerConfig.java +++ b/server/src/main/java/nl/andrewl/aos2_server/config/ServerConfig.java @@ -2,6 +2,11 @@ package nl.andrewl.aos2_server.config; public class ServerConfig { public int port = 25565; + public String name = "My Server"; + public String description = "My server"; + public String[] registries = new String[0]; + + public int maxPlayers = 32; public int connectionBacklog = 5; public float ticksPerSecond = 20.0f; public String world = "worlds.redfort"; diff --git a/server/src/main/resources/default-config.yaml b/server/src/main/resources/default-config.yaml index 4c6ed00..f76031d 100644 --- a/server/src/main/resources/default-config.yaml +++ b/server/src/main/resources/default-config.yaml @@ -1,5 +1,10 @@ # Ace of Shades 2 Server Configuration port: 25565 +name: My Server +description: This is my Ace of Shades server. +registries: + - https://reg.aos2.net +maxPlayers: 32 connectionBacklog: 5 ticksPerSecond: 20.0 world: worlds.redfort