diff --git a/src/main/java/me/braydon/mc/RESTfulMC.java b/src/main/java/me/braydon/mc/RESTfulMC.java deleted file mode 100644 index 26e1dd3..0000000 --- a/src/main/java/me/braydon/mc/RESTfulMC.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import io.swagger.v3.oas.annotations.OpenAPIDefinition; -import io.swagger.v3.oas.annotations.info.Contact; -import io.swagger.v3.oas.annotations.info.Info; -import io.swagger.v3.oas.annotations.info.License; -import lombok.NonNull; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; - -import java.io.File; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; -import java.util.Objects; - -/** - * @author Braydon - */ -@SpringBootApplication(exclude = { JacksonAutoConfiguration.class }) -@Slf4j(topic = "RESTfulMC") -@OpenAPIDefinition(info = @Info( - title = "RESTfulMC", - description = "A simple, yet useful RESTful API for Minecraft utilizing Springboot.", - version = "1.0.0", - contact = @Contact(name = "Braydon (Rainnny)", url = "https://rainnny.club", email = "braydonrainnny@gmail.com"), - license = @License(name = "MIT License", url = "https://opensource.org/license/MIT") -)) -public class RESTfulMC { - public static final Gson GSON = new GsonBuilder() - .setDateFormat("MM-dd-yyyy HH:mm:ss") - .create(); - - @SneakyThrows - public static void main(@NonNull String[] args) { - // Handle loading of our configuration file - File config = new File("application.yml"); - if (!config.exists()) { // Saving the default config if it doesn't exist locally - Files.copy(Objects.requireNonNull(RESTfulMC.class.getResourceAsStream("/application.yml")), config.toPath(), StandardCopyOption.REPLACE_EXISTING); - log.info("Saved the default configuration to '{}', please re-launch the application", // Log the default config being saved - config.getAbsolutePath() - ); - return; - } - log.info("Found configuration at '{}'", config.getAbsolutePath()); // Log the found config - - // Start the app - SpringApplication.run(RESTfulMC.class, args); - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/ColorUtils.java b/src/main/java/me/braydon/mc/common/ColorUtils.java deleted file mode 100644 index 2979914..0000000 --- a/src/main/java/me/braydon/mc/common/ColorUtils.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.common; - -import lombok.NonNull; -import lombok.experimental.UtilityClass; - -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Pattern; - -/** - * @author Braydon - */ -@UtilityClass -public final class ColorUtils { - private static final Pattern STRIP_COLOR_PATTERN = Pattern.compile("(?i)§[0-9A-FK-OR]"); - private static final Map COLOR_MAP = new HashMap<>(); - static { - // Map each color to its corresponding hex code - COLOR_MAP.put('0', "#000000"); // Black - COLOR_MAP.put('1', "#0000AA"); // Dark Blue - COLOR_MAP.put('2', "#00AA00"); // Dark Green - COLOR_MAP.put('3', "#00AAAA"); // Dark Aqua - COLOR_MAP.put('4', "#AA0000"); // Dark Red - COLOR_MAP.put('5', "#AA00AA"); // Dark Purple - COLOR_MAP.put('6', "#FFAA00"); // Gold - COLOR_MAP.put('7', "#AAAAAA"); // Gray - COLOR_MAP.put('8', "#555555"); // Dark Gray - COLOR_MAP.put('9', "#5555FF"); // Blue - COLOR_MAP.put('a', "#55FF55"); // Green - COLOR_MAP.put('b', "#55FFFF"); // Aqua - COLOR_MAP.put('c', "#FF5555"); // Red - COLOR_MAP.put('d', "#FF55FF"); // Light Purple - COLOR_MAP.put('e', "#FFFF55"); // Yellow - COLOR_MAP.put('f', "#FFFFFF"); // White - } - - /** - * Strip the color codes - * from the given input. - * - * @param input the input to strip - * @return the stripped input - */ - @NonNull - public static String stripColor(@NonNull String input) { - return STRIP_COLOR_PATTERN.matcher(input).replaceAll(""); - } - - /** - * Convert the given input into HTML format. - *

- * This will replace each color code with - * a span tag with the respective color in - * hex format. - *

- * - * @param input the input to convert - * @return the converted input - */ - @NonNull - public static String toHTML(@NonNull String input) { - StringBuilder builder = new StringBuilder(); - boolean nextIsColor = false; // Is the next char a color code? - - for (char character : input.toCharArray()) { - // Found color symbol, next color is the color - if (character == '§') { - nextIsColor = true; - continue; - } - if (nextIsColor) { // Map the current color to its hex code - String color = COLOR_MAP.getOrDefault(Character.toLowerCase(character), ""); - builder.append(""); - nextIsColor = false; - continue; - } - builder.append(character); // Append the char... - } - return builder.toString(); - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/DNSUtils.java b/src/main/java/me/braydon/mc/common/DNSUtils.java deleted file mode 100644 index ae23a72..0000000 --- a/src/main/java/me/braydon/mc/common/DNSUtils.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.common; - -import lombok.NonNull; -import lombok.SneakyThrows; -import lombok.experimental.UtilityClass; -import org.xbill.DNS.Record; -import org.xbill.DNS.*; - -import java.net.InetAddress; -import java.net.InetSocketAddress; - -/** - * @author Braydon - */ -@UtilityClass -public final class DNSUtils { - private static final String SRV_QUERY_PREFIX = "_minecraft._tcp.%s"; - - /** - * Resolve the hostname to an {@link InetSocketAddress}. - * - * @param hostname the hostname to resolve - * @return the resolved {@link InetSocketAddress} - */ - @SneakyThrows - public static InetSocketAddress resolveSRV(@NonNull String hostname) { - Record[] records = new Lookup(SRV_QUERY_PREFIX.formatted(hostname), Type.SRV).run(); // Resolve SRV records - if (records == null) { // No records exist - return null; - } - String host = null; - int port = -1; - for (Record record : records) { - SRVRecord srv = (SRVRecord) record; - host = srv.getTarget().toString().replaceFirst("\\.$", ""); - port = srv.getPort(); - } - return host == null ? null : new InetSocketAddress(host, port); - } - - @SneakyThrows - public static InetAddress resolveA(@NonNull String hostname) { - Record[] records = new Lookup(hostname, Type.A).run(); // Resolve A records - if (records == null) { // No records exist - return null; - } - InetAddress address = null; - for (Record record : records) { - address = ((ARecord) record).getAddress(); - } - return address; - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/EnumUtils.java b/src/main/java/me/braydon/mc/common/EnumUtils.java deleted file mode 100644 index cd16f96..0000000 --- a/src/main/java/me/braydon/mc/common/EnumUtils.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.common; - -import lombok.NonNull; -import lombok.experimental.UtilityClass; - -/** - * @author Braydon - */ -@UtilityClass -public final class EnumUtils { - /** - * Get the enum constant of the specified enum type with the specified name. - * - * @param enumType the enum type - * @param name the name of the constant to return - * @param the type of the enum - * @return the enum constant of the specified enum type with the specified name - */ - public > T getEnumConstant(@NonNull Class enumType, @NonNull String name) { - try { - return Enum.valueOf(enumType, name); - } catch (IllegalArgumentException ex) { - return null; - } - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/ExpiringSet.java b/src/main/java/me/braydon/mc/common/ExpiringSet.java deleted file mode 100644 index 80cbd97..0000000 --- a/src/main/java/me/braydon/mc/common/ExpiringSet.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.common; - -import lombok.NonNull; -import net.jodah.expiringmap.ExpirationPolicy; -import net.jodah.expiringmap.ExpiringMap; - -import javax.annotation.concurrent.ThreadSafe; -import java.util.Iterator; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; - -/** - * A simple set that expires elements after a certain - * amount of time, utilizing the {@link ExpiringMap} library. - * - * @param The type of element to store within this set - * @author Braydon - */ -@ThreadSafe -public final class ExpiringSet implements Iterable { - /** - * The internal cache for this set. - */ - @NonNull private final ExpiringMap cache; - - /** - * The lifetime (in millis) of the elements in this set. - */ - private final long lifetime; - - public ExpiringSet(@NonNull ExpirationPolicy expirationPolicy, long duration, @NonNull TimeUnit timeUnit) { - this(expirationPolicy, duration, timeUnit, ignored -> {}); - } - - public ExpiringSet(@NonNull ExpirationPolicy expirationPolicy, long duration, @NonNull TimeUnit timeUnit, @NonNull Consumer onExpire) { - //noinspection unchecked - this.cache = ExpiringMap.builder() - .expirationPolicy(expirationPolicy) - .expiration(duration, timeUnit) - .expirationListener((key, ignored) -> onExpire.accept((T) key)) - .build(); - this.lifetime = timeUnit.toMillis(duration); // Get the lifetime in millis - } - - /** - * Add an element to this set. - * - * @param element the element - * @return whether the element was added - */ - public boolean add(@NonNull T element) { - boolean contains = contains(element); // Does this set already contain the element? - this.cache.put(element, System.currentTimeMillis() + this.lifetime); - return !contains; - } - - /** - * Get the entry time of an element in this set. - * - * @param element the element - * @return the entry time, -1 if not contained - */ - public long getEntryTime(@NonNull T element) { - return contains(element) ? this.cache.get(element) - this.lifetime : -1L; - } - - /** - * Check if an element is - * contained within this set. - * - * @param element the element - * @return whether the element is contained - */ - public boolean contains(@NonNull T element) { - Long timeout = this.cache.get(element); // Get the timeout for the element - return timeout != null && (timeout > System.currentTimeMillis()); - } - - /** - * Check if this set is empty. - * - * @return whether this set is empty - */ - public boolean isEmpty() { - return this.cache.isEmpty(); - } - - /** - * Get the size of this set. - * - * @return the size - */ - public int size() { - return this.cache.size(); - } - - /** - * Remove an element from this set. - * - * @param element the element - * @return whether the element was removed - */ - public boolean remove(@NonNull T element) { - return this.cache.remove(element) != null; - } - - /** - * Clear this set. - */ - public void clear() { - this.cache.clear(); - } - - /** - * Get the elements in this set. - * - * @return the elements - */ - @NonNull - public Set getElements() { - return this.cache.keySet(); - } - - /** - * Returns an iterator over elements of type {@code T}. - * - * @return an Iterator. - */ - @Override @NonNull - public Iterator iterator() { - return this.cache.keySet().iterator(); - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/IPUtils.java b/src/main/java/me/braydon/mc/common/IPUtils.java deleted file mode 100644 index ba15853..0000000 --- a/src/main/java/me/braydon/mc/common/IPUtils.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.common; - -import jakarta.servlet.http.HttpServletRequest; -import lombok.NonNull; -import lombok.experimental.UtilityClass; - -/** - * @author Braydon - */ -@UtilityClass -public final class IPUtils { - private static final String[] IP_HEADERS = new String[] { - "CF-Connecting-IP", - "X-Forwarded-For" - }; - - /** - * Get the real IP from the given request. - * - * @param request the request - * @return the real IP - */ - @NonNull - public static String getRealIp(@NonNull HttpServletRequest request) { - String ip = request.getRemoteAddr(); - for (String headerName : IP_HEADERS) { - String header = request.getHeader(headerName); - if (header == null) { - continue; - } - if (!header.contains(",")) { // Handle single IP - ip = header; - break; - } - // Handle multiple IPs - String[] ips = header.split(","); - for (String ipHeader : ips) { - ip = ipHeader; - break; - } - } - return ip; - } -} diff --git a/src/main/java/me/braydon/mc/common/ImageUtils.java b/src/main/java/me/braydon/mc/common/ImageUtils.java deleted file mode 100644 index 5d98dc7..0000000 --- a/src/main/java/me/braydon/mc/common/ImageUtils.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.common; - -import lombok.NonNull; -import lombok.SneakyThrows; -import lombok.experimental.UtilityClass; -import me.braydon.mc.model.Skin; - -import javax.imageio.ImageIO; -import java.awt.geom.AffineTransform; -import java.awt.image.AffineTransformOp; -import java.awt.image.BufferedImage; -import java.io.ByteArrayOutputStream; -import java.net.URL; - -/** - * @author Braydon - */ -@UtilityClass -public final class ImageUtils { - public static final int SKIN_TEXTURE_SIZE = 64; // The skin of a skin texture - - /** - * Get the texture of a part of a skin. - * - * @param skin the skin to get the part texture from - * @param part the part of the skin to get - * @param size the size to scale the texture to - * @return the texture of the skin part - */ - @SneakyThrows - public static byte[] getSkinPart(@NonNull Skin skin, @NonNull Skin.Part part, int size) { - return getSkinPartTexture(skin, part.getX(), part.getY(), part.getWidth(), part.getHeight(), size); - } - - /** - * Get the texture of a specific part of a skin. - * - * @param skin the skin to get the part from - * @param x the x position of the part - * @param y the y position of the part - * @param width the width of the part - * @param height the height of the part - * @param size the size to scale the part to - * @return the texture of the skin part - */ - @SneakyThrows - public static byte[] getSkinPartTexture(@NonNull Skin skin, int x, int y, int width, int height, int size) { - BufferedImage skinImage = ImageIO.read(new URL(skin.getUrl())); // The skin texture - - // Create a new BufferedImage for the part of the skin texture - BufferedImage headTexture = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); - - // Crop just the part we want based on our x, y, width, and height - headTexture.getGraphics().drawImage(skinImage, 0, 0, width, height, x, y, x + width, y + height, null); - - // Scale the skin part texture - double scale = (double) size / width; - AffineTransform transform = AffineTransform.getScaleInstance(scale, scale); - headTexture = new AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR).filter(headTexture, null); - - // Convert BufferedImage to byte array - try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { - ImageIO.write(headTexture, "png", outputStream); - outputStream.flush(); - return outputStream.toByteArray(); - } - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/JavaMinecraftVersion.java b/src/main/java/me/braydon/mc/common/JavaMinecraftVersion.java deleted file mode 100644 index a55d178..0000000 --- a/src/main/java/me/braydon/mc/common/JavaMinecraftVersion.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.common; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.ToString; - -/** - * 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 -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 - - V1_19_4(762, "v1_19_R3"), // 1.19.4 - V1_19_3(761, "v1_19_R2"), // 1.19.3 - V1_19_1(760, "v1_19_R1"), // 1.19.1 & 1.19.2 - V1_19(759, "v1_19_R1"), // 1.19 - - V1_18_2(758, "v1_18_R2"), // 1.18.2 - V1_18(757, "v1_18_R1"), // 1.18 & 1.18.1 - - V1_17_1(756, "v1_17_R1"), // 1.17.1 - V1_17(755, "v1_17_R1"), // 1.17 - - V1_16_4(754, "v1_16_R3"), // 1.16.4 & 1.16.5 - V1_16_3(753, "v1_16_R2"), // 1.16.3 - V1_16_2(751, "v1_16_R2"), // 1.16.2 - V1_16_1(736, "v1_16_R1"), // 1.16.1 - V1_16(735, "v1_16_R1"), // 1.16 - - V1_15_2(578, "v1_15_R1"), // 1.15.2 - V1_15_1(575, "v1_15_R1"), // 1.15.1 - V1_15(573, "v1_15_R1"), // 1.15 - - V1_14_4(498, "v1_14_R1"), // 1.14.4 - V1_14_3(490, "v1_14_R1"), // 1.14.3 - V1_14_2(485, "v1_14_R1"), // 1.14.2 - V1_14_1(480, "v1_14_R1"), // 1.14.1 - V1_14(477, "v1_14_R1"), // 1.14 - - V1_13_2(404, "v1_13_R2"), // 1.13.2 - V1_13_1(401, "v1_13_R2"), // 1.13.1 - V1_13(393, "v1_13_R1"), // 1.13 - - V1_12_2(340, "v1_12_R1"), // 1.12.2 - V1_12_1(338, "v1_12_R1"), // 1.12.1 - V1_12(335, "v1_12_R1"), // 1.12 - - V1_11_1(316, "v1_11_R1"), // 1.11.1 & 1.11.2 - V1_11(315, "v1_11_R1"), // 1.11 - - V1_10(210, "v1_10_R1"), // 1.10.x - - V1_9_3(110, "v1_9_R2"), // 1.9.3 & 1.9.4 - V1_9_2(109, "v1_9_R1"), // 1.9.2 - V1_9_1(108, "v1_9_R1"), // 1.9.1 - V1_9(107, "v1_9_R1"), // 1.9 - - V1_8(47, "v1_8_R3"), // 1.8.x - - UNKNOWN(-1, "Unknown"); - - // Game Updates - 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. - */ - private final int protocol; - - /** - * The server version for this version. - */ - private final String nmsVersion; - - /** - * The cached name of this version. - */ - private String name; - - /** - * Get the name of this protocol version. - * - * @return the name - */ - public String getName() { - // We have a name - if (this.name != null) { - return this.name; - } - // Use the server version as the name if unknown - if (this == UNKNOWN) { - this.name = this.getNmsVersion(); - } else { // Parse the name - this.name = name().substring(1); - this.name = this.name.replace("_", "."); - } - return this.name; - } - - /** - * Get the version from the given protocol. - * - * @param protocol the protocol to get the version for - * @return the version, null if none - */ - public static JavaMinecraftVersion byProtocol(int protocol) { - for (JavaMinecraftVersion version : values()) { - if (version.getProtocol() == protocol) { - return version; - } - } - return null; - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/MiscUtils.java b/src/main/java/me/braydon/mc/common/MiscUtils.java deleted file mode 100644 index c6553ef..0000000 --- a/src/main/java/me/braydon/mc/common/MiscUtils.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.common; - -import lombok.NonNull; -import lombok.experimental.UtilityClass; - -import java.util.Arrays; -import java.util.List; -import java.util.regex.Pattern; - -/** - * @author Braydon - */ -@UtilityClass -public final class MiscUtils { - private static final Pattern USERNAME_REGEX = Pattern.compile("^[a-zA-Z0-9_]{2,16}$"); - private static final List WHITELISTED_NAMES = Arrays.asList("8", "g"); - - /** - * Check if the given username is a valid. - * - * @param username the username to check - * @return whether the username is valid - */ - public static boolean isUsernameValid(@NonNull String username) { - if (WHITELISTED_NAMES.contains(username.toLowerCase())) { // Name is whitelisted - return true; - } - return USERNAME_REGEX.matcher(username).matches(); - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/Tuple.java b/src/main/java/me/braydon/mc/common/Tuple.java deleted file mode 100644 index 742c10e..0000000 --- a/src/main/java/me/braydon/mc/common/Tuple.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.common; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -/** - * A simple tuple utility. - * - * @author Braydon - */ -@NoArgsConstructor @AllArgsConstructor @Setter @Getter -public class Tuple { - /** - * The left value. - */ - private L left; - - /** - * The right value. - */ - private R right; -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/UUIDUtils.java b/src/main/java/me/braydon/mc/common/UUIDUtils.java deleted file mode 100644 index 5a8ee95..0000000 --- a/src/main/java/me/braydon/mc/common/UUIDUtils.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.common; - -import lombok.NonNull; -import lombok.experimental.UtilityClass; - -import java.util.UUID; - -/** - * @author Braydon - */ -@UtilityClass -public final class UUIDUtils { - /** - * Add dashes to an untrimmed uuid. - * - * @param trimmed the untrimmed uuid - * @return the uuid with dashes - */ - @NonNull - public static UUID addDashes(@NonNull String trimmed) { - StringBuilder builder = new StringBuilder(trimmed); - for (int i = 0, pos = 20; i < 4; i++, pos -= 4) { - builder.insert(pos, "-"); - } - return UUID.fromString(builder.toString()); - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/packet/MinecraftBedrockPacket.java b/src/main/java/me/braydon/mc/common/packet/MinecraftBedrockPacket.java deleted file mode 100644 index 23dbe8f..0000000 --- a/src/main/java/me/braydon/mc/common/packet/MinecraftBedrockPacket.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.common.packet; - -import lombok.NonNull; - -import java.io.IOException; -import java.net.DatagramSocket; - -/** - * Represents a packet in the - * Minecraft Bedrock protocol. - * - * @author Braydon - * @see Protocol Docs - */ -public interface MinecraftBedrockPacket { - /** - * Process this packet. - * - * @param socket the socket to process the packet for - * @throws IOException if an I/O error occurs - */ - void process(@NonNull DatagramSocket socket) throws IOException; -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/packet/MinecraftJavaPacket.java b/src/main/java/me/braydon/mc/common/packet/MinecraftJavaPacket.java deleted file mode 100644 index 97f4468..0000000 --- a/src/main/java/me/braydon/mc/common/packet/MinecraftJavaPacket.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.common.packet; - -import lombok.NonNull; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -/** - * Represents a packet in the - * Minecraft Java protocol. - * - * @author Braydon - * @see Protocol Docs - */ -public abstract class MinecraftJavaPacket { - /** - * Process this packet. - * - * @param inputStream the input stream to read from - * @param outputStream the output stream to write to - * @throws IOException if an I/O error occurs - */ - public abstract void process(@NonNull DataInputStream inputStream, @NonNull DataOutputStream outputStream) throws IOException; - - /** - * Write a variable integer to the output stream. - * - * @param outputStream the output stream to write to - * @param paramInt the integer to write - * @throws IOException if an I/O error occurs - */ - protected final void writeVarInt(DataOutputStream outputStream, int paramInt) throws IOException { - while (true) { - if ((paramInt & 0xFFFFFF80) == 0) { - outputStream.writeByte(paramInt); - return; - } - outputStream.writeByte(paramInt & 0x7F | 0x80); - paramInt >>>= 7; - } - } - - /** - * Read a variable integer from the input stream. - * - * @param inputStream the input stream to read from - * @return the integer that was read - * @throws IOException if an I/O error occurs - */ - protected final int readVarInt(@NonNull DataInputStream inputStream) throws IOException { - int i = 0; - int j = 0; - while (true) { - int k = inputStream.readByte(); - i |= (k & 0x7F) << j++ * 7; - if (j > 5) { - throw new RuntimeException("VarInt too big"); - } - if ((k & 0x80) != 128) { - break; - } - } - return i; - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/packet/impl/bedrock/BedrockPacketUnconnectedPing.java b/src/main/java/me/braydon/mc/common/packet/impl/bedrock/BedrockPacketUnconnectedPing.java deleted file mode 100644 index d0d56e0..0000000 --- a/src/main/java/me/braydon/mc/common/packet/impl/bedrock/BedrockPacketUnconnectedPing.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.common.packet.impl.bedrock; - -import lombok.NonNull; -import me.braydon.mc.common.packet.MinecraftBedrockPacket; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * This packet is sent by the client to the server to - * request a pong response from the server. The server - * will respond with a string containing the server's status. - * - * @author Braydon - * @see Protocol Docs - */ -public final class BedrockPacketUnconnectedPing implements MinecraftBedrockPacket { - private static final byte ID = 0x01; // The ID of the packet - private static final byte[] MAGIC = { 0, -1, -1, 0, -2, -2, -2, -2, -3, -3, -3, -3, 18, 52, 86, 120 }; - - /** - * Process this packet. - * - * @param socket the socket to process the packet for - * @throws IOException if an I/O error occurs - */ - @Override - public void process(@NonNull DatagramSocket socket) throws IOException { - // Construct the packet buffer - ByteBuffer buffer = ByteBuffer.allocate(33).order(ByteOrder.LITTLE_ENDIAN);; - buffer.put(ID); // Packet ID - buffer.putLong(System.currentTimeMillis()); // Timestamp - buffer.put(MAGIC); // Magic - buffer.putLong(0L); // Client GUID - - // Send the packet - socket.send(new DatagramPacket(buffer.array(), 0, buffer.limit())); - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/packet/impl/bedrock/BedrockPacketUnconnectedPong.java b/src/main/java/me/braydon/mc/common/packet/impl/bedrock/BedrockPacketUnconnectedPong.java deleted file mode 100644 index a36ca79..0000000 --- a/src/main/java/me/braydon/mc/common/packet/impl/bedrock/BedrockPacketUnconnectedPong.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.common.packet.impl.bedrock; - -import lombok.Getter; -import lombok.NonNull; -import me.braydon.mc.common.packet.MinecraftBedrockPacket; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.charset.StandardCharsets; - -/** - * This packet is sent by the server to the client in - * response to the {@link BedrockPacketUnconnectedPing}. - * - * @author Braydon - * @see Protocol Docs - */ -@Getter -public final class BedrockPacketUnconnectedPong implements MinecraftBedrockPacket { - private static final byte ID = 0x1C; // The ID of the packet - - /** - * The response from the server, null if none. - */ - private String response; - - /** - * Process this packet. - * - * @param socket the socket to process the packet for - * @throws IOException if an I/O error occurs - */ - @Override - public void process(@NonNull DatagramSocket socket) throws IOException { - // Handle receiving of the packet - byte[] receiveData = new byte[2048]; - DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); - socket.receive(receivePacket); - - // Construct a buffer from the received packet - ByteBuffer buffer = ByteBuffer.wrap(receivePacket.getData()).order(ByteOrder.LITTLE_ENDIAN); - byte id = buffer.get(); // The received packet id - if (id == ID) { - response = new String(buffer.array(), StandardCharsets.UTF_8).substring(34).trim(); - } - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/packet/impl/java/JavaPacketHandshakingInSetProtocol.java b/src/main/java/me/braydon/mc/common/packet/impl/java/JavaPacketHandshakingInSetProtocol.java deleted file mode 100644 index 945d460..0000000 --- a/src/main/java/me/braydon/mc/common/packet/impl/java/JavaPacketHandshakingInSetProtocol.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.common.packet.impl.java; - -import lombok.AllArgsConstructor; -import lombok.NonNull; -import lombok.ToString; -import me.braydon.mc.common.packet.MinecraftJavaPacket; - -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -/** - * This packet is sent by the client to the server to set - * the hostname, port, and protocol version of the client. - * - * @author Braydon - * @see Protocol Docs - */ -@AllArgsConstructor @ToString -public final class JavaPacketHandshakingInSetProtocol extends MinecraftJavaPacket { - private static final byte ID = 0x00; // The ID of the packet - private static final int STATUS_HANDSHAKE = 1; // The status handshake ID - - /** - * The hostname of the server. - */ - @NonNull private final String hostname; - - /** - * The port of the server. - */ - private final int port; - - /** - * The protocol version of the server. - */ - private final int protocolVersion; - - /** - * Process this packet. - * - * @param inputStream the input stream to read from - * @param outputStream the output stream to write to - * @throws IOException if an I/O error occurs - */ - @Override - public void process(@NonNull DataInputStream inputStream, @NonNull DataOutputStream outputStream) throws IOException { - try (ByteArrayOutputStream handshakeBytes = new ByteArrayOutputStream(); - DataOutputStream handshake = new DataOutputStream(handshakeBytes) - ) { - handshake.writeByte(ID); // Write the ID of the packet - writeVarInt(handshake, protocolVersion); // Write the protocol version - writeVarInt(handshake, hostname.length()); // Write the length of the hostname - handshake.writeBytes(hostname); // Write the hostname - handshake.writeShort(port); // Write the port - writeVarInt(handshake, STATUS_HANDSHAKE); // Write the status handshake ID - - // Write the handshake bytes to the output stream - writeVarInt(outputStream, handshakeBytes.size()); - outputStream.write(handshakeBytes.toByteArray()); - } - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/packet/impl/java/JavaPacketStatusInStart.java b/src/main/java/me/braydon/mc/common/packet/impl/java/JavaPacketStatusInStart.java deleted file mode 100644 index 7e9009e..0000000 --- a/src/main/java/me/braydon/mc/common/packet/impl/java/JavaPacketStatusInStart.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.common.packet.impl.java; - -import lombok.Getter; -import lombok.NonNull; -import me.braydon.mc.common.packet.MinecraftJavaPacket; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -/** - * This packet is sent by the client to the server to request the - * status of the server. The server will respond with a json object - * containing the server's status. - * - * @author Braydon - * @see Protocol Docs - */ -@Getter -public final class JavaPacketStatusInStart extends MinecraftJavaPacket { - private static final byte ID = 0x00; // The ID of the packet - - /** - * The response json from the server, null if none. - */ - private String response; - - /** - * Process this packet. - * - * @param inputStream the input stream to read from - * @param outputStream the output stream to write to - * @throws IOException if an I/O error occurs - */ - @Override - public void process(@NonNull DataInputStream inputStream, @NonNull DataOutputStream outputStream) throws IOException { - // Send the status request - outputStream.writeByte(0x01); // Size of packet - outputStream.writeByte(ID); - - // Read the status response - readVarInt(inputStream); // Size of the response - int id = readVarInt(inputStream); - if (id == -1) { // The stream was prematurely ended - throw new IOException("Server prematurely ended stream."); - } else if (id != ID) { // Invalid packet ID - throw new IOException("Server returned invalid packet ID."); - } - - int length = readVarInt(inputStream); // Length of the response - if (length == -1) { // The stream was prematurely ended - throw new IOException("Server prematurely ended stream."); - } else if (length == 0) { - throw new IOException("Server returned unexpected value."); - } - - // Get the json response - byte[] data = new byte[length]; - inputStream.readFully(data); - response = new String(data); - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/web/JsonWebException.java b/src/main/java/me/braydon/mc/common/web/JsonWebException.java deleted file mode 100644 index e7f40f6..0000000 --- a/src/main/java/me/braydon/mc/common/web/JsonWebException.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.common.web; - -import lombok.Getter; -import lombok.NonNull; - -/** - * This exception is raised when a - * {@link JsonWebRequest} encounters an error. - * - * @author Braydon - */ -@Getter -public class JsonWebException extends RuntimeException { - /** - * The status code of the response. - */ - private final int statusCode; - - protected JsonWebException(int statusCode, @NonNull String message) { - super(message); - this.statusCode = statusCode; - } - - protected JsonWebException(int statusCode, @NonNull Throwable cause) { - super(cause); - this.statusCode = statusCode; - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/web/JsonWebRequest.java b/src/main/java/me/braydon/mc/common/web/JsonWebRequest.java deleted file mode 100644 index 95a8469..0000000 --- a/src/main/java/me/braydon/mc/common/web/JsonWebRequest.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.common.web; - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import me.braydon.mc.RESTfulMC; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; - -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.util.Collections; -import java.util.HashMap; -import java.util.Map; - -/** - * A Json web request. - * - * @author Braydon - */ -@RequiredArgsConstructor(access = AccessLevel.PRIVATE) @Getter -public final class JsonWebRequest { - private static final HttpClient HTTP_CLIENT = HttpClient.newHttpClient(); - - /** - * The endpoint to make the request to. - */ - @NonNull private final String endpoint; - - /** - * The method to use for the request. - */ - @NonNull private final HttpMethod method; - - /** - * The headers to send with the request. - */ - private final Map headers = Collections.synchronizedMap(new HashMap<>()); - - /** - * Make a new web request. - * - * @param endpoint the endpoint to make the request to - * @param method the method of the request to make - * @return the web request - */ - @NonNull - public static JsonWebRequest makeRequest(@NonNull String endpoint, @NonNull HttpMethod method) { - return new JsonWebRequest(endpoint, method); - } - - /** - * Set a header for this request. - * - * @param name the header name - * @param value the header value - * @return the request - */ - @NonNull - public JsonWebRequest header(@NonNull String name, @NonNull String value) { - headers.put(name, value); - return this; - } - - /** - * Execute this request. - * - * @param responseType the response type - * @return the response - * @param the type of the response - * @throws JsonWebException if an error is encountered while making the request - */ - public T execute(@NonNull Class responseType) throws JsonWebException { - // Build the request - HttpRequest.Builder request = HttpRequest.newBuilder() - .uri(URI.create(endpoint)) - .method(method.name(), HttpRequest.BodyPublishers.noBody()); - // Append headers - headers.put("User-Agent", "RESTfulMC"); - headers.put("Content-Type", "application/json"); - for (Map.Entry header : headers.entrySet()) { - request.header(header.getKey(), header.getValue()); - } - - // Send the request and get the response - int status = -1; // The response status code - try { - HttpResponse response = HTTP_CLIENT.send(request.build(), HttpResponse.BodyHandlers.ofString()); - status = response.statusCode(); // Set the response status - if (status != HttpStatus.OK.value()) { // Status code is not OK, raise an exception - throw new IOException("Failed to make a %s request to %s: %s".formatted(method.name(), endpoint, status)); - } - // Return with the response as the type - return RESTfulMC.GSON.fromJson(response.body(), responseType); - } catch (Exception ex) { - if (!(ex instanceof JsonWebException)) { - throw new JsonWebException(status, ex); - } - throw (JsonWebException) ex; - } - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/config/AppConfig.java b/src/main/java/me/braydon/mc/config/AppConfig.java deleted file mode 100644 index 86cb96f..0000000 --- a/src/main/java/me/braydon/mc/config/AppConfig.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.config; - -import jakarta.annotation.PostConstruct; -import lombok.Getter; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; - -/** - * The configuration for the app. - * - * @author Braydon - */ -@Configuration @Getter -public class AppConfig { - public static AppConfig INSTANCE; - - @Value("${server.publicUrl}") - private String serverPublicUrl; - - @PostConstruct - public void onInitialize() { - INSTANCE = this; - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/config/RedisConfig.java b/src/main/java/me/braydon/mc/config/RedisConfig.java deleted file mode 100644 index d14f68f..0000000 --- a/src/main/java/me/braydon/mc/config/RedisConfig.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.config; - -import lombok.NonNull; -import lombok.extern.log4j.Log4j2; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisStandaloneConfiguration; -import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; - -/** - * @author Braydon - */ -@Configuration -@Log4j2(topic = "Redis") -public class RedisConfig { - /** - * The Redis server host. - */ - @Value("${spring.data.redis.host}") - private String host; - - /** - * The Redis server port. - */ - @Value("${spring.data.redis.port}") - private int port; - - /** - * The Redis database index. - */ - @Value("${spring.data.redis.database}") - private int database; - - /** - * The optional Redis password. - */ - @Value("${spring.data.redis.auth}") - private String auth; - - /** - * Build the config to use for Redis. - * - * @return the config - * @see RedisTemplate for config - */ - @Bean @NonNull - public RedisTemplate redisTemplate() { - RedisTemplate template = new RedisTemplate<>(); - template.setConnectionFactory(jedisConnectionFactory()); - return template; - } - - /** - * Build the connection factory to use - * when making connections to Redis. - * - * @return the built factory - * @see JedisConnectionFactory for factory - */ - @Bean @NonNull - public JedisConnectionFactory jedisConnectionFactory() { - log.info("Connecting to Redis at {}:{}/{}", host, port, database); - RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(host, port); - config.setDatabase(database); - if (!auth.trim().isEmpty()) { // Auth with our provided password - log.info("Using auth..."); - config.setPassword(auth); - } - return new JedisConnectionFactory(config); - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/config/WebMvcConfig.java b/src/main/java/me/braydon/mc/config/WebMvcConfig.java deleted file mode 100644 index dbeab90..0000000 --- a/src/main/java/me/braydon/mc/config/WebMvcConfig.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.config; - -import com.google.gson.Gson; -import me.braydon.mc.RESTfulMC; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.json.GsonHttpMessageConverter; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -import java.util.List; - -/** - * @author Braydon - */ -@Configuration -public class WebMvcConfig implements WebMvcConfigurer { - @Override - public void configureMessageConverters(List> converters) { - GsonHttpMessageConverter gsonHttpMessageConverter = new GsonHttpMessageConverter(); - gsonHttpMessageConverter.setGson(gson()); - converters.add(gsonHttpMessageConverter); - } - - @Bean - public Gson gson() { - return RESTfulMC.GSON; - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/controller/PlayerController.java b/src/main/java/me/braydon/mc/controller/PlayerController.java deleted file mode 100644 index 2400d35..0000000 --- a/src/main/java/me/braydon/mc/controller/PlayerController.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.controller; - -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.NonNull; -import lombok.extern.log4j.Log4j2; -import me.braydon.mc.exception.impl.BadRequestException; -import me.braydon.mc.exception.impl.MojangRateLimitException; -import me.braydon.mc.exception.impl.ResourceNotFoundException; -import me.braydon.mc.model.Player; -import me.braydon.mc.model.cache.CachedPlayer; -import me.braydon.mc.service.MojangService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -/** - * The controller for handling - * {@link Player} related requests. - * - * @author Braydon - */ -@RestController -@RequestMapping(value = "/player", produces = MediaType.APPLICATION_JSON_VALUE) -@Log4j2(topic = "Player Controller") -@Tag(name = "Player Controller", description = "The controller for handling player related requests.") -public final class PlayerController { - /** - * The Mojang service to use for player information. - */ - @NonNull private final MojangService mojangService; - - @Autowired - public PlayerController(@NonNull MojangService mojangService) { - this.mojangService = mojangService; - } - - /** - * A GET route to get a player by their username or UUID. - * - * @param query the query to search for the player by - * @return the player response - * @throws BadRequestException if the UUID or username is invalid - * @throws ResourceNotFoundException if the player is not found - * @throws MojangRateLimitException if the Mojang API rate limit is reached - */ - @GetMapping("/{query}") - @ResponseBody - public ResponseEntity getPlayer(@PathVariable @NonNull String query) - throws BadRequestException, ResourceNotFoundException, MojangRateLimitException { - return ResponseEntity.ofNullable(mojangService.getPlayer(query, false)); - } - - /** - * Get the part of a skin texture for - * a player by their username or UUID. - *

- * If the player being searched is - * invalid, the default Steve skin - * will be used. - *

- * - * @param partName the part of the player's skin texture to get - * @param query the query to search for the player by - * @param extension the skin part image extension - * @param size the size of the skin part image - * @return the skin part texture - * @throws BadRequestException if the extension is invalid - */ - @GetMapping(value = "/{partName}/{query}.{extension}", produces = { MediaType.IMAGE_PNG_VALUE, MediaType.IMAGE_JPEG_VALUE }) - @ResponseBody - public ResponseEntity getPartTexture(@PathVariable @NonNull String partName, @PathVariable @NonNull String query, - @PathVariable @NonNull String extension, @RequestParam(required = false) String size - ) throws BadRequestException { - return ResponseEntity.ok() - .contentType(extension.equalsIgnoreCase("png") ? MediaType.IMAGE_PNG : MediaType.IMAGE_JPEG) - .body(mojangService.getSkinPartTexture(partName, query, extension, size)); - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/controller/ServerController.java b/src/main/java/me/braydon/mc/controller/ServerController.java deleted file mode 100644 index 7760719..0000000 --- a/src/main/java/me/braydon/mc/controller/ServerController.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.controller; - -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.NonNull; -import lombok.extern.log4j.Log4j2; -import me.braydon.mc.exception.impl.BadRequestException; -import me.braydon.mc.exception.impl.ResourceNotFoundException; -import me.braydon.mc.model.MinecraftServer; -import me.braydon.mc.model.cache.CachedMinecraftServer; -import me.braydon.mc.service.MojangService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.Map; - -/** - * The controller for handling - * {@link MinecraftServer} related requests. - * - * @author Braydon - */ -@RestController -@RequestMapping(value = "/server", produces = MediaType.APPLICATION_JSON_VALUE) -@Log4j2(topic = "Server Controller") -@Tag(name = "Server Controller", description = "The controller for handling server related requests.") -public final class ServerController { - /** - * The Mojang service to use for server information. - */ - @NonNull private final MojangService mojangService; - - @Autowired - public ServerController(@NonNull MojangService mojangService) { - this.mojangService = mojangService; - } - - /** - * Get a Minecraft server by its platform and hostname. - * - * @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, platform, or port 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, - @RequestParam(required = false) String port - ) throws BadRequestException, ResourceNotFoundException { - return ResponseEntity.ofNullable(mojangService.getMinecraftServer(platform, hostname, port)); - } - - /** - * Check if the server with the - * given hostname is blocked by Mojang. - * - * @param hostname the server hostname to check - * @return whether the hostname is blocked - */ - @GetMapping("/blocked/{hostname}") - @ResponseBody - public ResponseEntity> isServerBlocked(@PathVariable @NonNull String hostname) { - return ResponseEntity.ok(Map.of( - "blocked", mojangService.isServerBlocked(hostname) - )); - } - - /** - * Get the server icon of a Minecraft - * 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, @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, port)); - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/exception/ExceptionControllerAdvice.java b/src/main/java/me/braydon/mc/exception/ExceptionControllerAdvice.java deleted file mode 100644 index 691d1ce..0000000 --- a/src/main/java/me/braydon/mc/exception/ExceptionControllerAdvice.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.exception; - -import lombok.NonNull; -import me.braydon.mc.model.response.ErrorResponse; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.servlet.resource.NoResourceFoundException; - -/** - * Advice for handling raised exceptions. - * - * @author Braydon - */ -@ControllerAdvice -public final class ExceptionControllerAdvice { - /** - * Handle a raised exception. - * - * @param ex the raised exception - * @return the error response - */ - @ExceptionHandler(Exception.class) - public ResponseEntity handleException(@NonNull Exception ex) { - HttpStatus status = null; // Get the HTTP status - if (ex instanceof NoResourceFoundException) { // Not found - status = HttpStatus.NOT_FOUND; - } else if (ex instanceof UnsupportedOperationException) { // Not implemented - status = HttpStatus.NOT_IMPLEMENTED; - } - if (ex.getClass().isAnnotationPresent(ResponseStatus.class)) { // Get from the @ResponseStatus annotation - status = ex.getClass().getAnnotation(ResponseStatus.class).value(); - } - String message = ex.getLocalizedMessage(); // Get the error message - if (message == null) { // Fallback - message = "An internal error has occurred."; - } - // Print the stack trace if no response status is present - if (status == null) { - ex.printStackTrace(); - } - if (status == null) { // Fallback to 500 - status = HttpStatus.INTERNAL_SERVER_ERROR; - } - return new ResponseEntity<>(new ErrorResponse(status, message), status); - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/exception/impl/BadRequestException.java b/src/main/java/me/braydon/mc/exception/impl/BadRequestException.java deleted file mode 100644 index 371e06f..0000000 --- a/src/main/java/me/braydon/mc/exception/impl/BadRequestException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.exception.impl; - -import lombok.experimental.StandardException; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -/** - * This exception is raised - * when a bad request is made. - * - * @author Braydon - */ -@StandardException -@ResponseStatus(HttpStatus.BAD_REQUEST) -public final class BadRequestException extends RuntimeException { } \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/exception/impl/MojangRateLimitException.java b/src/main/java/me/braydon/mc/exception/impl/MojangRateLimitException.java deleted file mode 100644 index fe60421..0000000 --- a/src/main/java/me/braydon/mc/exception/impl/MojangRateLimitException.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.exception.impl; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -/** - * This exception is raised when the - * Mojang API rate limit is reached. - * - * @author Braydon - */ -@ResponseStatus(HttpStatus.TOO_MANY_REQUESTS) -public final class MojangRateLimitException extends RuntimeException { - public MojangRateLimitException() { - super("Mojang requests exhausted, please try again later."); - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/exception/impl/ResourceNotFoundException.java b/src/main/java/me/braydon/mc/exception/impl/ResourceNotFoundException.java deleted file mode 100644 index b7fd8e6..0000000 --- a/src/main/java/me/braydon/mc/exception/impl/ResourceNotFoundException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.exception.impl; - -import lombok.experimental.StandardException; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -/** - * This exception is raised - * when a resource is not found. - * - * @author Braydon - */ -@StandardException -@ResponseStatus(HttpStatus.NOT_FOUND) -public final class ResourceNotFoundException extends RuntimeException { } \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/log/TransactionLogger.java b/src/main/java/me/braydon/mc/log/TransactionLogger.java deleted file mode 100644 index 701350f..0000000 --- a/src/main/java/me/braydon/mc/log/TransactionLogger.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.log; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; -import me.braydon.mc.common.IPUtils; -import org.springframework.core.MethodParameter; -import org.springframework.http.MediaType; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.server.ServerHttpRequest; -import org.springframework.http.server.ServerHttpResponse; -import org.springframework.http.server.ServletServerHttpRequest; -import org.springframework.http.server.ServletServerHttpResponse; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; - -import java.util.Arrays; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -/** - * Responsible for logging request and - * response transactions to the terminal. - * - * @author Braydon - */ -@ControllerAdvice -@Slf4j(topic = "Req/Res Transaction") -public class TransactionLogger implements ResponseBodyAdvice { - @Override - public Object beforeBodyWrite(Object body, @NonNull MethodParameter returnType, @NonNull MediaType selectedContentType, - @NonNull Class> selectedConverterType, @NonNull ServerHttpRequest rawRequest, - @NonNull ServerHttpResponse rawResponse) { - HttpServletRequest request = ((ServletServerHttpRequest) rawRequest).getServletRequest(); - HttpServletResponse response = ((ServletServerHttpResponse) rawResponse).getServletResponse(); - - // Get the request ip ip - String ip = IPUtils.getRealIp(request); - - // Getting params - Map params = new HashMap<>(); - for (Entry entry : request.getParameterMap().entrySet()) { - params.put(entry.getKey(), Arrays.toString(entry.getValue())); - } - - // Getting headers - Map headers = new HashMap<>(); - Enumeration headerNames = request.getHeaderNames(); - while (headerNames.hasMoreElements()) { - String headerName = headerNames.nextElement(); - headers.put(headerName, request.getHeader(headerName)); - } - - // Log the request - log.info(String.format("[Req] %s | %s | '%s', params=%s, headers=%s", - request.getMethod(), - ip, - request.getRequestURI(), - params, - headers - )); - - // Getting response headers - headers = new HashMap<>(); - for (String headerName : response.getHeaderNames()) { - headers.put(headerName, response.getHeader(headerName)); - } - - // Log the response - log.info(String.format("[Res] %s, headers=%s", - response.getStatus(), - headers - )); - return body; - } - - @Override - public boolean supports(@NonNull MethodParameter returnType, @NonNull Class> converterType) { - return true; - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/model/Cape.java b/src/main/java/me/braydon/mc/model/Cape.java deleted file mode 100644 index 422d87e..0000000 --- a/src/main/java/me/braydon/mc/model/Cape.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.model; - -import com.google.gson.JsonObject; -import lombok.*; - -/** - * A cape for a {@link Player}. - * - * @author Braydon - */ -@AllArgsConstructor(access = AccessLevel.PRIVATE) @Getter @ToString -public final class Cape { - /** - * The texture URL of this cape. - */ - @NonNull private final String url; - - /** - * Build a cape from the given Json object. - * - * @param jsonObject the json object to build from - * @return the built cape - */ - public static Cape fromJsonObject(JsonObject jsonObject) { - if (jsonObject == null) { // No object to parse - return null; - } - return new Cape(jsonObject.get("url").getAsString()); - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/model/MinecraftServer.java b/src/main/java/me/braydon/mc/model/MinecraftServer.java deleted file mode 100644 index d999feb..0000000 --- a/src/main/java/me/braydon/mc/model/MinecraftServer.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.model; - -import lombok.*; -import me.braydon.mc.common.ColorUtils; -import me.braydon.mc.service.pinger.MinecraftServerPinger; -import me.braydon.mc.service.pinger.impl.BedrockMinecraftServerPinger; -import me.braydon.mc.service.pinger.impl.JavaMinecraftServerPinger; - -import java.util.Arrays; -import java.util.UUID; - -/** - * A model representing a Minecraft server. - * - * @author Braydon - */ -@AllArgsConstructor @Getter @EqualsAndHashCode(onlyExplicitlyIncluded = true) @ToString -public class MinecraftServer { - /** - * The hostname of this server. - */ - @EqualsAndHashCode.Include @NonNull private final String hostname; - - /** - * The IP address of this server, if resolved. - */ - private final String ip; - - /** - * The port of this server. - */ - @EqualsAndHashCode.Include private final int port; - - /** - * The player counts of this server. - */ - @NonNull private final Players players; - - /** - * The MOTD of this server. - */ - @NonNull private final MOTD motd; - - /** - * Player count data for a server. - */ - @AllArgsConstructor @Getter @ToString - public static class Players { - /** - * The online players on this server. - */ - private final int online; - - /** - * The maximum allowed players on this server. - */ - private final int max; - - /** - * A sample of players on this server, null or empty if no sample. - */ - private final Sample[] sample; - - /** - * A sample player. - */ - @AllArgsConstructor @Getter @ToString - public static class Sample { - /** - * The unique id of this player. - */ - @NonNull private final UUID id; - - /** - * The name of this player. - */ - @NonNull private final String name; - } - } - - /** - * The MOTD for a server. - */ - @AllArgsConstructor @Getter @ToString - public static class MOTD { - /** - * The raw MOTD lines. - */ - @NonNull private final String[] raw; - - /** - * The clean MOTD lines (no color codes). - */ - @NonNull private final String[] clean; - - /** - * The HTML MOTD lines. - */ - @NonNull private final String[] html; - - /** - * Create a new MOTD from a raw string. - * - * @param raw the raw motd string - * @return the new motd - */ - @NonNull - public static MOTD create(@NonNull String raw) { - String[] rawLines = raw.split("\n"); // The raw lines - return new MOTD( - rawLines, - Arrays.stream(rawLines).map(ColorUtils::stripColor).toArray(String[]::new), - Arrays.stream(rawLines).map(ColorUtils::toHTML).toArray(String[]::new) - ); - } - } - - /** - * A platform a Minecraft - * server can operate on. - */ - @AllArgsConstructor @Getter - public enum Platform { - /** - * The Java edition of Minecraft. - */ - JAVA(new JavaMinecraftServerPinger(), 25565), - - /** - * The Bedrock edition of Minecraft. - */ - BEDROCK(new BedrockMinecraftServerPinger(), 19132); - - /** - * The server pinger for this platform. - */ - @NonNull private final MinecraftServerPinger pinger; - - /** - * The default server port for this platform. - */ - private final int defaultPort; - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/model/Player.java b/src/main/java/me/braydon/mc/model/Player.java deleted file mode 100644 index 6ac8c68..0000000 --- a/src/main/java/me/braydon/mc/model/Player.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.model; - -import lombok.*; -import org.springframework.data.annotation.Id; - -import java.util.UUID; - -/** - * A model representing a player. - * - * @author Braydon - */ -@AllArgsConstructor @Getter -@EqualsAndHashCode(onlyExplicitlyIncluded = true) -@ToString -public class Player { - /** - * The unique id of this player. - */ - @Id @EqualsAndHashCode.Include @NonNull private final UUID uniqueId; - - /** - * The username of this player. - */ - @NonNull private final String username; - - /** - * The skin of this player. - */ - @NonNull private final Skin skin; - - /** - * The cape of this player, null if none. - */ - private final Cape cape; - - /** - * The profile actions this player has, null if none. - */ - private final ProfileAction[] profileActions; -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/model/ProfileAction.java b/src/main/java/me/braydon/mc/model/ProfileAction.java deleted file mode 100644 index 0f64265..0000000 --- a/src/main/java/me/braydon/mc/model/ProfileAction.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.model; - -/** - * Profile actions that can - * be taken on a {@link Player}. - * - * @author Braydon - */ -public enum ProfileAction { - /** - * The player is required to change their - * username before accessing Multiplayer. - */ - FORCED_NAME_CHANGE, - - /** - * The player is using a banned skin. - */ - USING_BANNED_SKIN -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/model/Skin.java b/src/main/java/me/braydon/mc/model/Skin.java deleted file mode 100644 index 88b5f05..0000000 --- a/src/main/java/me/braydon/mc/model/Skin.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.model; - -import com.google.gson.JsonObject; -import com.google.gson.annotations.SerializedName; -import lombok.*; -import me.braydon.mc.common.ImageUtils; -import me.braydon.mc.config.AppConfig; - -import java.util.HashMap; -import java.util.Map; - -/** - * A skin for a {@link Player}. - * - * @author Braydon - */ -@RequiredArgsConstructor(access = AccessLevel.PRIVATE) @Setter @Getter @ToString -public final class Skin { - public static final Skin DEFAULT_STEVE = new Skin("http://textures.minecraft.net/texture/60a5bd016b3c9a1b9272e4929e30827a67be4ebb219017adbbc4a4d22ebd5b1", Model.DEFAULT); - - /** - * The texture URL of this skin. - */ - @NonNull private final String url; - - /** - * The model of this skin. - */ - @NonNull private final Model model; - - /** - * URLs to the parts of this skin. - */ - @NonNull @SerializedName("parts") private Map partUrls = new HashMap<>(); - - /** - * Populate the part URLs for this skin. - * - * @param playerUuid the UUID of the player - * @return the skin - */ - @NonNull - public Skin populatePartUrls(@NonNull String playerUuid) { - for (Part part : Part.values()) { - partUrls.put(part.name(), AppConfig.INSTANCE.getServerPublicUrl() + "/player/" + part.name().toLowerCase() + "/" + playerUuid + ".png"); - } - return this; - } - - /** - * Build a skin from the given Json object. - * - * @param jsonObject the json object to build from - * @return the built skin - */ - public static Skin fromJsonObject(JsonObject jsonObject) { - if (jsonObject == null) { // No object to parse - return null; - } - Model model = Model.DEFAULT; // The skin model - - JsonObject metadataJsonObject = jsonObject.getAsJsonObject("metadata"); - if (metadataJsonObject != null) { // Parse the skin model - model = Model.valueOf(metadataJsonObject.get("model").getAsString().toUpperCase()); - } - return new Skin(jsonObject.get("url").getAsString(), model); - } - - /** - * Possible models for a skin. - */ - public enum Model { - SLIM, DEFAULT - } - - /** - * The part of a skin. - */ - @AllArgsConstructor @Getter @ToString - public enum Part { - HEAD(8, 8, ImageUtils.SKIN_TEXTURE_SIZE / 8, ImageUtils.SKIN_TEXTURE_SIZE / 8); - - /** - * The coordinates of this part. - */ - private final int x, y; - - /** - * The size of this part. - */ - private final int width, height; - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/model/cache/CachedMinecraftServer.java b/src/main/java/me/braydon/mc/model/cache/CachedMinecraftServer.java deleted file mode 100644 index 5051e67..0000000 --- a/src/main/java/me/braydon/mc/model/cache/CachedMinecraftServer.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.model.cache; - -import lombok.*; -import me.braydon.mc.model.MinecraftServer; -import org.springframework.data.annotation.Id; -import org.springframework.data.redis.core.RedisHash; - -import java.io.Serializable; - -/** - * @author Braydon - */ -@AllArgsConstructor @Setter @Getter @ToString -@RedisHash(value = "server", timeToLive = 60L) // 1 minute (in seconds) -public final class CachedMinecraftServer implements Serializable { - /** - * The id of this cached server. - */ - @Id @NonNull private transient final String id; - - /** - * The cached server. - */ - @NonNull private final MinecraftServer value; - - /** - * The unix timestamp of when this - * server was cached, -1 if not cached. - */ - private long cached; -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/model/cache/CachedPlayer.java b/src/main/java/me/braydon/mc/model/cache/CachedPlayer.java deleted file mode 100644 index 4978674..0000000 --- a/src/main/java/me/braydon/mc/model/cache/CachedPlayer.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.model.cache; - -import lombok.Getter; -import lombok.NonNull; -import lombok.Setter; -import lombok.ToString; -import me.braydon.mc.model.Cape; -import me.braydon.mc.model.Player; -import me.braydon.mc.model.ProfileAction; -import me.braydon.mc.model.Skin; -import org.springframework.data.redis.core.RedisHash; - -import java.io.Serializable; -import java.util.UUID; - -/** - * A cacheable {@link Player}. - * - * @author Braydon - */ -@Setter @Getter -@ToString(callSuper = true) -@RedisHash(value = "player", timeToLive = 60L * 60L) // 1 hour (in seconds) -public final class CachedPlayer extends Player implements Serializable { - /** - * The unix timestamp of when this - * player was cached, -1 if not cached. - */ - private long cached; - - public CachedPlayer(@NonNull UUID uniqueId, @NonNull String username, - @NonNull Skin skin, Cape cape, ProfileAction[] profileActions, long cached) { - super(uniqueId, username, skin, cape, profileActions); - this.cached = cached; - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/model/cache/CachedPlayerName.java b/src/main/java/me/braydon/mc/model/cache/CachedPlayerName.java deleted file mode 100644 index 3a60e22..0000000 --- a/src/main/java/me/braydon/mc/model/cache/CachedPlayerName.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.model.cache; - -import lombok.*; -import org.springframework.data.annotation.Id; -import org.springframework.data.redis.core.RedisHash; - -import java.util.UUID; - -/** - * @author Braydon - */ -@AllArgsConstructor -@Getter -@EqualsAndHashCode(onlyExplicitlyIncluded = true) -@ToString -@RedisHash(value = "playerName", timeToLive = 60L * 60L) // 1 hour (in seconds) -public final class CachedPlayerName { - /** - * The username of the player. - */ - @Id @NonNull private String username; - - /** - * The unique id of the player. - */ - @NonNull private UUID uniqueId; -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/model/response/ErrorResponse.java b/src/main/java/me/braydon/mc/model/response/ErrorResponse.java deleted file mode 100644 index 59bcc89..0000000 --- a/src/main/java/me/braydon/mc/model/response/ErrorResponse.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.model.response; - -import lombok.Getter; -import lombok.NonNull; -import lombok.ToString; -import org.springframework.http.HttpStatus; - -import java.util.Date; - -/** - * A response representing an error. - * - * @author Braydon - */ -@Getter @ToString -public final class ErrorResponse { - /** - * The status code of this error. - */ - @NonNull private final HttpStatus status; - - /** - * The HTTP code of this error. - */ - private final int code; - - /** - * The message of this error. - */ - @NonNull private final String message; - - /** - * The timestamp this error occurred. - */ - @NonNull private final Date timestamp; - - public ErrorResponse(@NonNull HttpStatus status, @NonNull String message) { - this.status = status; - code = status.value(); - this.message = message; - timestamp = new Date(); - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/model/server/BedrockMinecraftServer.java b/src/main/java/me/braydon/mc/model/server/BedrockMinecraftServer.java deleted file mode 100644 index f1c3dd7..0000000 --- a/src/main/java/me/braydon/mc/model/server/BedrockMinecraftServer.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.model.server; - -import lombok.*; -import me.braydon.mc.model.MinecraftServer; - -/** - * A Bedrock edition {@link MinecraftServer}. - * - * @author Braydon - */ -@Getter @ToString(callSuper = true) @EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = true) -public final class BedrockMinecraftServer extends MinecraftServer { - /** - * The unique ID of this server. - */ - @EqualsAndHashCode.Include @NonNull private final String uniqueId; - - /** - * The edition of this server. - */ - @NonNull private final Edition edition; - - /** - * The version information of this server. - */ - @NonNull private final Version version; - - /** - * The gamemode of this server. - */ - @NonNull private final GameMode gamemode; - - private BedrockMinecraftServer(@NonNull String uniqueId, @NonNull String hostname, String ip, int port, - @NonNull Edition edition, @NonNull Version version, @NonNull Players players, - @NonNull MOTD motd, @NonNull GameMode gamemode) { - super(hostname, ip, port, players, motd); - this.uniqueId = uniqueId; - this.edition = edition; - this.version = version; - this.gamemode = gamemode; - } - - /** - * Create a new Bedrock Minecraft server. - * - * @param hostname the hostname of the server - * @param ip the IP address of the server - * @param port the port of the server - * @param token the status token - * @return the Bedrock Minecraft server - */ - @NonNull - public static BedrockMinecraftServer create(@NonNull String hostname, String ip, int port, @NonNull String token) { - String[] split = token.split(";"); // Split the token - - Edition edition; - try { - edition = Edition.valueOf(split[0]); - } catch (IllegalArgumentException ex) { - // Funky fix, but sometimes the edition can contain an extra - // portion of the length of the edition, so we need to remove it - edition = Edition.valueOf(split[0].substring(1)); - } - - Version version = new Version(Integer.parseInt(split[2]), split[3]); - Players players = new Players(Integer.parseInt(split[4]), Integer.parseInt(split[5]), null); - MOTD motd = MOTD.create(split[1] + "\n" + split[7]); - GameMode gameMode = new GameMode(split[8], Integer.parseInt(split[9])); - return new BedrockMinecraftServer(split[6], hostname, ip, port, edition, version, players, motd, gameMode); - } - - /** - * The edition of a Bedrock server. - */ - @AllArgsConstructor @Getter - public enum Edition { - /** - * Minecraft: Pocket Edition. - */ - MCPE, - - /** - * Minecraft: Education Edition. - */ - MCEE - } - - /** - * Version information for a server. - */ - @AllArgsConstructor @Getter @ToString - public static class Version { - /** - * The protocol version of the server. - */ - private final int protocol; - - /** - * The version name of the server. - */ - @NonNull private final String name; - } - - /** - * The gamemode of a server. - */ - @AllArgsConstructor @Getter @ToString - public static class GameMode { - /** - * The name of this gamemode. - */ - @NonNull private final String name; - - /** - * The numeric of this gamemode. - */ - private final int numericId; - } -} \ 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 deleted file mode 100644 index 2050493..0000000 --- a/src/main/java/me/braydon/mc/model/server/JavaMinecraftServer.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.model.server; - -import com.google.gson.annotations.SerializedName; -import lombok.*; -import me.braydon.mc.RESTfulMC; -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; -import me.braydon.mc.service.MojangService; -import net.md_5.bungee.api.chat.TextComponent; -import net.md_5.bungee.chat.ComponentSerializer; - -/** - * A Java edition {@link MinecraftServer}. - * - * @author Braydon - */ -@Setter @Getter @ToString(callSuper = true) -public final class JavaMinecraftServer extends MinecraftServer { - /** - * The version information of this server. - */ - @NonNull private final Version version; - - /** - * The favicon of this server, null if none. - */ - private final Favicon favicon; - - /** - * The Forge mod information for this server, null if none. - */ - private final ModInfo modInfo; - - /** - * Does this server enforce secure chat? - */ - private final boolean enforcesSecureChat; - - /** - * Is this server preventing chat reports? - */ - private final boolean preventsChatReports; - - /** - * Is this server on the list - * of blocked servers by Mojang? - *

- * This value is later set by the - * {@link MojangService} when a server - * is requested. - *

- * - * @see Mojang API - */ - private boolean mojangBanned; - - private JavaMinecraftServer(@NonNull String hostname, String ip, int port, @NonNull Version version, - @NonNull Players players, @NonNull MOTD motd, Favicon favicon, ModInfo modInfo, - boolean enforcesSecureChat, boolean preventsChatReports, boolean mojangBanned) { - super(hostname, ip, port, players, motd); - this.version = version; - this.favicon = favicon; - this.modInfo = modInfo; - this.enforcesSecureChat = enforcesSecureChat; - this.preventsChatReports = preventsChatReports; - this.mojangBanned = mojangBanned; - } - - /** - * Create a new Java Minecraft server. - * - * @param hostname the hostname of the server - * @param ip the IP address of the server - * @param port the port of the server - * @param token the status token - * @return the Java Minecraft server - */ - @NonNull - public static JavaMinecraftServer create(@NonNull String hostname, String ip, int port, @NonNull JavaServerStatusToken token) { - String motdString = token.getDescription() instanceof String ? (String) token.getDescription() : null; - if (motdString == null) { // Not a string motd, convert from Json - motdString = new TextComponent(ComponentSerializer.parse(RESTfulMC.GSON.toJson(token.getDescription()))).toLegacyText(); - } - return new JavaMinecraftServer(hostname, ip, port, token.getVersion().detailedCopy(), token.getPlayers(), - MOTD.create(motdString), Favicon.create(token.getFavicon(), hostname), token.getModInfo(), - token.isEnforcesSecureChat(), token.isPreventsChatReports(), false - ); - } - - /** - * Version information for a server. - */ - @AllArgsConstructor @Getter @ToString - public static class Version { - /** - * The version name of the server. - */ - @NonNull private final String name; - - /** - * The identified platform of the server, null if unknown. - */ - private String platform; - - /** - * The protocol version of the server. - */ - private final int protocol; - - /** - * The name of the version for the protocol, null if unknown. - */ - private final String protocolName; - - /** - * Create a more detailed - * copy of this object. - * - * @return the detailed copy - */ - @NonNull - public Version detailedCopy() { - String platform = null; - if (name.contains(" ")) { // Parse the server platform - String[] split = name.split(" "); - if (split.length == 2) { - platform = split[0]; - } - } - JavaMinecraftVersion minecraftVersion = JavaMinecraftVersion.byProtocol(protocol); - return new Version(name, platform, protocol, minecraftVersion == null ? null : minecraftVersion.getName()); - } - } - - /** - * The favicon for a server. - */ - @AllArgsConstructor @Getter @ToString - public static class Favicon { - /** - * The raw Base64 encoded favicon. - */ - @NonNull private final String base64; - - /** - * The URL to the favicon. - */ - @NonNull private final String url; - - /** - * Create a new favicon for a server. - * - * @param base64 the Base64 encoded favicon - * @param hostname the server hostname - * @return the favicon, null if none - */ - public static Favicon create(String base64, @NonNull String hostname) { - if (base64 == null) { // No favicon to create - return null; - } - return new Favicon( - base64, - AppConfig.INSTANCE.getServerPublicUrl() + "/server/icon/" + hostname - ); - } - } - - /** - * Forge mod information for a server. - */ - @AllArgsConstructor @Getter @ToString - public static class ModInfo { - /** - * The type of modded server this is. - */ - @NonNull private final String type; - - /** - * The list of mods on this server, null or empty if none. - */ - private final ForgeMod[] modList; - } - - /** - * A forge mod for a server. - */ - @AllArgsConstructor @Getter @ToString - private static class ForgeMod { - /** - * The id of this mod. - */ - @NonNull @SerializedName("modid") private final String id; - - /** - * The version of this mod. - */ - private final String version; - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/model/token/JavaServerStatusToken.java b/src/main/java/me/braydon/mc/model/token/JavaServerStatusToken.java deleted file mode 100644 index faa09d6..0000000 --- a/src/main/java/me/braydon/mc/model/token/JavaServerStatusToken.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.model.token; - -import com.google.gson.annotations.SerializedName; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NonNull; -import lombok.ToString; -import me.braydon.mc.model.MinecraftServer; -import me.braydon.mc.model.server.JavaMinecraftServer; - -/** - * A token representing the response from - * pinging a {@link JavaMinecraftServer}. - * - * @author Braydon - */ -@AllArgsConstructor @Getter @ToString -public final class JavaServerStatusToken { - /** - * The description (MOTD) of this server. - *

- * Legacy: String, New: JSON Object - *

- */ - @NonNull private final Object description; - - /** - * The base64 encoded favicon of this server, null if no favicon. - */ - private final String favicon; - - /** - * The version information of this server. - */ - @NonNull private final JavaMinecraftServer.Version version; - - /** - * The player counts of this server. - */ - @NonNull private final MinecraftServer.Players players; - - /** - * The Forge mod information for this server, null if none. - */ - @SerializedName("modinfo") private final JavaMinecraftServer.ModInfo modInfo; - - /** - * Does this server enforce secure chat? - */ - private final boolean enforcesSecureChat; - - /** - * Is this server preventing chat reports? - */ - private final boolean preventsChatReports; -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/model/token/MojangProfileToken.java b/src/main/java/me/braydon/mc/model/token/MojangProfileToken.java deleted file mode 100644 index adb8231..0000000 --- a/src/main/java/me/braydon/mc/model/token/MojangProfileToken.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.model.token; - -import com.google.gson.JsonObject; -import lombok.*; -import me.braydon.mc.RESTfulMC; -import me.braydon.mc.common.Tuple; -import me.braydon.mc.model.Cape; -import me.braydon.mc.model.ProfileAction; -import me.braydon.mc.model.Skin; - -import java.util.Base64; - -/** - * A token representing a Mojang user profile. - * - * @author Braydon - * @see Mojang API - */ -@AllArgsConstructor @Getter @EqualsAndHashCode(onlyExplicitlyIncluded = true) @ToString -public final class MojangProfileToken { - /** - * The id of the profile. - */ - @EqualsAndHashCode.Include @NonNull private final String id; - - /** - * The name of the profile. - */ - @NonNull private final String name; - - /** - * The properties of the profile. - */ - @NonNull private final ProfileProperty[] properties; - - /** - * The actions this profile has. - */ - @NonNull private final ProfileAction[] profileActions; - - /** - * Get the skin and cape of this profile. - * - * @return the skin and cape of this profile - */ - public Tuple getSkinAndCape() { - ProfileProperty textures = getPropertyByName("textures"); // Get the profile textures - if (textures == null) { // No profile textures - return new Tuple<>(); - } - JsonObject jsonObject = RESTfulMC.GSON.fromJson(textures.getDecodedValue(), JsonObject.class); // Get the Json object - JsonObject texturesJsonObject = jsonObject.getAsJsonObject("textures"); // Get the textures object - - // Return the tuple containing the skin and cape - return new Tuple<>( - Skin.fromJsonObject(texturesJsonObject.getAsJsonObject("SKIN")).populatePartUrls(id), - Cape.fromJsonObject(texturesJsonObject.getAsJsonObject("CAPE")) - ); - } - - /** - * Get the profile property - * with the given name. - * - * @param name the property name - * @return the profile property, null if none - */ - public ProfileProperty getPropertyByName(@NonNull String name) { - for (ProfileProperty property : properties) { - if (property.getName().equalsIgnoreCase(name)) { - return property; - } - } - return null; - } - - /** - * A property of a Mojang profile. - */ - @NoArgsConstructor @Setter @Getter @EqualsAndHashCode(onlyExplicitlyIncluded = true) @ToString - public static class ProfileProperty { - /** - * The name of this property. - */ - @EqualsAndHashCode.Include @NonNull private String name; - - /** - * The base64 value of this property. - */ - @NonNull private String value; - - /** - * The base64 signature of this property. - */ - private String signature; - - /** - * Get the decoded Base64 - * value of this property. - * - * @return the decoded value - */ - @NonNull - public String getDecodedValue() { - return new String(Base64.getDecoder().decode(value)); - } - - /** - * Is this property signed? - * - * @return whether this property has a signature - */ - public boolean isSigned() { - return signature != null; - } - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/model/token/MojangUsernameToUUIDToken.java b/src/main/java/me/braydon/mc/model/token/MojangUsernameToUUIDToken.java deleted file mode 100644 index 9be0328..0000000 --- a/src/main/java/me/braydon/mc/model/token/MojangUsernameToUUIDToken.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.model.token; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NonNull; -import lombok.ToString; - -/** - * A token representing a Mojang username to UUID response. - * - * @author Braydon - * @see Mojang API - */ -@AllArgsConstructor @Getter @ToString -public final class MojangUsernameToUUIDToken { - /** - * The id of the username. - */ - @NonNull private final String id; -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/repository/MinecraftServerCacheRepository.java b/src/main/java/me/braydon/mc/repository/MinecraftServerCacheRepository.java deleted file mode 100644 index 596a5f6..0000000 --- a/src/main/java/me/braydon/mc/repository/MinecraftServerCacheRepository.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.repository; - -import me.braydon.mc.model.cache.CachedMinecraftServer; -import org.springframework.data.repository.CrudRepository; - -/** - * A cache repository for {@link CachedMinecraftServer}'s. - * - * @author Braydon - */ -public interface MinecraftServerCacheRepository extends CrudRepository { } \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/repository/PlayerCacheRepository.java b/src/main/java/me/braydon/mc/repository/PlayerCacheRepository.java deleted file mode 100644 index bad024a..0000000 --- a/src/main/java/me/braydon/mc/repository/PlayerCacheRepository.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.repository; - -import me.braydon.mc.model.cache.CachedPlayer; -import org.springframework.data.repository.CrudRepository; - -import java.util.UUID; - -/** - * A cache repository for {@link CachedPlayer}'s. - * - * @author Braydon - */ -public interface PlayerCacheRepository extends CrudRepository { } \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/repository/PlayerNameCacheRepository.java b/src/main/java/me/braydon/mc/repository/PlayerNameCacheRepository.java deleted file mode 100644 index 476b4da..0000000 --- a/src/main/java/me/braydon/mc/repository/PlayerNameCacheRepository.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.repository; - -import me.braydon.mc.model.cache.CachedPlayerName; -import org.springframework.data.repository.CrudRepository; - -/** - * A cache repository for player usernames. - *

- * This will allow us to easily lookup a - * player's username and get their uuid. - *

- * - * @author Braydon - */ -public interface PlayerNameCacheRepository extends CrudRepository { } \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/service/MojangService.java b/src/main/java/me/braydon/mc/service/MojangService.java deleted file mode 100644 index c1d589a..0000000 --- a/src/main/java/me/braydon/mc/service/MojangService.java +++ /dev/null @@ -1,479 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.service; - -import com.google.common.base.Joiner; -import com.google.common.base.Splitter; -import com.google.common.collect.Lists; -import com.google.common.hash.Hashing; -import jakarta.annotation.PostConstruct; -import lombok.NonNull; -import lombok.SneakyThrows; -import lombok.extern.log4j.Log4j2; -import me.braydon.mc.common.*; -import me.braydon.mc.common.web.JsonWebException; -import me.braydon.mc.common.web.JsonWebRequest; -import me.braydon.mc.exception.impl.BadRequestException; -import me.braydon.mc.exception.impl.MojangRateLimitException; -import me.braydon.mc.exception.impl.ResourceNotFoundException; -import me.braydon.mc.model.*; -import me.braydon.mc.model.cache.CachedMinecraftServer; -import me.braydon.mc.model.cache.CachedPlayer; -import me.braydon.mc.model.cache.CachedPlayerName; -import me.braydon.mc.model.server.JavaMinecraftServer; -import me.braydon.mc.model.token.MojangProfileToken; -import me.braydon.mc.model.token.MojangUsernameToUUIDToken; -import me.braydon.mc.repository.MinecraftServerCacheRepository; -import me.braydon.mc.repository.PlayerCacheRepository; -import me.braydon.mc.repository.PlayerNameCacheRepository; -import net.jodah.expiringmap.ExpirationPolicy; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpMethod; -import org.springframework.stereotype.Service; - -import java.io.InputStream; -import java.net.InetSocketAddress; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.TimeUnit; - -/** - * A service for interacting with the Mojang API. - * - * @author Braydon - */ -@Service -@Log4j2(topic = "Mojang Service") -public final class MojangService { - private static final String SESSION_SERVER_ENDPOINT = "https://sessionserver.mojang.com"; - private static final String API_ENDPOINT = "https://api.mojang.com"; - private static final String UUID_TO_PROFILE = SESSION_SERVER_ENDPOINT + "/session/minecraft/profile/%s"; - private static final String USERNAME_TO_UUID = API_ENDPOINT + "/users/profiles/minecraft/%s"; - private static final String FETCH_BLOCKED_SERVERS = SESSION_SERVER_ENDPOINT + "/blockedservers"; - - private static final int DEFAULT_PART_TEXTURE_SIZE = 128; - private static final int MAX_PART_TEXTURE_SIZE = 512; - - private static final String DEFAULT_SERVER_ICON = "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAASFBMVEWwsLBBQUE9PT1JSUlFRUUuLi5MTEyzs7M0NDQ5OTlVVVVQUFAmJia5ubl+fn5zc3PFxcVdXV3AwMCJiYmUlJRmZmbQ0NCjo6OL5p+6AAAFVklEQVRYw+1W67K0KAzkJnIZdRAZ3/9NtzvgXM45dX7st1VbW7XBUVDSdEISRqn/5R+T82/+nsr/XZn/SHm/3x9/ArA/IP8qwPK433d44VubZ/XT6/cJy0L792VZfnDrcRznr86d748u92X5vtaxOe228zcCy+MSMpg/5SwRopsYMv8oigCwngbQhE/rzhwAYMpxnvMvHhgy/8AgByJolzb5pPqEbvtgMBBmtvkbgxKmaaIZ5TyPum6Viue6te241N+s+W6nOlucgjEx6Nay9zZta1XVxejW+Q5ZhhkDS31lgOTegjUBor33CQilbC2GYGy9y9bN8ytevjE4a2stajHDAgAcUkoYwzO6zQi8ZflC+XO0+exiuNa3OQtIJOCk13neUjv7VO7Asu/3LwDFeg37sQtQhy4lAQH6IR9ztca0E3oI5PtDAlJ1tHGplrJ12jjrrXPWYvXsU042Bl/qUr3B9qzPSKaovpvjgglYL2F1x+Zs7gIvpLYuq46wr3H5/RJxyvM6sXOY762oU4YZ3mAz1lpc9O3Y30VJUM/iWhBIib63II/LA4COEMxcSmrH4ddl/wTYe3RIO0vK2VI9wQy6AxRsJpb3AAALvXb6TxvUCYSdOQo5Mh0GySkJc7rB405GUEfzbbl/iFpPoNQVNUQAZG06nkI6RCABRqRA9IimH6Up5Mhybtu2IlewB2Sf6AmQ4ZU9rfBELvyA23Yub6LWWtUBgK3OB79L7FILLDKWd4wpxmMRAMoLQR1ItLoiWUmhFtjptab7LQDgRARliLITLrcBkHNp9VACUH1UDRQEYGuYxzyM9H0mBccQNnCkQ3Q1UHBaO6sNyw0CelEtBGXKSoE+fJWZh5GupyneMIkCOMESAniMAzMreLvuO+pnmBQSp4C+ELCiMSGVLPh7M023SSBAiAA5yPh2m0wigEbWKnw3qDrrscF00cciCATGwNQRAv2YGvyD4Y36QGhqOS4AcABAA88oGvBCRho5H2+UiW6EfyM1L5l8a56rqdvE6lFakc3ScVDOBNBUoFM8c1vgnhAG5VsAqMD6Q9IwwtAkR39iGEQF1ZBxgU+v9UGL6MBQYiTdJllIBtx5y0rixGdAZ1YysbS53TAVy3vf4aabEpt1T0HoB2Eg4Yv5OKNwyHgmNvPKaQAYLG3EIyIqcL6Fj5C2jhXL9EpCdRMROE5nCW3qm1vfR6wYh0HKGG3wY+JgLkUWQ/WMfI8oMvIWMY7aCncNxxpSmHRUCEzDdSR0+dRwIQaMWW1FE0AOGeKkx0OLwYanBK3qfC0BSmIlozkuFcvSkulckoIB2FbHWu0y9gMHsEapMMEoySNUA2RDrduxIqr5POQV2zZ++IBOwVrFO9THrtjU2uWsCMZjxXl88Hmeaz1rPdAqXyJl68F5RTtdvN1aIyYEAMAWJaCMHvon7s23jljlxoKBEgNv6LQ25/rZIQyOdwDO3jLsqE2nbVAil21LxqFpZ2xJ3CFuE33QCo7kfkfO8kpW6gdioxdzZDLOaMMwidzeKD0RxaD7cnHHsu0jVkW5oTwwMGI0lwwA36u2nMY8AKzErLW9JxFiteyzZsAAxY1vPe5Uf68lIDVjV8JZpPfjxbc/QuyRKdAQJaAdIA4tCTht+kQJ1I4nbdjfHxgpTSLyI19pb/iuK7+9YJaZCxEIKj79YZ6uDU8f97878teRN1FzA7OvquSrVKUgk+S6ROpJfA7GpN6RPkx4voshXgu91p7CGHeA+IY8dUUVXwT7PYw12Xsj0Lfh9X4ac9XgKW86cj8bPh8XmyDOD88FLoB+YPXp4YtyB3gBPXu98xeRI2zploVCBQAAAABJRU5ErkJggg=="; - - private static final Splitter DOT_SPLITTER = Splitter.on('.'); - private static final Joiner DOT_JOINER = Joiner.on('.'); - - /** - * The cache repository for {@link Player}'s by their username. - */ - @NonNull private final PlayerNameCacheRepository playerNameCache; - - /** - * The cache repository for {@link Player}'s. - */ - @NonNull private final PlayerCacheRepository playerCache; - - /** - * The cache repository for {@link MinecraftServer}'s. - */ - @NonNull private final MinecraftServerCacheRepository minecraftServerCache; - - /** - * A list of banned server hashes provided by Mojang. - *

- * This is periodically fetched from Mojang, see - * {@link #fetchBlockedServers()} for more info. - *

- * - * @see Mojang API - */ - private List bannedServerHashes; - - /** - * A cache of blocked server hostnames. - * - * @see #isServerHostnameBlocked(String) for more - */ - private final ExpiringSet blockedServersCache = new ExpiringSet<>(ExpirationPolicy.CREATED, 10L, TimeUnit.MINUTES); - - @Autowired - public MojangService(@NonNull PlayerNameCacheRepository playerNameCache, @NonNull PlayerCacheRepository playerCache, - @NonNull MinecraftServerCacheRepository minecraftServerCache) { - this.playerNameCache = playerNameCache; - this.playerCache = playerCache; - this.minecraftServerCache = minecraftServerCache; - } - - @PostConstruct - public void onInitialize() { - // Schedule a task to fetch blocked - // servers from Mojang every 15 minutes. - new Timer().scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - fetchBlockedServers(); - } - }, 0L, 60L * 15L * 1000L); - } - - /** - * Get the part of a skin texture for - * a player by their username or UUID. - * - * @param partName the part of the player's skin texture to get - * @param query the query to search for the player by - * @param extension the skin part image extension - * @param sizeString the size of the skin part image - * @return the skin part texture - * @throws BadRequestException if the extension is invalid - * @throws MojangRateLimitException if the Mojang API rate limit is reached - */ - public byte[] getSkinPartTexture(@NonNull String partName, @NonNull String query, @NonNull String extension, String sizeString) - throws BadRequestException, MojangRateLimitException { - Integer size = null; - if (sizeString != null) { // Attempt to parse the size - try { - size = Integer.parseInt(sizeString); - } catch (NumberFormatException ignored) { - // Safely ignore, invalid number provided - } - } - Skin.Part part = EnumUtils.getEnumConstant(Skin.Part.class, partName.toUpperCase()); // The skin part to get - if (part == null) { // Default to the head part - part = Skin.Part.HEAD; - } - if (extension.isBlank()) { // Invalid extension - throw new BadRequestException("Invalid extension"); - } - if (size == null || size <= 0) { // Invalid size - size = DEFAULT_PART_TEXTURE_SIZE; - } - size = Math.min(size, MAX_PART_TEXTURE_SIZE); // Limit the size to 512 - - Skin target = null; // The target skin to get the skin part of - try { - CachedPlayer player = getPlayer(query, false); // Retrieve the player - target = player.getSkin(); // Use the player's skin - } catch (Exception ignored) { - // Simply ignore, and fallback to the default skin - } - if (target == null) { // Fallback to the default skin - target = Skin.DEFAULT_STEVE; - } - return ImageUtils.getSkinPart(target, part, size); - } - - /** - * Get a player by their username or UUID. - *

- * If the player is present within the cache, that will - * be returned. If the player is not cached, a request - * will be made to retrieve the player from Mojang, cache it - * and then return the response. - *

- * - * @param query the query to search for the player by - * @param bypassCache should the cache be bypassed? - * @return the player - * @throws BadRequestException if the UUID or username is invalid - * @throws ResourceNotFoundException if the player is not found - * @throws MojangRateLimitException if the Mojang API rate limit is reached - */ - @NonNull - public CachedPlayer getPlayer(@NonNull String query, boolean bypassCache) - throws BadRequestException, ResourceNotFoundException, MojangRateLimitException { - log.info("Requesting player with query: {}", query); - - UUID uuid; // The player UUID to lookup - boolean isFullUuid = query.length() == 36; // Was a UUID provided? - if (query.length() == 32 || isFullUuid) { // Parse the query as a UUID - try { - uuid = isFullUuid ? UUID.fromString(query) : UUIDUtils.addDashes(query); - log.info("Parsed {}UUID: {} -> {}", isFullUuid ? "" : "trimmed ", query, uuid); - } catch (IllegalArgumentException ex) { - throw new BadRequestException("Malformed UUID provided: %s".formatted(query)); - } - } else { // The query is a username, request from Mojang - if (!MiscUtils.isUsernameValid(query)) { // Ensure the username is valid - throw new BadRequestException("Invalid username provided: %s".formatted(query)); - } - uuid = usernameToUUID(query); - log.info("Found UUID for username {}: {}", query, uuid); - } - - // Check the cache for the player - if (!bypassCache) { - Optional cached = playerCache.findById(uuid); - if (cached.isPresent()) { // Respond with the cache if present - log.info("Found player in cache: {}", uuid); - return cached.get(); - } - } - - // Send a request to Mojang requesting - // the player profile by their UUID - try { - log.info("Retrieving player profile for UUID: {}", uuid); - MojangProfileToken token = JsonWebRequest.makeRequest( - UUID_TO_PROFILE.formatted(uuid), HttpMethod.GET - ).execute(MojangProfileToken.class); - Tuple skinAndCape = token.getSkinAndCape(); // Get the skin and cape - ProfileAction[] profileActions = token.getProfileActions(); - - // Build our player model, cache it, and then return it - CachedPlayer player = new CachedPlayer( - uuid, token.getName(), - skinAndCape.getLeft() == null ? Skin.DEFAULT_STEVE : skinAndCape.getLeft(), - skinAndCape.getRight(), - profileActions.length == 0 ? null : profileActions, - System.currentTimeMillis() - ); - if (!bypassCache) { // Store in the cache - playerCache.save(player); - log.info("Cached player: {}", uuid); - } - - player.setCached(-1L); // Set to -1 to indicate it's not cached in the response - return player; - } catch (JsonWebException ex) { - // No profile found, return null - if (ex.getStatusCode() == 400) { - throw new ResourceNotFoundException("Player not found with query: %s".formatted(query)); - } - throw ex; - } - } - - /** - * Get the favicon of a Java - * server with the given hostname. - *

- * If the favicon of the server cannot be - * retrieved, the default icon will be used. - *

- * - * @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, String port) { - String icon = null; // The server base64 icon - try { - 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 - } - } catch (BadRequestException | ResourceNotFoundException ignored) { - // Safely ignore these, we will use the default server icon - } - if (icon == null) { // Use the default server icon - icon = DEFAULT_SERVER_ICON; - } - return Base64.getDecoder().decode(icon); // Return the decoded favicon - } - - /** - * Check if the server with the - * given hostname is blocked by Mojang. - * - * @param hostname the server hostname to check - * @return whether the hostname is blocked - */ - public boolean isServerBlocked(@NonNull String hostname) { - // Remove trailing dots - while (hostname.charAt(hostname.length() - 1) == '.') { - hostname = hostname.substring(0, hostname.length() - 1); - } - // Is the hostname banned? - if (isServerHostnameBlocked(hostname)) { - return true; - } - List splitDots = Lists.newArrayList(DOT_SPLITTER.split(hostname)); // Split the hostname by dots - boolean isIp = splitDots.size() == 4; // Is it an IP address? - if (isIp) { - for (String element : splitDots) { - try { - int part = Integer.parseInt(element); - if (part >= 0 && part <= 255) { // Ensure the part is within the valid range - continue; - } - } catch (NumberFormatException ignored) { - // Safely ignore, not a number - } - isIp = false; - break; - } - } - // Check if the hostname is blocked - if (!isIp && isServerHostnameBlocked("*." + hostname)) { - return true; - } - // Additional checks for the hostname - while (splitDots.size() > 1) { - splitDots.remove(isIp ? splitDots.size() - 1 : 0); - String starredPart = isIp ? DOT_JOINER.join(splitDots) + ".*" : "*." + DOT_JOINER.join(splitDots); - if (isServerHostnameBlocked(starredPart)) { - return true; - } - } - return false; - } - - /** - * Resolve a Minecraft server on the given - * platform with the given hostname. - * - * @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, platform, or port is invalid - * @throws ResourceNotFoundException if the server isn't found - */ - @NonNull - 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 - - 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 + "-" + 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 - 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 + "-" + (portString == null ? port : portString), - platform.getPinger().ping(hostname, port), - System.currentTimeMillis() - ); - - // Get the blocked status of the Java server - if (platform == MinecraftServer.Platform.JAVA) { - ((JavaMinecraftServer) minecraftServer.getValue()).setMojangBanned(isServerBlocked(hostname)); - } - - minecraftServerCache.save(minecraftServer); - log.info("Cached server: {}", hostname); - minecraftServer.setCached(-1L); // Set to -1 to indicate it's not cached in the response - return minecraftServer; - } - - /** - * Get the UUID of a player by their username. - * - * @param username the player's username - * @return the player's UUID - * @throws ResourceNotFoundException if the player isn't found - * @throws MojangRateLimitException if the Mojang rate limit is reached - */ - @NonNull - private UUID usernameToUUID(@NonNull String username) throws ResourceNotFoundException, MojangRateLimitException { - String originalUsername = username; - username = username.toLowerCase(); // Lowercase the username - - // Check the cache for the player's UUID - Optional cached = playerNameCache.findById(username); - if (cached.isPresent()) { // Respond with the cache if present - log.info("Found UUID in cache for username {}: {}", originalUsername, cached.get().getUniqueId()); - return cached.get().getUniqueId(); - } - - // Make a request to Mojang requesting the UUID - try { - MojangUsernameToUUIDToken token = JsonWebRequest.makeRequest( - USERNAME_TO_UUID.formatted(username), HttpMethod.GET - ).execute(MojangUsernameToUUIDToken.class); - - // Cache the UUID and return it - UUID uuid = UUIDUtils.addDashes(token.getId()); - playerNameCache.save(new CachedPlayerName(username, uuid)); - log.info("Cached UUID for username {}: {}", username, uuid); - return uuid; - } catch (JsonWebException ex) { - if (ex.getStatusCode() == 429) { // Mojang rate limit reached - throw new MojangRateLimitException(); - } else if (ex.getStatusCode() == 404) { // Player not found - throw new ResourceNotFoundException("Player not found with username: %s".formatted(originalUsername)); - } - throw ex; - } - } - - /** - * Fetch a list of blocked servers from Mojang. - */ - @SneakyThrows - private void fetchBlockedServers() { - try ( - InputStream inputStream = new URL(FETCH_BLOCKED_SERVERS).openStream(); - Scanner scanner = new Scanner(inputStream, StandardCharsets.UTF_8).useDelimiter("\n"); - ) { - List hashes = new ArrayList<>(); - while (scanner.hasNext()) { - hashes.add(scanner.next()); - } - bannedServerHashes = Collections.synchronizedList(hashes); - log.info("Fetched {} banned server hashes", bannedServerHashes.size()); - } - } - - /** - * Check if the hash for the given - * hostname is in the blocked server list. - * - * @param hostname the hostname to check - * @return whether the hostname is blocked - */ - private boolean isServerHostnameBlocked(@NonNull String hostname) { - // Check the cache first for the hostname - if (blockedServersCache.contains(hostname)) { - return true; - } - String hashed = Hashing.sha1().hashBytes(hostname.toLowerCase().getBytes(StandardCharsets.ISO_8859_1)).toString(); - boolean blocked = bannedServerHashes.contains(hashed); // Is the hostname blocked? - if (blocked) { // Cache the blocked hostname - blockedServersCache.add(hostname); - } - return blocked; - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/service/pinger/MinecraftServerPinger.java b/src/main/java/me/braydon/mc/service/pinger/MinecraftServerPinger.java deleted file mode 100644 index a37d337..0000000 --- a/src/main/java/me/braydon/mc/service/pinger/MinecraftServerPinger.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.service.pinger; - -import lombok.NonNull; -import me.braydon.mc.model.MinecraftServer; - -/** - * A {@link MinecraftServerPinger} is - * used to ping a {@link MinecraftServer}. - * - * @author Braydon - * @param the type of server to ping - */ -public interface MinecraftServerPinger { - /** - * Ping the server with the given hostname and port. - * - * @param hostname the hostname of the server - * @param port the port of the server - * @return the server that was pinged - */ - T ping(@NonNull String hostname, int port); -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/service/pinger/impl/BedrockMinecraftServerPinger.java b/src/main/java/me/braydon/mc/service/pinger/impl/BedrockMinecraftServerPinger.java deleted file mode 100644 index 3fcf26f..0000000 --- a/src/main/java/me/braydon/mc/service/pinger/impl/BedrockMinecraftServerPinger.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.service.pinger.impl; - -import lombok.NonNull; -import lombok.extern.log4j.Log4j2; -import me.braydon.mc.common.DNSUtils; -import me.braydon.mc.common.packet.impl.bedrock.BedrockPacketUnconnectedPing; -import me.braydon.mc.common.packet.impl.bedrock.BedrockPacketUnconnectedPong; -import me.braydon.mc.exception.impl.BadRequestException; -import me.braydon.mc.exception.impl.ResourceNotFoundException; -import me.braydon.mc.model.server.BedrockMinecraftServer; -import me.braydon.mc.service.pinger.MinecraftServerPinger; - -import java.io.IOException; -import java.net.*; - -/** - * The {@link MinecraftServerPinger} for pinging - * {@link BedrockMinecraftServer} over UDP. - * - * @author Braydon - */ -@Log4j2(topic = "Bedrock MC Server Pinger") -public final class BedrockMinecraftServerPinger implements MinecraftServerPinger { - private static final int TIMEOUT = 3000; // The timeout for the socket - - /** - * Ping the server with the given hostname and port. - * - * @param hostname the hostname of the server - * @param port the port of the server - * @return the server that was pinged - */ - @Override - public BedrockMinecraftServer ping(@NonNull String hostname, int port) { - InetAddress inetAddress = DNSUtils.resolveA(hostname); // Resolve the hostname to an IP address - String ip = inetAddress == null ? null : inetAddress.getHostAddress(); // Get the IP address - if (ip != null) { // Was the IP resolved? - log.info("Resolved hostname: {} -> {}", hostname, ip); - } - log.info("Pinging {}:{}...", hostname, port); - long before = System.currentTimeMillis(); // Timestamp before pinging - - // Open a socket connection to the server - try (DatagramSocket socket = new DatagramSocket()) { - socket.setSoTimeout(TIMEOUT); - socket.connect(new InetSocketAddress(hostname, port)); - - long ping = System.currentTimeMillis() - before; // Calculate the ping - log.info("Pinged {}:{} in {}ms", hostname, port, ping); - - // Send the unconnected ping packet - new BedrockPacketUnconnectedPing().process(socket); - - // Handle the received unconnected pong packet - BedrockPacketUnconnectedPong unconnectedPong = new BedrockPacketUnconnectedPong(); - unconnectedPong.process(socket); - String response = unconnectedPong.getResponse(); - if (response == null) { // No pong response - throw new ResourceNotFoundException("Server didn't respond to ping"); - } - return BedrockMinecraftServer.create(hostname, ip, port, response); // Return the server - } catch (IOException ex) { - if (ex instanceof UnknownHostException) { - throw new BadRequestException("Unknown hostname: %s".formatted(hostname)); - } else if (ex instanceof SocketTimeoutException) { - throw new ResourceNotFoundException(ex); - } - log.error("An error occurred pinging %s:%s:".formatted(hostname, port), ex); - } - return null; - } -} \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/service/pinger/impl/JavaMinecraftServerPinger.java b/src/main/java/me/braydon/mc/service/pinger/impl/JavaMinecraftServerPinger.java deleted file mode 100644 index 0817bd3..0000000 --- a/src/main/java/me/braydon/mc/service/pinger/impl/JavaMinecraftServerPinger.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.service.pinger.impl; - -import lombok.NonNull; -import lombok.extern.log4j.Log4j2; -import me.braydon.mc.RESTfulMC; -import me.braydon.mc.common.DNSUtils; -import me.braydon.mc.common.packet.impl.java.JavaPacketHandshakingInSetProtocol; -import me.braydon.mc.common.packet.impl.java.JavaPacketStatusInStart; -import me.braydon.mc.exception.impl.BadRequestException; -import me.braydon.mc.exception.impl.ResourceNotFoundException; -import me.braydon.mc.model.server.JavaMinecraftServer; -import me.braydon.mc.model.token.JavaServerStatusToken; -import me.braydon.mc.service.pinger.MinecraftServerPinger; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.net.*; - -/** - * The {@link MinecraftServerPinger} for pinging - * {@link JavaMinecraftServer}'s over TCP. - * - * @author Braydon - */ -@Log4j2(topic = "Java MC Server Pinger") -public final class JavaMinecraftServerPinger implements MinecraftServerPinger { - private static final int TIMEOUT = 3000; // The timeout for the socket - - /** - * Ping the server with the given hostname and port. - * - * @param hostname the hostname of the server - * @param port the port of the server - * @return the server that was pinged - * @throws BadRequestException if the hostname is unknown - * @throws ResourceNotFoundException if the server could not be found - */ - @Override - public JavaMinecraftServer ping(@NonNull String hostname, int port) throws BadRequestException, ResourceNotFoundException { - InetAddress inetAddress = DNSUtils.resolveA(hostname); // Resolve the hostname to an IP address - String ip = inetAddress == null ? null : inetAddress.getHostAddress(); // Get the IP address - if (ip != null) { // Was the IP resolved? - log.info("Resolved hostname: {} -> {}", hostname, ip); - } - log.info("Pinging {}:{}...", hostname, port); - long before = System.currentTimeMillis(); // Timestamp before pinging - - // Open a socket connection to the server - try (Socket socket = new Socket()) { - socket.setTcpNoDelay(true); - socket.connect(new InetSocketAddress(hostname, port), TIMEOUT); - - long ping = System.currentTimeMillis() - before; // Calculate the ping - log.info("Pinged {}:{} in {}ms", hostname, port, ping); - - // Open data streams to begin packet transaction - try (DataInputStream inputStream = new DataInputStream(socket.getInputStream()); - DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream())) { - // Begin handshaking with the server - new JavaPacketHandshakingInSetProtocol(hostname, port, 47).process(inputStream, outputStream); - - // Send the status request to the server, and await back the response - JavaPacketStatusInStart packetStatusInStart = new JavaPacketStatusInStart(); - packetStatusInStart.process(inputStream, outputStream); - JavaServerStatusToken token = RESTfulMC.GSON.fromJson(packetStatusInStart.getResponse(), JavaServerStatusToken.class); - return JavaMinecraftServer.create(hostname, ip, port, token); // Return the server - } - } catch (IOException ex) { - if (ex instanceof UnknownHostException) { - throw new BadRequestException("Unknown hostname: %s".formatted(hostname)); - } else if (ex instanceof ConnectException || ex instanceof SocketTimeoutException) { - throw new ResourceNotFoundException(ex); - } - log.error("An error occurred pinging %s:%s:".formatted(hostname, port), ex); - } - return null; - } -} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml deleted file mode 100644 index 6c89f48..0000000 --- a/src/main/resources/application.yml +++ /dev/null @@ -1,28 +0,0 @@ -# Server Configuration -server: - address: 0.0.0.0 - port: 7500 - publicUrl: "http://localhost:7500" # The publicly accessible URL for this app - servlet: - context-path: / - -# Log Configuration -logging: - file: - path: "./logs" - -# Spring Configuration -spring: - data: - # Redis - This is used for caching - redis: - host: "localhost" - port: 6379 - database: 0 - auth: "" # Leave blank for no auth - - # Ignore - application: - name: "RESTfulMC" - banner: - location: "classpath:banner.txt" \ No newline at end of file diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt deleted file mode 100644 index c386a34..0000000 --- a/src/main/resources/banner.txt +++ /dev/null @@ -1,10 +0,0 @@ - _____ ______ _____ _______ __ _ __ __ _____ - | __ \| ____|/ ____|__ __/ _| | | \/ |/ ____| - | |__) | |__ | (___ | | | |_ _ _| | \ / | | - | _ /| __| \___ \ | | | _| | | | | |\/| | | - | | \ \| |____ ____) | | | | | | |_| | | | | | |____ - |_| \_\______|_____/ |_| |_| \__,_|_|_| |_|\_____| - - | API Version - v${application.version} - | Spring Version - ${spring-boot.formatted-version} -_______________________________________ diff --git a/src/main/resources/public/favicon.ico b/src/main/resources/public/favicon.ico deleted file mode 100644 index f8b6029..0000000 Binary files a/src/main/resources/public/favicon.ico and /dev/null differ diff --git a/src/main/resources/public/index.html b/src/main/resources/public/index.html deleted file mode 100644 index d86c264..0000000 --- a/src/main/resources/public/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - RESTfulMC - - -

RESTfulMC

-

A simple, yet useful RESTful API for Minecraft utilizing Springboot.

-

View the source here!

- - \ No newline at end of file diff --git a/src/test/java/me/braydon/mc/test/config/TestRedisConfig.java b/src/test/java/me/braydon/mc/test/config/TestRedisConfig.java deleted file mode 100644 index 89c8828..0000000 --- a/src/test/java/me/braydon/mc/test/config/TestRedisConfig.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.test.config; - -import jakarta.annotation.PostConstruct; -import jakarta.annotation.PreDestroy; -import lombok.NonNull; -import org.springframework.boot.test.context.TestConfiguration; -import redis.embedded.RedisServer; - -import java.io.IOException; - -/** - * Test configuration for - * a mock Redis server. - * - * @author Braydon - */ -@TestConfiguration -public class TestRedisConfig { - @NonNull private final RedisServer server; - - public TestRedisConfig() throws IOException { - server = new RedisServer(); // Construct the mock server - } - - /** - * Start up the mock Redis server. - * - * @throws IOException if there was an issue starting the server - */ - @PostConstruct - public void onInitialize() throws IOException { - server.start(); - } - - /** - * Shutdown the running mock Redis server. - * - * @throws IOException if there was an issue stopping the server - */ - @PreDestroy - public void housekeeping() throws IOException { - server.stop(); - } -} \ No newline at end of file diff --git a/src/test/java/me/braydon/mc/test/controller/PlayerControllerTests.java b/src/test/java/me/braydon/mc/test/controller/PlayerControllerTests.java deleted file mode 100644 index abe755a..0000000 --- a/src/test/java/me/braydon/mc/test/controller/PlayerControllerTests.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.test.controller; - -import lombok.NonNull; -import me.braydon.mc.controller.PlayerController; -import me.braydon.mc.test.config.TestRedisConfig; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -/** - * Tests for the {@link PlayerController}. - * - * @author Braydon - */ -@SpringBootTest(classes = TestRedisConfig.class) -@AutoConfigureMockMvc -public final class PlayerControllerTests { - /** - * The {@link MockMvc} instance to use for testing. - */ - @NonNull private final MockMvc mockMvc; - - @Autowired - public PlayerControllerTests(@NonNull MockMvc mockMvc) { - this.mockMvc = mockMvc; - } - - /** - * Run a test to ensure retrieving - * a player's data is successful. - * - * @throws Exception if the test fails - */ - @Test - void ensurePlayerLookupSuccess() throws Exception { - mockMvc.perform(get("/player/g") - .accept(MediaType.APPLICATION_JSON) // Accept JSON - .contentType(MediaType.APPLICATION_JSON) // Content type is JSON - ).andExpect(status().isOk()) // Expect 200 (OK) - .andExpect(jsonPath("$.username").value("g")) // Expect the player's username - .andReturn(); - } - - /** - * Run a test to ensure retrieving - * invalid player's results in a 404. - * - * @throws Exception if the test fails - */ - @Test - void ensurePlayerNotFound() throws Exception { - mockMvc.perform(get("/player/SDFSDFSDFSDFDDDG") - .accept(MediaType.APPLICATION_JSON) // Accept JSON - .contentType(MediaType.APPLICATION_JSON) // Content type is JSON - ).andExpect(status().isNotFound()) // Expect 404 (Not Found) - .andReturn(); - } - - /** - * Run a test to ensure retrieving - * player's with invalid usernames - * results in a 400. - * - * @throws Exception if the test fails - */ - @Test - void ensureUsernameIsInvalid() throws Exception { - mockMvc.perform(get("/player/A") - .accept(MediaType.APPLICATION_JSON) // Accept JSON - .contentType(MediaType.APPLICATION_JSON) // Content type is JSON - ).andExpect(status().isBadRequest()) // Expect 400 (Bad Request) - .andReturn(); - } - - /** - * Run a test to ensure retrieving - * a player's head texture is successful. - * - * @throws Exception if the test fails - */ - @Test - void ensureSkinPartTextureSuccess() throws Exception { - mockMvc.perform(get("/player/head/Rainnny.png") - .contentType(MediaType.IMAGE_PNG) // Content type is PNG - ).andExpect(status().isOk()) // Expect 200 (OK) - .andReturn(); - } -} \ No newline at end of file diff --git a/src/test/java/me/braydon/mc/test/controller/ServerControllerTests.java b/src/test/java/me/braydon/mc/test/controller/ServerControllerTests.java deleted file mode 100644 index 4b5737a..0000000 --- a/src/test/java/me/braydon/mc/test/controller/ServerControllerTests.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Braydon (Rainnny). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package me.braydon.mc.test.controller; - -import lombok.NonNull; -import me.braydon.mc.controller.ServerController; -import me.braydon.mc.test.config.TestRedisConfig; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -/** - * Tests for the {@link ServerController}. - * - * @author Braydon - */ -@SpringBootTest(classes = TestRedisConfig.class) -@AutoConfigureMockMvc -public final class ServerControllerTests { - /** - * The {@link MockMvc} instance to use for testing. - */ - @NonNull private final MockMvc mockMvc; - - @Autowired - public ServerControllerTests(@NonNull MockMvc mockMvc) { - this.mockMvc = mockMvc; - } - - /** - * Run a test to ensure retrieving - * a Java server's status is successful. - * - * @throws Exception if the test fails - */ - @Test - void ensureJavaServerLookupSuccess() throws Exception { - mockMvc.perform(get("/server/java/hypixel.net") - .accept(MediaType.APPLICATION_JSON) // Accept JSON - .contentType(MediaType.APPLICATION_JSON) // Content type is JSON - ).andExpect(status().isOk()) // Expect 200 (OK) - .andExpect(jsonPath("$.value.hostname") // Expect the server's resolved hostname - .value("mc.hypixel.net") - ).andReturn(); - } - - /** - * Run a test to ensure retrieving - * a Bedrock server's status is successful. - * - * @throws Exception if the test fails - */ - @Test - void ensureBedrockServerLookupSuccess() throws Exception { - mockMvc.perform(get("/server/bedrock/gateway.wildnetwork.net") - .accept(MediaType.APPLICATION_JSON) // Accept JSON - .contentType(MediaType.APPLICATION_JSON) // Content type is JSON - ).andExpect(status().isOk()) // Expect 200 (OK) - .andExpect(jsonPath("$.value.hostname") // Expect the server's resolved hostname - .value("gateway.wildnetwork.net") - ).andReturn(); - } - - /** - * Run a test to ensure that requesting - * information about a server on an invalid - * platform results in a 400. - * - * @throws Exception if the test fails - */ - @Test - void ensureUnknownPlatform() throws Exception { - mockMvc.perform(get("/server/invalid/hypixel.net") - .accept(MediaType.APPLICATION_JSON) // Accept JSON - .contentType(MediaType.APPLICATION_JSON) // Content type is JSON - ).andExpect(status().isBadRequest()) // Expect 400 (Bad Request) - .andReturn(); - } - - /** - * Run a test to ensure looking up - * an invalid hostname results in a 400. - * - * @throws Exception if the test fails - */ - @Test - void ensureUnknownHostname() throws Exception { - mockMvc.perform(get("/server/java/invalid") - .accept(MediaType.APPLICATION_JSON) // Accept JSON - .contentType(MediaType.APPLICATION_JSON) // Content type is JSON - ).andExpect(status().isBadRequest()) // Expect 400 (Bad Request) - .andReturn(); - } - - /** - * Run a test to ensure looking up - * an invalid port results in a 400. - * - * @throws Exception if the test fails - */ - @Test - void ensureUnknownPort() throws Exception { - mockMvc.perform(get("/server/java/hypixel.net?port=A") - .accept(MediaType.APPLICATION_JSON) // Accept JSON - .contentType(MediaType.APPLICATION_JSON) // Content type is JSON - ).andExpect(status().isBadRequest()) // Expect 400 (Bad Request) - .andReturn(); - } - - /** - * Run a test to ensure checking if - * a server is banned is successful. - * - * @throws Exception if the test fails - */ - @Test - void ensureServerBanCheckSuccess() throws Exception{ - mockMvc.perform(get("/server/blocked/arkhamnetwork.org") - .accept(MediaType.APPLICATION_JSON) // Accept JSON - .contentType(MediaType.APPLICATION_JSON) // Content type is JSON - ).andExpect(status().isOk()) // Expect 200 (OK) - .andExpect(jsonPath("$.blocked").value(true)) // Expect block - .andReturn(); - } - - /** - * Run a test to ensure retrieving - * a server's favicon is successful. - * - * @throws Exception if the test fails - */ - @Test - void ensureServerFaviconSuccess() throws Exception { - mockMvc.perform(get("/server/icon/hypixel.net") - .contentType(MediaType.IMAGE_PNG) // Content type is PNG - ).andExpect(status().isOk()) // Expect 200 (OK) - .andReturn(); - } -} \ No newline at end of file