From 0027466a564a9a6bebbdeed05192a616175ea6f3 Mon Sep 17 00:00:00 2001 From: Cow Date: Sun, 26 Jul 2020 23:41:58 +0200 Subject: Replaced 3rd party with official API --- .../eu/olli/cowlection/command/MooCommand.java | 38 ++++---- .../java/eu/olli/cowlection/data/DataHelper.java | 57 ++++++++++++ .../java/eu/olli/cowlection/data/HyPlayerData.java | 103 +++++++++++++++++++++ .../eu/olli/cowlection/data/HyStalkingData.java | 54 +---------- .../eu/olli/cowlection/data/SlothStalkingData.java | 52 ----------- .../java/eu/olli/cowlection/util/ApiUtils.java | 20 ++-- .../java/eu/olli/cowlection/util/GsonUtils.java | 20 +++- 7 files changed, 211 insertions(+), 133 deletions(-) create mode 100644 src/main/java/eu/olli/cowlection/data/HyPlayerData.java delete mode 100644 src/main/java/eu/olli/cowlection/data/SlothStalkingData.java (limited to 'src') diff --git a/src/main/java/eu/olli/cowlection/command/MooCommand.java b/src/main/java/eu/olli/cowlection/command/MooCommand.java index 16547af..e1c8a13 100644 --- a/src/main/java/eu/olli/cowlection/command/MooCommand.java +++ b/src/main/java/eu/olli/cowlection/command/MooCommand.java @@ -292,34 +292,34 @@ public class MooCommand extends CommandBase { + (session.getMode() != null ? ": " + EnumChatFormatting.GOLD + session.getMode() : "") + (session.getMap() != null ? EnumChatFormatting.YELLOW + " (Map: " + EnumChatFormatting.GOLD + session.getMap() + EnumChatFormatting.YELLOW + ")" : "")); } else { - ApiUtils.fetchPlayerOfflineStatus(stalkedPlayer, slothStalking -> { - if (slothStalking == null) { - throw new ApiContactException("Slothpixel", "couldn't stalk " + EnumChatFormatting.DARK_RED + stalkedPlayer.getName() + EnumChatFormatting.RED + " but they appear to be offline currently."); - } else if (slothStalking.hasNeverJoinedHypixel()) { + ApiUtils.fetchPlayerOfflineStatus(stalkedPlayer, hyPlayerData -> { + if (hyPlayerData == null) { + throw new ApiContactException("Hypixel", "couldn't stalk " + EnumChatFormatting.DARK_RED + stalkedPlayer.getName() + EnumChatFormatting.RED + " but they appear to be offline currently."); + } else if (hyPlayerData.hasNeverJoinedHypixel()) { main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, EnumChatFormatting.GOLD + stalkedPlayer.getName() + EnumChatFormatting.YELLOW + " has " + EnumChatFormatting.GOLD + "never " + EnumChatFormatting.YELLOW + "been on Hypixel (or might be nicked)."); - } else if (slothStalking.isHidingOnlineStatus()) { - main.getChatHelper().sendMessage(new ChatComponentText(slothStalking.getPlayerNameFormatted()).appendSibling(new ChatComponentText(" is hiding their online status from the Hypixel API. You can see their online status with ").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.YELLOW))) - .appendSibling(new ChatComponentText("/profile " + slothStalking.getPlayerName()).setChatStyle(new ChatStyle() + } else if (hyPlayerData.isHidingOnlineStatus()) { + main.getChatHelper().sendMessage(new ChatComponentText(hyPlayerData.getPlayerNameFormatted()).appendSibling(new ChatComponentText(" is hiding their online status from the Hypixel API. You can see their online status with ").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.YELLOW))) + .appendSibling(new ChatComponentText("/profile " + hyPlayerData.getPlayerName()).setChatStyle(new ChatStyle() .setColor(EnumChatFormatting.GOLD) - .setChatClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/profile " + slothStalking.getPlayerName())) - .setChatHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ChatComponentText(EnumChatFormatting.YELLOW + "Run " + EnumChatFormatting.GOLD + "/profile " + slothStalking.getPlayerName()))))) + .setChatClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/profile " + hyPlayerData.getPlayerName())) + .setChatHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ChatComponentText(EnumChatFormatting.YELLOW + "Run " + EnumChatFormatting.GOLD + "/profile " + hyPlayerData.getPlayerName()))))) .appendSibling(new ChatComponentText(" while you're in a lobby (tooltip of the player head on the top left).").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.YELLOW)))); - } else if (slothStalking.hasNeverLoggedOut()) { - Pair lastOnline = Utils.getDurationAsWords(slothStalking.getLastLogin()); + } else if (hyPlayerData.hasNeverLoggedOut()) { + Pair lastOnline = Utils.getDurationAsWords(hyPlayerData.getLastLogin()); - main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, slothStalking.getPlayerNameFormatted() + EnumChatFormatting.YELLOW + " was last online " + EnumChatFormatting.GOLD + lastOnline.first() + EnumChatFormatting.YELLOW + " ago" + main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, hyPlayerData.getPlayerNameFormatted() + EnumChatFormatting.YELLOW + " was last online " + EnumChatFormatting.GOLD + lastOnline.first() + EnumChatFormatting.YELLOW + " ago" + (lastOnline.second() != null ? " (" + EnumChatFormatting.GOLD + lastOnline.second() + EnumChatFormatting.YELLOW + ")" : "") + "."); - } else if (slothStalking.getLastLogin() > slothStalking.getLastLogout()) { + } else if (hyPlayerData.getLastLogin() > hyPlayerData.getLastLogout()) { // player is logged in but is hiding their session details from API (My Profile > API settings > Online Status) - main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, EnumChatFormatting.GOLD + slothStalking.getPlayerNameFormatted() + EnumChatFormatting.YELLOW + " is currently playing " + EnumChatFormatting.GOLD + slothStalking.getLastGame() + "\n" + EnumChatFormatting.DARK_GRAY + "(" + slothStalking.getPlayerName() + " hides their session details from the API so that only their current game mode is visible)"); + main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, EnumChatFormatting.GOLD + hyPlayerData.getPlayerNameFormatted() + EnumChatFormatting.YELLOW + " is currently playing " + EnumChatFormatting.GOLD + hyPlayerData.getLastGame() + "\n" + EnumChatFormatting.DARK_GRAY + "(" + hyPlayerData.getPlayerName() + " hides their session details from the API so that only their current game mode is visible)"); } else { - Pair lastOnline = Utils.getDurationAsWords(slothStalking.getLastLogout()); + Pair lastOnline = Utils.getDurationAsWords(hyPlayerData.getLastLogout()); - main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, slothStalking.getPlayerNameFormatted() + EnumChatFormatting.YELLOW + " is " + EnumChatFormatting.GOLD + "offline" + EnumChatFormatting.YELLOW + " for " + EnumChatFormatting.GOLD + lastOnline.first() + EnumChatFormatting.YELLOW - + ((lastOnline.second() != null || slothStalking.getLastGame() != null) ? (" (" + main.getChatHelper().sendMessage(EnumChatFormatting.YELLOW, hyPlayerData.getPlayerNameFormatted() + EnumChatFormatting.YELLOW + " is " + EnumChatFormatting.GOLD + "offline" + EnumChatFormatting.YELLOW + " for " + EnumChatFormatting.GOLD + lastOnline.first() + EnumChatFormatting.YELLOW + + ((lastOnline.second() != null || hyPlayerData.getLastGame() != null) ? (" (" + (lastOnline.second() != null ? EnumChatFormatting.GOLD + lastOnline.second() + EnumChatFormatting.YELLOW : "") // = last online date - + (lastOnline.second() != null && slothStalking.getLastGame() != null ? "; " : "") // = delimiter - + (slothStalking.getLastGame() != null ? "last played gamemode: " + EnumChatFormatting.GOLD + slothStalking.getLastGame() + EnumChatFormatting.YELLOW : "") // = last gamemode + + (lastOnline.second() != null && hyPlayerData.getLastGame() != null ? "; " : "") // = delimiter + + (hyPlayerData.getLastGame() != null ? "last played gamemode: " + EnumChatFormatting.GOLD + hyPlayerData.getLastGame() + EnumChatFormatting.YELLOW : "") // = last gamemode + ")") : "") + "."); } }); diff --git a/src/main/java/eu/olli/cowlection/data/DataHelper.java b/src/main/java/eu/olli/cowlection/data/DataHelper.java index 4fa2f35..d6167b0 100644 --- a/src/main/java/eu/olli/cowlection/data/DataHelper.java +++ b/src/main/java/eu/olli/cowlection/data/DataHelper.java @@ -1,5 +1,7 @@ package eu.olli.cowlection.data; +import eu.olli.cowlection.util.Utils; + import java.util.HashMap; import java.util.Map; @@ -7,6 +9,61 @@ public final class DataHelper { private DataHelper() { } + // TODO replace with api request: https://github.com/HypixelDev/PublicAPI/blob/master/Documentation/misc/GameType.md + public enum GameType { + QUAKECRAFT("Quakecraft"), + WALLS("Walls"), + PAINTBALL("Paintball"), + SURVIVAL_GAMES("Blitz Survival Games"), + TNTGAMES("The TNT Games"), + VAMPIREZ("VampireZ"), + WALLS3("Mega Walls"), + ARCADE("Arcade"), + ARENA("Arena Brawl"), + UHC("UHC Champions"), + MCGO("Cops and Crims"), + BATTLEGROUND("Warlords"), + SUPER_SMASH("Smash Heroes"), + GINGERBREAD("Turbo Kart Racers"), + HOUSING("Housing"), + SKYWARS("SkyWars"), + TRUE_COMBAT("Crazy Walls"), + SPEED_UHC("Speed UHC"), + SKYCLASH("SkyClash"), + LEGACY("Classic Games"), + PROTOTYPE("Prototype"), + BEDWARS("Bed Wars"), + MURDER_MYSTERY("Murder Mystery"), + BUILD_BATTLE("Build Battle"), + DUELS("Duels"), + SKYBLOCK("SkyBlock"), + PIT("Pit"); + + private final String cleanName; + + GameType(String cleanName) { + this.cleanName = cleanName; + } + + public static String getFancyName(String gameName) { + if (gameName == null) { + return null; + } + String cleanGameType; + try { + cleanGameType = valueOf(gameName).getCleanName(); + } catch (IllegalArgumentException e) { + // no matching game type found + cleanGameType = Utils.fancyCase(gameName); + } + return cleanGameType; + } + + public String getCleanName() { + return cleanName; + } + } + public static Map getMinions() { // key = skin id, value = minion type and tier Map minions = new HashMap<>(); diff --git a/src/main/java/eu/olli/cowlection/data/HyPlayerData.java b/src/main/java/eu/olli/cowlection/data/HyPlayerData.java new file mode 100644 index 0000000..06be1e9 --- /dev/null +++ b/src/main/java/eu/olli/cowlection/data/HyPlayerData.java @@ -0,0 +1,103 @@ +package eu.olli.cowlection.data; + +import net.minecraft.util.EnumChatFormatting; + +public class HyPlayerData { + private String displayname; + private String rank; + private String prefix; + private String newPackageRank; + private String rankPlusColor; + private String monthlyPackageRank; + private String monthlyRankColor; + private long lastLogin; + private long lastLogout; + private String mostRecentGameType; + + /** + * No-args constructor for GSON + */ + public HyPlayerData() { + } + + public String getPlayerName() { + return displayname; + } + + public String getPlayerNameFormatted() { + return getRankFormatted() + " " + displayname; + } + + public long getLastLogin() { + return lastLogin; + } + + public long getLastLogout() { + return lastLogout; + } + + public String getLastGame() { + return DataHelper.GameType.getFancyName(mostRecentGameType); + } + + public boolean hasNeverJoinedHypixel() { + // example player that has never joined Hypixel (as of April 2020): Joe + return rank == null && lastLogin == 0; + } + + public boolean hasNeverLoggedOut() { + // example player that has no logout value (as of April 2020): Pig (in general accounts that haven't logged in for a few years) + return lastLogin != 0 && lastLogout == 0; + } + + public boolean isHidingOnlineStatus() { + // example players: any higher ranked player (mods, admins, ...) + return lastLogin == 0 && lastLogout == 0; + } + + /** + * Player's Rank prefix: https://github.com/HypixelDev/PublicAPI/wiki/Common-Questions#how-do-i-get-a-players-rank-prefix + * + * @return formatted rank + */ + private String getRankFormatted() { + if (prefix != null) { + return prefix; + } + if (rank != null) { + switch (rank) { + case "HELPER": + return EnumChatFormatting.BLUE + "[HELPER]"; + case "MODERATOR": + return EnumChatFormatting.DARK_GREEN + "[MOD]"; + case "ADMIN": + return EnumChatFormatting.RED + "[ADMIN]"; + case "YOUTUBER": + return EnumChatFormatting.RED + "[" + EnumChatFormatting.WHITE + "YOUTUBER" + EnumChatFormatting.RED + "]"; + } + } + if (rankPlusColor == null) { + rankPlusColor = "RED"; + } + if (monthlyPackageRank != null && monthlyPackageRank.equals("SUPERSTAR")) { + // MVP++ + EnumChatFormatting rankPlusPlusColor = monthlyRankColor != null ? EnumChatFormatting.getValueByName(monthlyRankColor) : EnumChatFormatting.GOLD; + return rankPlusPlusColor + "[MVP" + EnumChatFormatting.getValueByName(rankPlusColor) + "++" + rankPlusPlusColor + "]"; + } + if (newPackageRank != null) { + switch (newPackageRank) { + case "VIP": + return EnumChatFormatting.GREEN + "[VIP]"; + case "VIP_PLUS": + return EnumChatFormatting.GREEN + "[VIP" + EnumChatFormatting.GOLD + "+" + EnumChatFormatting.GREEN + "]"; + case "MVP": + return EnumChatFormatting.AQUA + "[MVP]"; + case "MVP_PLUS": + return EnumChatFormatting.AQUA + "[MVP" + EnumChatFormatting.getValueByName(rankPlusColor) + "+" + EnumChatFormatting.AQUA + "]"; + default: + return EnumChatFormatting.GRAY.toString(); + } + } + return EnumChatFormatting.GRAY.toString(); + } +} diff --git a/src/main/java/eu/olli/cowlection/data/HyStalkingData.java b/src/main/java/eu/olli/cowlection/data/HyStalkingData.java index a592f2a..771a11d 100644 --- a/src/main/java/eu/olli/cowlection/data/HyStalkingData.java +++ b/src/main/java/eu/olli/cowlection/data/HyStalkingData.java @@ -43,14 +43,7 @@ public class HyStalkingData { } public String getGameType() { - String cleanGameType; - try { - cleanGameType = GameType.valueOf(gameType).getCleanName(); - } catch (IllegalArgumentException e) { - // no matching game type found - cleanGameType = Utils.fancyCase(gameType); - } - return cleanGameType; + return DataHelper.GameType.getFancyName(gameType); } public String getMode() { @@ -59,7 +52,7 @@ public class HyStalkingData { return null; } String gameType = getGameType(); - if (GameType.BEDWARS.cleanName.equals(gameType)) { + if (DataHelper.GameType.BEDWARS.getCleanName().equals(gameType)) { // BedWars related String playerMode; String specialMode; @@ -92,7 +85,7 @@ public class HyStalkingData { playerModeClean = playerMode; } return Utils.fancyCase(specialMode + playerModeClean); - } else if (GameType.SKYBLOCK.cleanName.equals(gameType)) { + } else if (DataHelper.GameType.SKYBLOCK.getCleanName().equals(gameType)) { // SkyBlock related switch (mode) { case "dynamic": @@ -123,46 +116,5 @@ public class HyStalkingData { public String getMap() { return map; } - - // TODO replace with api request: https://github.com/HypixelDev/PublicAPI/blob/master/Documentation/misc/GameType.md - public enum GameType { - QUAKECRAFT("Quakecraft"), - WALLS("Walls"), - PAINTBALL("Paintball"), - SURVIVAL_GAMES("Blitz Survival Games"), - TNTGAMES("The TNT Games"), - VAMPIREZ("VampireZ"), - WALLS3("Mega Walls"), - ARCADE("Arcade"), - ARENA("Arena Brawl"), - UHC("UHC Champions"), - MCGO("Cops and Crims"), - BATTLEGROUND("Warlords"), - SUPER_SMASH("Smash Heroes"), - GINGERBREAD("Turbo Kart Racers"), - HOUSING("Housing"), - SKYWARS("SkyWars"), - TRUE_COMBAT("Crazy Walls"), - SPEED_UHC("Speed UHC"), - SKYCLASH("SkyClash"), - LEGACY("Classic Games"), - PROTOTYPE("Prototype"), - BEDWARS("Bed Wars"), - MURDER_MYSTERY("Murder Mystery"), - BUILD_BATTLE("Build Battle"), - DUELS("Duels"), - SKYBLOCK("SkyBlock"), - PIT("Pit"); - - private final String cleanName; - - GameType(String cleanName) { - this.cleanName = cleanName; - } - - public String getCleanName() { - return cleanName; - } - } } } diff --git a/src/main/java/eu/olli/cowlection/data/SlothStalkingData.java b/src/main/java/eu/olli/cowlection/data/SlothStalkingData.java deleted file mode 100644 index 6c6085e..0000000 --- a/src/main/java/eu/olli/cowlection/data/SlothStalkingData.java +++ /dev/null @@ -1,52 +0,0 @@ -package eu.olli.cowlection.data; - -public class SlothStalkingData { - private String username; - private String rank; - private String rank_formatted; - // private boolean online; - private long last_login; - private long last_logout; - private String last_game; - - /** - * No-args constructor for GSON - */ - public SlothStalkingData() { - } - - public String getPlayerName() { - return username; - } - - public String getPlayerNameFormatted() { - return rank_formatted.replace('&', 'ยง') + " " + username; - } - - public long getLastLogin() { - return last_login; - } - - public long getLastLogout() { - return last_logout; - } - - public String getLastGame() { - return last_game; - } - - public boolean hasNeverJoinedHypixel() { - // example player that has never joined Hypixel (as of April 2020): Joe - return rank == null && last_login == 0; - } - - public boolean hasNeverLoggedOut() { - // example player that has no logout value (as of April 2020): Pig (in general accounts that haven't logged in for a few years) - return last_login != 0 && last_logout == 0; - } - - public boolean isHidingOnlineStatus() { - // example players: any higher ranked player (mods, admins, ...) - return last_login == 0 && last_logout == 0; - } -} diff --git a/src/main/java/eu/olli/cowlection/util/ApiUtils.java b/src/main/java/eu/olli/cowlection/util/ApiUtils.java index b0a4cce..f4f23ff 100644 --- a/src/main/java/eu/olli/cowlection/util/ApiUtils.java +++ b/src/main/java/eu/olli/cowlection/util/ApiUtils.java @@ -9,7 +9,7 @@ import eu.olli.cowlection.config.MooConfig; import eu.olli.cowlection.data.Friend; import eu.olli.cowlection.data.HySkyBlockStats; import eu.olli.cowlection.data.HyStalkingData; -import eu.olli.cowlection.data.SlothStalkingData; +import eu.olli.cowlection.data.HyPlayerData; import org.apache.http.HttpStatus; import java.io.BufferedReader; @@ -25,9 +25,9 @@ public class ApiUtils { public static final String UUID_NOT_FOUND = "UUID-NOT-FOUND"; private static final String NAME_TO_UUID_URL = "https://api.mojang.com/users/profiles/minecraft/"; private static final String UUID_TO_NAME_URL = "https://api.mojang.com/user/profiles/%s/names"; - private static final String STALKING_URL_OFFICIAL = "https://api.hypixel.net/status?key=%s&uuid=%s"; - private static final String SKYBLOCK_STATS_URL_OFFICIAL = "https://api.hypixel.net/skyblock/profiles?key=%s&uuid=%s"; - private static final String STALKING_URL_UNOFFICIAL = "https://api.slothpixel.me/api/players/%s"; + private static final String ONLINE_STATUS_URL = "https://api.hypixel.net/status?key=%s&uuid=%s"; + private static final String SKYBLOCK_STATS_URL = "https://api.hypixel.net/skyblock/profiles?key=%s&uuid=%s"; + private static final String PLAYER_URL = "https://api.hypixel.net/player?key=%s&uuid=%s"; private static final ExecutorService pool = Executors.newCachedThreadPool(); private ApiUtils() { @@ -75,7 +75,7 @@ public class ApiUtils { } private static HyStalkingData stalkPlayer(Friend friend) { - try (BufferedReader reader = makeApiCall(String.format(STALKING_URL_OFFICIAL, MooConfig.moo, UUIDTypeAdapter.fromUUID(friend.getUuid())))) { + try (BufferedReader reader = makeApiCall(String.format(ONLINE_STATUS_URL, MooConfig.moo, UUIDTypeAdapter.fromUUID(friend.getUuid())))) { if (reader != null) { return GsonUtils.fromJson(reader, HyStalkingData.class); } @@ -90,7 +90,7 @@ public class ApiUtils { } private static HySkyBlockStats stalkSkyBlockStats(Friend friend) { - try (BufferedReader reader = makeApiCall(String.format(SKYBLOCK_STATS_URL_OFFICIAL, MooConfig.moo, UUIDTypeAdapter.fromUUID(friend.getUuid())))) { + try (BufferedReader reader = makeApiCall(String.format(SKYBLOCK_STATS_URL, MooConfig.moo, UUIDTypeAdapter.fromUUID(friend.getUuid())))) { if (reader != null) { return GsonUtils.fromJson(reader, HySkyBlockStats.class); } @@ -100,14 +100,14 @@ public class ApiUtils { return null; } - public static void fetchPlayerOfflineStatus(Friend stalkedPlayer, ThrowingConsumer action) { + public static void fetchPlayerOfflineStatus(Friend stalkedPlayer, ThrowingConsumer action) { pool.execute(() -> action.accept(stalkOfflinePlayer(stalkedPlayer))); } - private static SlothStalkingData stalkOfflinePlayer(Friend stalkedPlayer) { - try (BufferedReader reader = makeApiCall(String.format(STALKING_URL_UNOFFICIAL, UUIDTypeAdapter.fromUUID(stalkedPlayer.getUuid())))) { + private static HyPlayerData stalkOfflinePlayer(Friend stalkedPlayer) { + try (BufferedReader reader = makeApiCall(String.format(PLAYER_URL, MooConfig.moo, UUIDTypeAdapter.fromUUID(stalkedPlayer.getUuid())))) { if (reader != null) { - return GsonUtils.fromJson(reader, SlothStalkingData.class); + return GsonUtils.fromJson(reader, HyPlayerData.class); } } catch (IOException e) { e.printStackTrace(); diff --git a/src/main/java/eu/olli/cowlection/util/GsonUtils.java b/src/main/java/eu/olli/cowlection/util/GsonUtils.java index e0f1a64..030f42e 100644 --- a/src/main/java/eu/olli/cowlection/util/GsonUtils.java +++ b/src/main/java/eu/olli/cowlection/util/GsonUtils.java @@ -2,6 +2,7 @@ package eu.olli.cowlection.util; import com.google.gson.*; import com.mojang.util.UUIDTypeAdapter; +import eu.olli.cowlection.data.HyPlayerData; import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; @@ -13,7 +14,7 @@ import java.lang.reflect.Type; import java.util.UUID; public final class GsonUtils { - private static final Gson gson = new GsonBuilder().registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).create(); + private static final Gson gson = new GsonBuilder().registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).registerTypeAdapter(HyPlayerData.class, new HyPlayerDataDeserializer()).create(); private static final Gson gsonPrettyPrinter = new GsonBuilder().registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).setPrettyPrinting().create(); private GsonUtils() { @@ -73,4 +74,21 @@ public final class GsonUtils { } return new JsonObject(); } + + public static class HyPlayerDataDeserializer implements JsonDeserializer { + @Override + public HyPlayerData deserialize(JsonElement json, Type type, JsonDeserializationContext jdc) throws JsonParseException { + if (!json.getAsJsonObject().get("success").getAsBoolean()) { + // status: failed + return null; + } + JsonElement player = json.getAsJsonObject().get("player"); + HyPlayerData hyPlayerData = gsonPrettyPrinter.fromJson(player, HyPlayerData.class); + if (hyPlayerData == null) { + // player hasn't played Hypixel before + return new HyPlayerData(); + } + return hyPlayerData; + } + } } -- cgit