commit ecde2bb2a72bea593481d4f58913ebd03039e1a3 Author: Liam Date: Wed Apr 17 21:06:43 2024 +0100 pls work first try diff --git a/.gitea/workflows/publish.yml b/.gitea/workflows/publish.yml new file mode 100644 index 0000000..e700acf --- /dev/null +++ b/.gitea/workflows/publish.yml @@ -0,0 +1,21 @@ +name: Publish package to the Maven Central Repository +on: + push: + branches: + - master + - +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Maven Central Repository + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'adopt' + - name: Publish package + run: mvn --batch-mode deploy + env: + MAVEN_USERNAME: ${{ secrets.REPO_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.REPO_PASSWORD }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..77440ae --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +### ME template +*.class +*.log +*.ctxt +.mtj.tmp/ +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar +hs_err_pid* +replay_pid* +.idea +cmake-build-*/ +.idea/**/mongoSettings.xml +*.iws +out/ +build/ +work/ +.idea_modules/ +atlassian-ide-plugin.xml +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties +git.properties +pom.xml.versionsBackup +application.yml +target/ diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..010b430 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..b820fdd --- /dev/null +++ b/pom.xml @@ -0,0 +1,67 @@ + + + 4.0.0 + + xyz.mcutils + mcutils-java-library + 1.0-SNAPSHOT + + + 17 + 17 + UTF-8 + + + + + mcutils-java-library + https://repo.fascinated.cc/public/mcutils-java-library/ + + + + + + + org.projectlombok + lombok + 1.18.32 + provided + + + com.google.code.gson + gson + 2.10.1 + compile + + + + + org.springframework + spring-web + 6.1.6 + compile + + + org.apache.httpcomponents.client5 + httpclient5 + 5.3 + compile + + + + + org.junit.jupiter + junit-jupiter-engine + 5.10.2 + test + + + org.junit.jupiter + junit-jupiter-api + 5.10.2 + test + + + \ No newline at end of file diff --git a/src/main/java/xyz/mcutils/McUtilsAPI.java b/src/main/java/xyz/mcutils/McUtilsAPI.java new file mode 100644 index 0000000..000a3e9 --- /dev/null +++ b/src/main/java/xyz/mcutils/McUtilsAPI.java @@ -0,0 +1,112 @@ +package xyz.mcutils; + +import xyz.mcutils.common.WebRequest; +import xyz.mcutils.exception.ErrorResponse; +import xyz.mcutils.models.mojang.CachedMojangEndpointStatus; +import xyz.mcutils.models.player.CachedPlayer; +import xyz.mcutils.models.player.CachedPlayerSkinPart; +import xyz.mcutils.models.player.CachedUsernameToUuid; +import xyz.mcutils.models.player.Skin; +import xyz.mcutils.models.server.*; + +public class McUtilsAPI { + private static final String API_ENDPOINT = "https://api.mcutils.xyz"; + private static final String MOJANG_API_STATUS_ENDPOINT = API_ENDPOINT + "/mojang/status"; + private static final String PLAYER_ENDPOINT = API_ENDPOINT + "/player/%s"; + private static final String USERNAME_TO_UUID_ENDPOINT = API_ENDPOINT + "/player/uuid/%s"; + private static final String PLAYER_SKIN_PART_ENDPOINT = API_ENDPOINT + "/player/%s/%s"; + private static final String SERVER_ENDPOINT = API_ENDPOINT + "/server/%s/%s"; + private static final String SERVER_ICON_ENDPOINT = API_ENDPOINT + "/server/icon/%s"; + private static final String SERVER_BLOCKED_STATUS_ENDPOINT = API_ENDPOINT + "/server/blocked/%s"; + + /** + * Gets the status of the Mojang APIs. + * + * @return The status of the Mojang API. + * @throws ErrorResponse If an error occurs. + */ + public static CachedMojangEndpointStatus getMojangApiStatus() throws ErrorResponse { + return WebRequest.get(MOJANG_API_STATUS_ENDPOINT, CachedMojangEndpointStatus.class); + } + + + /** + * Gets a player from the API. + * + * @param id The id of the player to get. + * @return The player. + * @throws ErrorResponse If an error occurs. + */ + public static CachedPlayer getPlayer(String id) throws ErrorResponse { + return WebRequest.get(PLAYER_ENDPOINT.formatted(id), CachedPlayer.class); + } + + /** + * Gets a player from the API. + * + * @param username The username of the player to get. + * @return The player. + * @throws ErrorResponse If an error occurs. + */ + public static CachedUsernameToUuid getUsernameToUuid(String username) throws ErrorResponse { + return WebRequest.get(USERNAME_TO_UUID_ENDPOINT.formatted(username), CachedUsernameToUuid.class); + } + + /** + * Gets a player skin part from the API. + * + * @param part The part of the skin to get. + * @param id The id of the player to get. + * @return The player skin part. + * @throws ErrorResponse If an error occurs. + */ + public static CachedPlayerSkinPart getPlayerSkinPart(Skin.SkinPart part, String id) throws ErrorResponse { + byte[] partBytes = WebRequest.get(PLAYER_SKIN_PART_ENDPOINT.formatted(part, id), byte[].class); + return new CachedPlayerSkinPart(partBytes); + } + + /** + * Gets a Bedrock server from the API. + * + * @param id The id of the server to get. + * @return The server. + * @throws ErrorResponse If an error occurs. + */ + public static CachedBedrockMinecraftServer getBedrockServer(String id) throws ErrorResponse { + return WebRequest.get(SERVER_ENDPOINT.formatted(ServerPlatform.BEDROCK.name(), id), CachedBedrockMinecraftServer.class); + } + + /** + * Gets a Java server from the API. + * + * @param id The id of the server to get. + * @return The server. + * @throws ErrorResponse If an error occurs. + */ + public static CachedJavaMinecraftServer getJavaServer(String id) throws ErrorResponse { + return WebRequest.get(SERVER_ENDPOINT.formatted(ServerPlatform.JAVA.name(), id), CachedJavaMinecraftServer.class); + } + + /** + * Gets the icon of a Java server from the API. + * + * @param id The id of the server to get the icon of. + * @return The server icon. + * @throws ErrorResponse If an error occurs. + */ + public static CachedServerIcon getServerIcon(String id) throws ErrorResponse { + byte[] bytes = WebRequest.get(SERVER_ICON_ENDPOINT.formatted(id), byte[].class); + return new CachedServerIcon(bytes); + } + + /** + * Gets the blocked status of a Java server from the API. + * + * @param id The id of the server to get the blocked status of. + * @return The server blocked status. + * @throws ErrorResponse If an error occurs. + */ + public static CachedServerBlockedStatus getServerBlockedStatus(String id) throws ErrorResponse { + return WebRequest.get(SERVER_BLOCKED_STATUS_ENDPOINT.formatted(id), CachedServerBlockedStatus.class); + } +} \ No newline at end of file diff --git a/src/main/java/xyz/mcutils/common/DateUtils.java b/src/main/java/xyz/mcutils/common/DateUtils.java new file mode 100644 index 0000000..d6d376b --- /dev/null +++ b/src/main/java/xyz/mcutils/common/DateUtils.java @@ -0,0 +1,22 @@ +package xyz.mcutils.common; + +import lombok.SneakyThrows; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +public class DateUtils { + private static final SimpleDateFormat FORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH); + + /** + * Converts a string to a date. + * + * @param date The date to convert + * @return The date + */ + @SneakyThrows + public static Date stringToDate(String date) { + return FORMATTER.parse(date); + } +} diff --git a/src/main/java/xyz/mcutils/common/WebRequest.java b/src/main/java/xyz/mcutils/common/WebRequest.java new file mode 100644 index 0000000..7896462 --- /dev/null +++ b/src/main/java/xyz/mcutils/common/WebRequest.java @@ -0,0 +1,58 @@ +package xyz.mcutils.common; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import lombok.experimental.UtilityClass; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestClient; +import xyz.mcutils.exception.ErrorResponse; + +@UtilityClass +public class WebRequest { + private static final Gson GSON = new GsonBuilder() + .setPrettyPrinting() + .create(); + + /** + * The web client. + */ + private static final RestClient CLIENT; + + static { + HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); + requestFactory.setConnectTimeout(2500); // 2.5 seconds + CLIENT = RestClient.builder() + .requestFactory(requestFactory) + .build(); + } + + /** + * Gets a response from the given URL. + * + * @param url the url + * @return the response + * @param the type of the response + */ + public static T get(String url, Class clazz) throws ErrorResponse { + try { + ResponseEntity responseEntity = CLIENT.get() + .uri(url) + .retrieve() + .toEntity(clazz); + + return responseEntity.getBody(); + } catch (HttpClientErrorException ex) { + JsonObject json = GSON.fromJson(ex.getResponseBodyAsString(), JsonObject.class); + throw new ErrorResponse( + HttpStatus.valueOf(ex.getStatusCode().value()), + json.get("code").getAsInt(), + json.get("message").getAsString(), + DateUtils.stringToDate(json.get("timestamp").getAsString()) + ); + } + } +} \ No newline at end of file diff --git a/src/main/java/xyz/mcutils/exception/ErrorResponse.java b/src/main/java/xyz/mcutils/exception/ErrorResponse.java new file mode 100644 index 0000000..76d7220 --- /dev/null +++ b/src/main/java/xyz/mcutils/exception/ErrorResponse.java @@ -0,0 +1,34 @@ +package xyz.mcutils.exception; + +import io.micrometer.common.lang.NonNull; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; +import org.springframework.http.HttpStatus; + +import java.util.Date; + +@Getter +@ToString @AllArgsConstructor +public class ErrorResponse extends RuntimeException { + /** + * 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; +} \ No newline at end of file diff --git a/src/main/java/xyz/mcutils/models/CachedResponse.java b/src/main/java/xyz/mcutils/models/CachedResponse.java new file mode 100644 index 0000000..7cc1acb --- /dev/null +++ b/src/main/java/xyz/mcutils/models/CachedResponse.java @@ -0,0 +1,58 @@ +package xyz.mcutils.models; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +public class CachedResponse { + + /** + * The cache information for this response. + */ + private Cache cache; + + @AllArgsConstructor + @Getter + @Setter + public static class Cache { + /** + * Whether this request is cached. + */ + private boolean cached; + + /** + * The unix timestamp of when this was cached. + */ + private long cachedTime; + + /** + * Create a new cache information object with the default values. + *

+ * The default values are: + *
+ *

    + *
  • cached: true
  • + *
  • cachedAt: {@link System#currentTimeMillis()}
  • + *
+ *
+ *

+ * + * @return the default cache information object + */ + public static Cache defaultCache() { + return new Cache(true, System.currentTimeMillis()); + } + + /** + * Sets if this request is cached. + * + * @param cached the new value of if this request is cached + */ + public void setCached(boolean cached) { + this.cached = cached; + if (!cached) { + cachedTime = -1; + } + } + } +} diff --git a/src/main/java/xyz/mcutils/models/dns/DNSRecord.java b/src/main/java/xyz/mcutils/models/dns/DNSRecord.java new file mode 100644 index 0000000..026c379 --- /dev/null +++ b/src/main/java/xyz/mcutils/models/dns/DNSRecord.java @@ -0,0 +1,29 @@ +package xyz.mcutils.models.dns; + +import io.micrometer.common.lang.NonNull; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Setter @Getter +@NoArgsConstructor @AllArgsConstructor +public class DNSRecord { + /** + * The type of this record. + */ + @NonNull + private Type type; + + /** + * The TTL (Time To Live) of this record. + */ + private long ttl; + + /** + * Types of a record. + */ + public enum Type { + A, SRV + } +} diff --git a/src/main/java/xyz/mcutils/models/dns/impl/ARecord.java b/src/main/java/xyz/mcutils/models/dns/impl/ARecord.java new file mode 100644 index 0000000..60dbcf9 --- /dev/null +++ b/src/main/java/xyz/mcutils/models/dns/impl/ARecord.java @@ -0,0 +1,15 @@ +package xyz.mcutils.models.dns.impl; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import xyz.mcutils.models.dns.DNSRecord; + +@Setter @Getter +@NoArgsConstructor +public final class ARecord extends DNSRecord { + /** + * The address of this record, null if unresolved. + */ + private String address; +} \ No newline at end of file diff --git a/src/main/java/xyz/mcutils/models/dns/impl/SRVRecord.java b/src/main/java/xyz/mcutils/models/dns/impl/SRVRecord.java new file mode 100644 index 0000000..1363d7e --- /dev/null +++ b/src/main/java/xyz/mcutils/models/dns/impl/SRVRecord.java @@ -0,0 +1,31 @@ +package xyz.mcutils.models.dns.impl; + +import io.micrometer.common.lang.NonNull; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import xyz.mcutils.models.dns.DNSRecord; + +@Setter @Getter +@NoArgsConstructor +public final class SRVRecord extends DNSRecord { + /** + * The priority of this record. + */ + private int priority; + + /** + * The weight of this record. + */ + private int weight; + + /** + * The port of this record. + */ + private int port; + + /** + * The target of this record. + */ + @NonNull private String target; +} \ No newline at end of file diff --git a/src/main/java/xyz/mcutils/models/mojang/CachedMojangEndpointStatus.java b/src/main/java/xyz/mcutils/models/mojang/CachedMojangEndpointStatus.java new file mode 100644 index 0000000..c7c5ef1 --- /dev/null +++ b/src/main/java/xyz/mcutils/models/mojang/CachedMojangEndpointStatus.java @@ -0,0 +1,35 @@ +package xyz.mcutils.models.mojang; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import xyz.mcutils.models.CachedResponse; + +import java.util.Map; + +@AllArgsConstructor +@Getter +public class CachedMojangEndpointStatus extends CachedResponse { + + /** + * The list of endpoints and their status. + */ + private Map endpoints; + + public enum Status { + /** + * The service is online and operational. + */ + ONLINE, + + /** + * The service is online, but may be experiencing issues. + * This could be due to high load or other issues. + */ + DEGRADED, + + /** + * The service is offline and not operational. + */ + OFFLINE + } +} \ No newline at end of file diff --git a/src/main/java/xyz/mcutils/models/player/CachedPlayer.java b/src/main/java/xyz/mcutils/models/player/CachedPlayer.java new file mode 100644 index 0000000..55329bf --- /dev/null +++ b/src/main/java/xyz/mcutils/models/player/CachedPlayer.java @@ -0,0 +1,62 @@ +package xyz.mcutils.models.player; + +import lombok.Getter; +import xyz.mcutils.models.CachedResponse; + +import java.util.UUID; + +@Getter +public class CachedPlayer extends CachedResponse { + + /** + * The UUID of the player + */ + private UUID uniqueId; + + /** + * The trimmed UUID of the player + */ + private String trimmedUniqueId; + + /** + * The username of the player + */ + private String username; + + /** + * The skin of the player, null if the + * player does not have a skin + */ + private Skin skin; + + /** + * The cape of the player, null if the + * player does not have a cape + */ + private Cape cape; + + /** + * The raw properties of the player + */ + private ProfileProperty[] rawProperties; + + /** + * A profile property for the player. + */ + private static class ProfileProperty { + /** + * The name of the property. + */ + private String name; + + /** + * The base64 value of the property. + */ + private String value; + + /** + * Whether the property is signed. + */ + private boolean signed; + } +} diff --git a/src/main/java/xyz/mcutils/models/player/CachedPlayerSkinPart.java b/src/main/java/xyz/mcutils/models/player/CachedPlayerSkinPart.java new file mode 100644 index 0000000..3a0ce2d --- /dev/null +++ b/src/main/java/xyz/mcutils/models/player/CachedPlayerSkinPart.java @@ -0,0 +1,12 @@ +package xyz.mcutils.models.player; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor @Getter +public class CachedPlayerSkinPart { + /** + * The bytes for the skin part + */ + private byte[] partBytes; +} diff --git a/src/main/java/xyz/mcutils/models/player/CachedUsernameToUuid.java b/src/main/java/xyz/mcutils/models/player/CachedUsernameToUuid.java new file mode 100644 index 0000000..ca08814 --- /dev/null +++ b/src/main/java/xyz/mcutils/models/player/CachedUsernameToUuid.java @@ -0,0 +1,19 @@ +package xyz.mcutils.models.player; + +import lombok.Getter; +import xyz.mcutils.models.CachedResponse; + +import java.util.UUID; + +@Getter +public class CachedUsernameToUuid extends CachedResponse { + /** + * The username of the player. + */ + private String username; + + /** + * The unique id of the player. + */ + private UUID uniqueId; +} diff --git a/src/main/java/xyz/mcutils/models/player/Cape.java b/src/main/java/xyz/mcutils/models/player/Cape.java new file mode 100644 index 0000000..bfafc7a --- /dev/null +++ b/src/main/java/xyz/mcutils/models/player/Cape.java @@ -0,0 +1,8 @@ +package xyz.mcutils.models.player; + +public class Cape { + /** + * The URL of the cape + */ + private String url; +} \ No newline at end of file diff --git a/src/main/java/xyz/mcutils/models/player/Skin.java b/src/main/java/xyz/mcutils/models/player/Skin.java new file mode 100644 index 0000000..e709c71 --- /dev/null +++ b/src/main/java/xyz/mcutils/models/player/Skin.java @@ -0,0 +1,51 @@ +package xyz.mcutils.models.player; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.HashMap; +import java.util.Map; + +public class Skin { + /** + * The URL for the skin + */ + private String url; + + /** + * The model for the skin + */ + private Model model; + + /** + * The legacy status of the skin + */ + private boolean legacy; + + /** + * The part URLs of the skin + */ + private Map parts = new HashMap<>(); + + /** + * The model of the skin. + */ + public enum Model { + DEFAULT, + SLIM + } + + @AllArgsConstructor + @Getter + public enum SkinPart { + HEAD("head"), + FACE("face"), + BODY("body"); + + /** + * The name of the skin part + */ + private final String name; + } + +} diff --git a/src/main/java/xyz/mcutils/models/server/CachedBedrockMinecraftServer.java b/src/main/java/xyz/mcutils/models/server/CachedBedrockMinecraftServer.java new file mode 100644 index 0000000..83c3c39 --- /dev/null +++ b/src/main/java/xyz/mcutils/models/server/CachedBedrockMinecraftServer.java @@ -0,0 +1,75 @@ +package xyz.mcutils.models.server; + +import lombok.Getter; +import lombok.ToString; + +@Getter +public class CachedBedrockMinecraftServer extends MinecraftServer { + /** + * The unique ID of this server. + */ + private String id; + + /** + * The edition of this server. + */ + private Edition edition; + + /** + * The version information of this server. + */ + private Version version; + + /** + * The gamemode of this server. + */ + private GameMode gamemode; + + /** + * The edition of a Bedrock server. + */ + @Getter + public enum Edition { + /** + * Minecraft: Pocket Edition. + */ + MCPE, + + /** + * Minecraft: Education Edition. + */ + MCEE + } + + /** + * Version information for a server. + */ + @Getter @ToString + public static class Version { + /** + * The protocol version of the server. + */ + private int protocol; + + /** + * The version name of the server. + */ + private String name; + } + + /** + * The gamemode of a server. + */ + @Getter @ToString + public static class GameMode { + /** + * The name of this gamemode. + */ + private String name; + + /** + * The numeric of this gamemode. + */ + private int numericId; + } +} diff --git a/src/main/java/xyz/mcutils/models/server/CachedJavaMinecraftServer.java b/src/main/java/xyz/mcutils/models/server/CachedJavaMinecraftServer.java new file mode 100644 index 0000000..4f3cda3 --- /dev/null +++ b/src/main/java/xyz/mcutils/models/server/CachedJavaMinecraftServer.java @@ -0,0 +1,181 @@ +package xyz.mcutils.models.server; + +import lombok.Getter; +import lombok.ToString; + +@Getter +public class CachedJavaMinecraftServer extends MinecraftServer { + + /** + * The version of the server. + */ + private Version version; + + /** + * The favicon of the server. + */ + private Favicon favicon; + + /** + * The mods running on this server. + */ + private ForgeModInfo modInfo; + + /** + * The mods running on this server. + *

+ * This is only used for servers + * running 1.13 and above. + *

+ */ + private ForgeData forgeData; + + /** + * Whether the server prevents chat reports. + */ + private boolean preventsChatReports; + + /** + * Whether the server enforces secure chat. + */ + private boolean enforcesSecureChat; + + /** + * Whether the server has previews chat enabled. + *

+ * Chat Preview sends chat messages to the server as they are typed, even before they're sent. + * More information + *

+ */ + private boolean previewsChat; + + /** + * The mojang blocked status for the server. + */ + private boolean mojangBlocked; + + @Getter + public static class Version { + /** + * The version name of the server. + */ + + private String name; + + /** + * The server platform. + */ + private String platform; + + /** + * The protocol version. + */ + private int protocol; + + /** + * The name of the protocol, null if not found. + */ + private String protocolName; + } + + @Getter + public static class Favicon { + + /** + * The raw base64 of the favicon. + */ + private String base64; + + /** + * The url to the favicon. + */ + private String url; + } + + /** + * Forge mod information for a server. + */ + @Getter @ToString + public static class ForgeModInfo { + /** + * The type of modded server this is. + */ + private String type; + + /** + * The list of mods on this server, null or empty if none. + */ + private ForgeMod[] modList; + + /** + * A forge mod for a server. + */ + @Getter @ToString + private static class ForgeMod { + /** + * The id of this mod. + */ + private String name; + + /** + * The version of this mod. + */ + private String version; + } + } + + @Getter + public static class ForgeData { + + /** + * The list of mod channels on this server, null or empty if none. + */ + private Channel[] channels; + + /** + * The list of mods on this server, null or empty if none. + */ + private Mod[] mods; + + /** + * Whether the mod list is truncated. + */ + private boolean truncated; + + /** + * The version of the FML network. + */ + private int fmlNetworkVersion; + + @Getter + public static class Channel { + /** + * The id of this mod channel. + */ + private String name; + + /** + * The version of this mod channel. + */ + private String version; + + /** + * Whether this mod channel is required to join. + */ + private boolean required; + } + + @Getter + public static class Mod { + /** + * The id of this mod. + */ + private String name; + + /** + * The version of this mod. + */ + private String version; + } + } +} \ No newline at end of file diff --git a/src/main/java/xyz/mcutils/models/server/CachedServerBlockedStatus.java b/src/main/java/xyz/mcutils/models/server/CachedServerBlockedStatus.java new file mode 100644 index 0000000..cb9be57 --- /dev/null +++ b/src/main/java/xyz/mcutils/models/server/CachedServerBlockedStatus.java @@ -0,0 +1,12 @@ +package xyz.mcutils.models.server; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor @Getter +public class CachedServerBlockedStatus { + /** + * Whether the server is Mojang blocked. + */ + private boolean blocked; +} diff --git a/src/main/java/xyz/mcutils/models/server/CachedServerIcon.java b/src/main/java/xyz/mcutils/models/server/CachedServerIcon.java new file mode 100644 index 0000000..73d6e35 --- /dev/null +++ b/src/main/java/xyz/mcutils/models/server/CachedServerIcon.java @@ -0,0 +1,12 @@ +package xyz.mcutils.models.server; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor @Getter +public class CachedServerIcon { + /** + * The bytes for the server icon. + */ + private byte[] bytes; +} diff --git a/src/main/java/xyz/mcutils/models/server/MinecraftServer.java b/src/main/java/xyz/mcutils/models/server/MinecraftServer.java new file mode 100644 index 0000000..b6d8ac6 --- /dev/null +++ b/src/main/java/xyz/mcutils/models/server/MinecraftServer.java @@ -0,0 +1,97 @@ +package xyz.mcutils.models.server; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; +import xyz.mcutils.models.dns.DNSRecord; + +import java.util.UUID; + +@Getter +public class MinecraftServer { + /** + * The hostname of the server. + */ + private String hostname; + + /** + * The IP address of the server. + */ + private String ip; + + /** + * The port of the server. + */ + private int port; + + /** + * The DNS records for the server. + */ + private DNSRecord[] records; + + /** + * The motd for the server. + */ + private MOTD motd; + + /** + * The players on the server. + */ + private Players players; + + @AllArgsConstructor @Getter + private static class MOTD { + + /** + * The raw motd lines + */ + private String[] raw; + + /** + * The clean motd lines + */ + private String[] clean; + + /** + * The html motd lines + */ + private String[] html; + } + + /** + * Player count data for a server. + */ + @Getter + private static class Players { + /** + * The online players on this server. + */ + private int online; + + /** + * The maximum allowed players on this server. + */ + private int max; + + /** + * A sample of players on this server, null or empty if no sample. + */ + private Sample[] sample; + + /** + * A sample player. + */ + @Getter @ToString + private static class Sample { + /** + * The unique id of this player. + */ + private UUID id; + + /** + * The name of this player. + */ + private String name; + } + } +} diff --git a/src/main/java/xyz/mcutils/models/server/ServerPlatform.java b/src/main/java/xyz/mcutils/models/server/ServerPlatform.java new file mode 100644 index 0000000..3d2d1d0 --- /dev/null +++ b/src/main/java/xyz/mcutils/models/server/ServerPlatform.java @@ -0,0 +1,20 @@ +package xyz.mcutils.models.server; + +import lombok.Getter; + +@Getter +public enum ServerPlatform { + /** + * The platform is Java Edition. + */ + JAVA, + /** + * The platform is Bedrock Edition. + */ + BEDROCK; + + /** + * The name of the platform. + */ + private final String name = name().toLowerCase(); +} diff --git a/src/test/java/xyz/mcutils/MojangTests.java b/src/test/java/xyz/mcutils/MojangTests.java new file mode 100644 index 0000000..d7d500e --- /dev/null +++ b/src/test/java/xyz/mcutils/MojangTests.java @@ -0,0 +1,15 @@ +package xyz.mcutils; + +import lombok.SneakyThrows; +import org.junit.jupiter.api.Test; +import xyz.mcutils.models.mojang.CachedMojangEndpointStatus; + +public class MojangTests { + + @Test + @SneakyThrows + public void ensureMojangApiStatusSuccess() { + CachedMojangEndpointStatus status = McUtilsAPI.getMojangApiStatus(); + assert !status.getEndpoints().isEmpty(); + } +} diff --git a/src/test/java/xyz/mcutils/PlayerTests.java b/src/test/java/xyz/mcutils/PlayerTests.java new file mode 100644 index 0000000..39ade31 --- /dev/null +++ b/src/test/java/xyz/mcutils/PlayerTests.java @@ -0,0 +1,77 @@ +package xyz.mcutils; + +import lombok.SneakyThrows; +import org.junit.jupiter.api.Test; +import xyz.mcutils.exception.ErrorResponse; +import xyz.mcutils.models.player.CachedPlayer; +import xyz.mcutils.models.player.CachedPlayerSkinPart; +import xyz.mcutils.models.player.CachedUsernameToUuid; +import xyz.mcutils.models.player.Skin; + +public class PlayerTests { + + private final String testPlayerUuid = "eeab5f8a-18dd-4d58-af78-2b3c4543da48"; + private final String testPlayer = "ImFascinated"; + private final String testInvalidPlayer = "invalidplayeromgyeswow"; + + @Test + @SneakyThrows + public void ensurePlayerLookupUuidSuccess() { + CachedPlayer player = McUtilsAPI.getPlayer(testPlayerUuid); + assert player.getUsername().equals(testPlayer); + } + + @Test + @SneakyThrows + public void ensurePlayerLookupUuidFailure() { + try { + McUtilsAPI.getPlayer(testInvalidPlayer); + } catch (ErrorResponse ex) { + assert ex.getCode() == 404; + } + } + + @Test + @SneakyThrows + public void ensurePlayerLookupUsernameSuccess() { + CachedPlayer player = McUtilsAPI.getPlayer(testPlayer); + assert player.getUsername().equals(testPlayer); + } + + @Test + @SneakyThrows + public void ensurePlayerLookupUsernameFailure() { + try { + McUtilsAPI.getPlayer(testInvalidPlayer); + } catch (ErrorResponse ex) { + assert ex.getCode() == 404; + } + } + + @Test + @SneakyThrows + public void ensurePlayerUsernameToUuidLookupSuccess() { + CachedUsernameToUuid player = McUtilsAPI.getUsernameToUuid(testPlayer); + assert player.getUsername().equals(testPlayer); + assert player.getUniqueId().toString().equals(testPlayerUuid); + } + + @Test + @SneakyThrows + public void ensurePlayerUsernameToUuidLookupFailure() { + try { + McUtilsAPI.getUsernameToUuid(testInvalidPlayer); + } catch (ErrorResponse ex) { + assert ex.getCode() == 404; + } + } + + @Test + @SneakyThrows + public void ensurePlayerSkinPartsLookupSuccess() { + for (Skin.SkinPart part : Skin.SkinPart.values()) { + CachedPlayerSkinPart partBytes = McUtilsAPI.getPlayerSkinPart(part, testPlayer); + assert partBytes.getPartBytes() != null; + } + } +} diff --git a/src/test/java/xyz/mcutils/ServerTests.java b/src/test/java/xyz/mcutils/ServerTests.java new file mode 100644 index 0000000..f53c1c2 --- /dev/null +++ b/src/test/java/xyz/mcutils/ServerTests.java @@ -0,0 +1,74 @@ +package xyz.mcutils; + +import lombok.SneakyThrows; +import org.junit.jupiter.api.Test; +import xyz.mcutils.exception.ErrorResponse; +import xyz.mcutils.models.server.CachedBedrockMinecraftServer; +import xyz.mcutils.models.server.CachedJavaMinecraftServer; +import xyz.mcutils.models.server.CachedServerBlockedStatus; +import xyz.mcutils.models.server.CachedServerIcon; + +public class ServerTests { + + private final String testJavaServer = "play.hypixel.net"; + private final String testBedrockServer = "geo.hivebedrock.network"; + private final String testInvalidServer = "invalidhostnamehahahahahayesslmaooo"; + + @Test + @SneakyThrows + public void ensureJavaServerLookupSuccess() { + CachedJavaMinecraftServer server = McUtilsAPI.getJavaServer(testJavaServer); + assert server.getHostname().equals(testJavaServer); + } + + @Test + @SneakyThrows + public void ensureJavaServerLookupFailure() { + try { + McUtilsAPI.getJavaServer(testInvalidServer); + } catch (ErrorResponse ex) { + assert ex.getCode() == 400; + } + } + + @Test + @SneakyThrows + public void ensureJavaServerIconLookupSuccess() { + CachedServerIcon icon = McUtilsAPI.getServerIcon(testJavaServer); + assert icon.getBytes() != null; + } + + @Test + @SneakyThrows + public void ensureJavaServerIconLookupFailure() { + try { + McUtilsAPI.getServerIcon(testInvalidServer); + } catch (ErrorResponse ex) { + assert ex.getCode() == 400; + } + } + + @Test + @SneakyThrows + public void ensureJavaServerBlockedLookupSuccess() { + CachedServerBlockedStatus status = McUtilsAPI.getServerBlockedStatus(testJavaServer); + assert !status.isBlocked(); + } + + @Test + @SneakyThrows + public void ensureBedrockServerLookupSuccess() { + CachedBedrockMinecraftServer server = McUtilsAPI.getBedrockServer(testBedrockServer); + assert server.getHostname().equals(testBedrockServer); + } + + @Test + @SneakyThrows + public void ensureBedrockServerLookupFailure() { + try { + McUtilsAPI.getBedrockServer(testInvalidServer); + } catch (ErrorResponse ex) { + assert ex.getCode() == 400; + } + } +}