diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 80abb05..3555574 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -39,7 +39,7 @@ jobs: run: mvn --batch-mode test -q # Re-checkout to reset the FS before deploying to Dokku - - name: Checkout + - name: Checkout - Reset FS uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/src/main/java/me/braydon/mc/common/MinecraftVersion.java b/src/main/java/me/braydon/mc/common/JavaMinecraftVersion.java similarity index 62% rename from src/main/java/me/braydon/mc/common/MinecraftVersion.java rename to src/main/java/me/braydon/mc/common/JavaMinecraftVersion.java index a49b152..a55d178 100644 --- a/src/main/java/me/braydon/mc/common/MinecraftVersion.java +++ b/src/main/java/me/braydon/mc/common/JavaMinecraftVersion.java @@ -26,17 +26,19 @@ package me.braydon.mc.common; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.ToString; -import lombok.extern.log4j.Log4j2; /** + * A list of versions for the + * Java edition of Minecraft. + * * @author Braydon * @see Protocol Version Numbers * @see Spigot NMS (1.16+) * @see Spigot NMS (1.10 - 1.15) * @see Spigot NMS (1.8 - 1.9) */ -@RequiredArgsConstructor @Getter @ToString @Log4j2(topic = "Minecraft Version") -public enum MinecraftVersion { +@RequiredArgsConstructor @Getter @ToString +public enum JavaMinecraftVersion { V1_20_3(765, "v1_20_R3"), // 1.20.3 & 1.20.4 V1_20_2(764, "v1_20_R2"), // 1.20.2 V1_20(763, "v1_20_R1"), // 1.20 & 1.20.1 @@ -91,19 +93,19 @@ public enum MinecraftVersion { UNKNOWN(-1, "Unknown"); // Game Updates - public static final MinecraftVersion TRAILS_AND_TALES = MinecraftVersion.V1_20; - public static final MinecraftVersion THE_WILD_UPDATE = MinecraftVersion.V1_19; - public static final MinecraftVersion CAVES_AND_CLIFFS_PT_2 = MinecraftVersion.V1_18; - public static final MinecraftVersion CAVES_AND_CLIFFS_PT_1 = MinecraftVersion.V1_17; - public static final MinecraftVersion NETHER_UPDATE = MinecraftVersion.V1_16; - public static final MinecraftVersion BUZZY_BEES = MinecraftVersion.V1_15; - public static final MinecraftVersion VILLAGE_AND_PILLAGE = MinecraftVersion.V1_14; - public static final MinecraftVersion UPDATE_AQUATIC = MinecraftVersion.V1_13; - public static final MinecraftVersion WORLD_OF_COLOR_UPDATE = MinecraftVersion.V1_12; - public static final MinecraftVersion EXPLORATION_UPDATE = MinecraftVersion.V1_11; - public static final MinecraftVersion FROSTBURN_UPDATE = MinecraftVersion.V1_10; - public static final MinecraftVersion THE_COMBAT_UPDATE = MinecraftVersion.V1_9; - public static final MinecraftVersion BOUNTIFUL_UPDATE = MinecraftVersion.V1_8; + public static final JavaMinecraftVersion TRAILS_AND_TALES = JavaMinecraftVersion.V1_20; + public static final JavaMinecraftVersion THE_WILD_UPDATE = JavaMinecraftVersion.V1_19; + public static final JavaMinecraftVersion CAVES_AND_CLIFFS_PT_2 = JavaMinecraftVersion.V1_18; + public static final JavaMinecraftVersion CAVES_AND_CLIFFS_PT_1 = JavaMinecraftVersion.V1_17; + public static final JavaMinecraftVersion NETHER_UPDATE = JavaMinecraftVersion.V1_16; + public static final JavaMinecraftVersion BUZZY_BEES = JavaMinecraftVersion.V1_15; + public static final JavaMinecraftVersion VILLAGE_AND_PILLAGE = JavaMinecraftVersion.V1_14; + public static final JavaMinecraftVersion UPDATE_AQUATIC = JavaMinecraftVersion.V1_13; + public static final JavaMinecraftVersion WORLD_OF_COLOR_UPDATE = JavaMinecraftVersion.V1_12; + public static final JavaMinecraftVersion EXPLORATION_UPDATE = JavaMinecraftVersion.V1_11; + public static final JavaMinecraftVersion FROSTBURN_UPDATE = JavaMinecraftVersion.V1_10; + public static final JavaMinecraftVersion THE_COMBAT_UPDATE = JavaMinecraftVersion.V1_9; + public static final JavaMinecraftVersion BOUNTIFUL_UPDATE = JavaMinecraftVersion.V1_8; /** * The protocol number of this version. @@ -140,67 +142,14 @@ public enum MinecraftVersion { return this.name; } - /** - * Is this version legacy? - * - * @return whether this version is legacy - */ - public boolean isLegacy() { - return this.isBelow(MinecraftVersion.V1_16); - } - - /** - * Check if this version is - * above the one given. - * - * @param other the other version - * @return true if above, otherwise false - */ - public boolean isAbove(MinecraftVersion other) { - return this.protocol > other.getProtocol(); - } - - /** - * Check if this version is - * or above the one given. - * - * @param other the other version - * @return true if is or above, otherwise false - */ - public boolean isOrAbove(MinecraftVersion other) { - return this.protocol >= other.getProtocol(); - } - - /** - * Check if this version is - * below the one given. - * - * @param other the other version - * @return true if below, otherwise false - */ - public boolean isBelow(MinecraftVersion other) { - return this.protocol < other.getProtocol(); - } - - /** - * Check if this version is - * or below the one given. - * - * @param other the other version - * @return true if is or below, otherwise false - */ - public boolean isOrBelow(MinecraftVersion other) { - return this.protocol <= other.getProtocol(); - } - /** * Get the version from the given protocol. * * @param protocol the protocol to get the version for * @return the version, null if none */ - public static MinecraftVersion byProtocol(int protocol) { - for (MinecraftVersion version : values()) { + public static JavaMinecraftVersion byProtocol(int protocol) { + for (JavaMinecraftVersion version : values()) { if (version.getProtocol() == protocol) { return version; } diff --git a/src/main/java/me/braydon/mc/controller/ServerController.java b/src/main/java/me/braydon/mc/controller/ServerController.java index eb55fd9..691a97b 100644 --- a/src/main/java/me/braydon/mc/controller/ServerController.java +++ b/src/main/java/me/braydon/mc/controller/ServerController.java @@ -63,16 +63,17 @@ public final class ServerController { * * @param platform the platform of the server * @param hostname the hostname of the server + * @param port the port of the server, null for default * @return the server - * @throws BadRequestException if the hostname or platform is invalid + * @throws BadRequestException if the hostname or platform is invalid * @throws ResourceNotFoundException if the server isn't found */ @GetMapping("/{platform}/{hostname}") @ResponseBody - public ResponseEntity getServer(@PathVariable @NonNull String platform, @PathVariable @NonNull String hostname) - throws BadRequestException, ResourceNotFoundException - { - return ResponseEntity.ofNullable(mojangService.getMinecraftServer(platform, hostname)); + public ResponseEntity getServer(@PathVariable @NonNull String platform, @PathVariable @NonNull String hostname, + @RequestParam(required = false) String port + ) throws BadRequestException, ResourceNotFoundException { + return ResponseEntity.ofNullable(mojangService.getMinecraftServer(platform, hostname, port)); } /** @@ -95,14 +96,15 @@ public final class ServerController { * server by its platform and hostname. * * @param hostname the hostname of the server + * @param port the port of the server, null for default * @return the server icon */ @GetMapping(value = "/icon/{hostname}", produces = MediaType.IMAGE_PNG_VALUE) @ResponseBody - public ResponseEntity getServerFavicon(@PathVariable @NonNull String hostname) { + public ResponseEntity getServerFavicon(@PathVariable @NonNull String hostname, @RequestParam(required = false) String port) { return ResponseEntity.ok() .contentType(MediaType.IMAGE_PNG) .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=%s.png".formatted(hostname)) - .body(mojangService.getServerFavicon(hostname)); + .body(mojangService.getServerFavicon(hostname, port)); } } \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/model/server/JavaMinecraftServer.java b/src/main/java/me/braydon/mc/model/server/JavaMinecraftServer.java index 7a02e4c..2050493 100644 --- a/src/main/java/me/braydon/mc/model/server/JavaMinecraftServer.java +++ b/src/main/java/me/braydon/mc/model/server/JavaMinecraftServer.java @@ -26,7 +26,7 @@ package me.braydon.mc.model.server; import com.google.gson.annotations.SerializedName; import lombok.*; import me.braydon.mc.RESTfulMC; -import me.braydon.mc.common.MinecraftVersion; +import me.braydon.mc.common.JavaMinecraftVersion; import me.braydon.mc.config.AppConfig; import me.braydon.mc.model.MinecraftServer; import me.braydon.mc.model.token.JavaServerStatusToken; @@ -152,7 +152,7 @@ public final class JavaMinecraftServer extends MinecraftServer { platform = split[0]; } } - MinecraftVersion minecraftVersion = MinecraftVersion.byProtocol(protocol); + JavaMinecraftVersion minecraftVersion = JavaMinecraftVersion.byProtocol(protocol); return new Version(name, platform, protocol, minecraftVersion == null ? null : minecraftVersion.getName()); } } diff --git a/src/main/java/me/braydon/mc/service/MojangService.java b/src/main/java/me/braydon/mc/service/MojangService.java index 08c8739..0626f38 100644 --- a/src/main/java/me/braydon/mc/service/MojangService.java +++ b/src/main/java/me/braydon/mc/service/MojangService.java @@ -271,13 +271,14 @@ public final class MojangService { *

* * @param hostname the hostname of the server + * @param port the port of the server, null for default * @return the server favicon * @see #DEFAULT_SERVER_ICON for the default server icon */ - public byte[] getServerFavicon(@NonNull String hostname) { + public byte[] getServerFavicon(@NonNull String hostname, String port) { String icon = null; // The server base64 icon try { - JavaMinecraftServer.Favicon favicon = ((JavaMinecraftServer) getMinecraftServer(MinecraftServer.Platform.JAVA.name(), hostname).getValue()).getFavicon(); + JavaMinecraftServer.Favicon favicon = ((JavaMinecraftServer) getMinecraftServer(MinecraftServer.Platform.JAVA.name(), hostname, port).getValue()).getFavicon(); if (favicon != null) { // Use the server's favicon icon = favicon.getBase64(); icon = icon.substring(icon.indexOf(",") + 1); // Remove the data type from the server icon @@ -344,35 +345,45 @@ public final class MojangService { * * @param platformName the name of the platform * @param hostname the hostname of the server + * @param portString the port of the server, null for default * @return the resolved Minecraft server - * @throws BadRequestException if the hostname or platform is invalid - * @throws ResourceNotFoundException if the server isn't found + * @throws BadRequestException if the hostname or platform is invalid + * @throws ResourceNotFoundException if the server isn't found */ @NonNull - public CachedMinecraftServer getMinecraftServer(@NonNull String platformName, @NonNull String hostname) + public CachedMinecraftServer getMinecraftServer(@NonNull String platformName, @NonNull String hostname, String portString) throws BadRequestException, ResourceNotFoundException { MinecraftServer.Platform platform = EnumUtils.getEnumConstant(MinecraftServer.Platform.class, platformName.toUpperCase()); if (platform == null) { // Invalid platform throw new BadRequestException("Invalid platform: %s".formatted(platformName)); } String lookupHostname = hostname; // The hostname used to lookup the server + String lookupPort = portString; // The port used to lookup the server + + int port = platform.getDefaultPort(); // Port to ping + if (portString != null) { + try { // Try and parse the port + port = Integer.parseInt(portString); + } catch (NumberFormatException ex) { // Invalid port + throw new BadRequestException("Invalid port defined"); + } + } // Check the cache for the server - Optional cached = minecraftServerCache.findById(platform.name() + "-" + hostname); + Optional cached = minecraftServerCache.findById(platform.name() + "-" + hostname + "-" + port); if (cached.isPresent()) { // Respond with the cache if present log.info("Found server in cache: {}", hostname); return cached.get(); } - InetSocketAddress address = platform == MinecraftServer.Platform.JAVA ? DNSUtils.resolveSRV(hostname) : null; // Resolve the SRV record - int port = platform.getDefaultPort(); // Port to ping if (address != null) { // SRV was resolved, use the hostname and port hostname = address.getHostName(); port = address.getPort(); } + // Build our server model, cache it, and then return it CachedMinecraftServer minecraftServer = new CachedMinecraftServer( - platform.name() + "-" + lookupHostname, + platform.name() + "-" + lookupHostname + "-" + (lookupPort == null ? port : lookupPort), platform.getPinger().ping(hostname, port), System.currentTimeMillis() );