package de.cowtipper.cowlection.data; import com.google.common.collect.ComparisonChain; import com.mojang.realmsclient.util.Pair; import com.mojang.util.UUIDTypeAdapter; import de.cowtipper.cowlection.config.MooConfig; import de.cowtipper.cowlection.util.Utils; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.EnumChatFormatting; import net.minecraftforge.common.util.Constants; import org.apache.commons.codec.binary.Base64; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.*; public class HySkyBlockStats { private boolean success; private String cause; private List profiles; /** * No-args constructor for GSON */ private HySkyBlockStats() { } public boolean isSuccess() { return success; } public String getCause() { return cause; } public Profile getActiveProfile(UUID uuid) { if (profiles == null) { return null; } Profile lastSavedProfile = null; long latestSave = -1; for (Profile profile : profiles) { long lastProfileSave = profile.getMember(uuid).last_save; if (latestSave < lastProfileSave) { lastSavedProfile = profile; latestSave = lastProfileSave; } } return lastSavedProfile; } public static class Profile { private String cute_name; private Map members; private Banking banking; /** * No-args constructor for GSON */ private Profile() { } public String getCuteName() { return cute_name; } public Member getMember(UUID uuid) { return members.get(UUIDTypeAdapter.fromUUID(uuid)); } public double getCoinBank() { return (banking != null) ? banking.balance : -1; } public int coopCount() { return members.size() - 1; } public double getCoopCoinPurses(UUID stalkedUuid) { double coopCoinPurses = 0; for (Map.Entry memberEntry : members.entrySet()) { if (memberEntry.getKey().equals(UUIDTypeAdapter.fromUUID(stalkedUuid))) { // don't include stalked player's purse again, only coops' purse continue; } coopCoinPurses += memberEntry.getValue().getCoinPurse(); } return coopCoinPurses; } public Pair getUniqueMinions() { int uniqueMinions = 0; int membersWithDisabledApi = 0; for (Member member : members.values()) { if (member.crafted_generators != null) { if (uniqueMinions > 0) { --uniqueMinions; // subtract duplicate COBBLESTONE_1 minion } uniqueMinions += member.crafted_generators.size(); } else { ++membersWithDisabledApi; } } return Pair.of(uniqueMinions, membersWithDisabledApi); } public static class Member { private long last_save; private long first_join; private double coin_purse; private NbtData inv_armor; private List crafted_generators; private int fairy_souls_collected = -1; private double experience_skill_farming = -1; private double experience_skill_mining = -1; private double experience_skill_combat = -1; private double experience_skill_foraging = -1; private double experience_skill_fishing = -1; private double experience_skill_enchanting = -1; private double experience_skill_alchemy = -1; private double experience_skill_carpentry = -1; private double experience_skill_runecrafting = -1; private double experience_skill_taming = -1; private Map slayer_bosses; private List pets; private Dungeons dungeons; /** * No-args constructor for GSON */ private Member() { } public Pair getFancyFirstJoined() { return Utils.getDurationAsWords(first_join); } public double getCoinPurse() { return coin_purse; } public int getFairySoulsCollected() { return fairy_souls_collected; } public Map getSkills() { Map skills = new TreeMap<>(); if (experience_skill_farming >= 0) { skills.put(XpTables.Skill.FARMING, XpTables.Skill.FARMING.getLevel(experience_skill_farming)); } if (experience_skill_mining >= 0) { skills.put(XpTables.Skill.MINING, XpTables.Skill.MINING.getLevel(experience_skill_mining)); } if (experience_skill_combat >= 0) { skills.put(XpTables.Skill.COMBAT, XpTables.Skill.COMBAT.getLevel(experience_skill_combat)); } if (experience_skill_foraging >= 0) { skills.put(XpTables.Skill.FORAGING, XpTables.Skill.FORAGING.getLevel(experience_skill_foraging)); } if (experience_skill_fishing >= 0) { skills.put(XpTables.Skill.FISHING, XpTables.Skill.FISHING.getLevel(experience_skill_fishing)); } if (experience_skill_enchanting >= 0) { skills.put(XpTables.Skill.ENCHANTING, XpTables.Skill.ENCHANTING.getLevel(experience_skill_enchanting)); } if (experience_skill_alchemy >= 0) { skills.put(XpTables.Skill.ALCHEMY, XpTables.Skill.ALCHEMY.getLevel(experience_skill_alchemy)); } if (experience_skill_carpentry >= 0) { skills.put(XpTables.Skill.CARPENTRY, XpTables.Skill.CARPENTRY.getLevel(experience_skill_carpentry)); } if (experience_skill_runecrafting >= 0) { skills.put(XpTables.Skill.RUNECRAFTING, XpTables.Skill.RUNECRAFTING.getLevel(experience_skill_runecrafting)); } if (experience_skill_taming >= 0) { skills.put(XpTables.Skill.TAMING, XpTables.Skill.TAMING.getLevel(experience_skill_taming)); } return skills; } public Map getSlayerLevels() { Map slayerLevels = new EnumMap<>(XpTables.Slayer.class); for (XpTables.Slayer slayerBoss : XpTables.Slayer.values()) { SlayerBossDetails bossDetails = slayer_bosses.get(slayerBoss.name().toLowerCase()); int slayerLevel = slayerBoss.getLevel(bossDetails.xp); slayerLevels.put(slayerBoss, slayerLevel); } return slayerLevels; } public Dungeons getDungeons() { return dungeons; } public List getPets() { pets.sort((p1, p2) -> ComparisonChain.start().compare(p2.active, p1.active).compare(p2.getRarity(), p1.getRarity()).compare(p2.exp, p1.exp).result()); return pets; } public List getArmor() { NBTTagCompound nbt = inv_armor.getDecodedData(); List armorList = new ArrayList<>(); if (nbt.hasKey("i", Constants.NBT.TAG_LIST)) { NBTTagList armor = nbt.getTagList("i", Constants.NBT.TAG_COMPOUND); for (int i = 0; i < armor.tagCount(); i++) { NBTTagCompound armorPiece = armor.getCompoundTagAt(i); NBTTagCompound nbtDisplay = armorPiece.getCompoundTag("tag").getCompoundTag("display"); if (nbtDisplay != null && nbtDisplay.hasKey("Name", Constants.NBT.TAG_STRING)) { String itemName = nbtDisplay.getString("Name"); armorList.add(0, itemName); } else { armorList.add(0, "" + EnumChatFormatting.GRAY + EnumChatFormatting.ITALIC + "(empty)"); } } } return armorList; } private static class NbtData { private int type; private String data; private NBTTagCompound getDecodedData() { try (ByteArrayInputStream bis = new ByteArrayInputStream(Base64.decodeBase64(this.data))) { return CompressedStreamTools.readCompressed(bis); } catch (IOException e) { e.printStackTrace(); return new NBTTagCompound(); } } } } private static class SlayerBossDetails { private int xp; } public static class Pet { private String type; private double exp; private String tier; private boolean active; public boolean isActive() { return active; } public DataHelper.SkyBlockRarity getRarity() { return DataHelper.SkyBlockRarity.valueOf(tier); } public String toFancyString() { return getRarity().getColor() + Utils.fancyCase(type) + " " + getLevel(); } private int getLevel() { return XpTables.Pet.getLevel(tier, exp); } } public static class Dungeons { private Map dungeon_types; private Map player_classes; private DataHelper.DungeonClass selected_dungeon_class; public Map getDungeonTypes() { return dungeon_types; } public Map getClassLevels() { Map classLevels = new TreeMap<>(); for (Map.Entry classEntry : player_classes.entrySet()) { classLevels.put(classEntry.getKey(), classEntry.getValue().getLevel()); } return classLevels; } public DataHelper.DungeonClass getSelectedClass() { return selected_dungeon_class; } public boolean hasPlayed() { if (dungeon_types != null) { for (Type dungeonType : dungeon_types.values()) { if (dungeonType != null && dungeonType.hasPlayed()) { return true; } } } return false; } public int getSelectedClassLevel() { return player_classes.get(selected_dungeon_class).getLevel(); } public StringBuilder getHighestFloorCompletions(int nHighestFloors, boolean indent) { StringBuilder output = new StringBuilder(); String spacer = indent ? "\n " : "\n"; Map latestDungeonType = Utils.getLastNMapEntries(dungeon_types, 1); for (Map.Entry dungeonTypeEntry : latestDungeonType.entrySet()) { if (!indent) { output.append(spacer); } if (dungeonTypeEntry != null) { Map highestFloorCompletions = Utils.getLastNMapEntries(dungeonTypeEntry.getValue().getTierCompletions(), nHighestFloors); String latestDungeonTypeName = Utils.fancyCase(dungeonTypeEntry.getKey()); if (highestFloorCompletions != null) { // top n highest floor completions: String highest = highestFloorCompletions.size() > 1 ? highestFloorCompletions.size() + " highest " : "Highest "; String pluralS = highestFloorCompletions.size() > 1 ? "s" : ""; output.append(spacer).append(EnumChatFormatting.BOLD).append(highest).append(latestDungeonTypeName).append(" floor").append(pluralS).append(":"); for (Map.Entry highestFloorEntry : highestFloorCompletions.entrySet()) { int highestFloorHighestScore = dungeonTypeEntry.getValue().getBestScore().get(highestFloorEntry.getKey()); output.append(spacer).append(EnumChatFormatting.GRAY).append(" Floor ").append(EnumChatFormatting.YELLOW).append(highestFloorEntry.getKey()).append(EnumChatFormatting.GRAY).append(": ") .append(EnumChatFormatting.GOLD).append(highestFloorEntry.getValue()).append(EnumChatFormatting.GRAY).append(" completions (best score: ").append(EnumChatFormatting.LIGHT_PURPLE).append(highestFloorHighestScore).append(EnumChatFormatting.GRAY).append(")"); } } else { // no floor completions yet output.append(spacer).append(EnumChatFormatting.ITALIC).append("No ").append(latestDungeonTypeName).append(" floor completions yet"); } } } return output; } public static class Type { private Map times_played; private Map tier_completions; private Map best_score; private int highest_tier_completed; private double experience; public Map getTimesPlayed() { return times_played; } public Map getTierCompletions() { return tier_completions; } public Map getBestScore() { return best_score; } public int getLevel() { return XpTables.Dungeoneering.DUNGEON.getLevel(experience); } public boolean hasPlayed() { return experience > 0; } /** * Level [lvl] ([amount]x Floor [highest]) * * @return summary text */ public String getSummary() { String floorCompletion; if (tier_completions != null) { int highestTierCompletions = tier_completions.get(String.valueOf(highest_tier_completed)); floorCompletion = "" + highestTierCompletions + EnumChatFormatting.GRAY + "x " + EnumChatFormatting.YELLOW + "Floor " + (MooConfig.useRomanNumerals() ? Utils.convertArabicToRoman(highest_tier_completed) : highest_tier_completed); } else { // played dungeons but never completed a floor floorCompletion = "not a single floor..."; } return "Level " + getLevel() + EnumChatFormatting.GRAY + " (beaten " + EnumChatFormatting.YELLOW + floorCompletion + EnumChatFormatting.GRAY + ")"; } } private static class ClassDetails { private double experience; public int getLevel() { return XpTables.Dungeoneering.CLASS.getLevel(experience); } } } public static class Banking { private double balance; // private List transactions; /** * No-args constructor for GSON */ private Banking() { } // private class Transaction { // private int amount; // private long timestamp; // private Transaction.Action action; // private String initiator_name; // // /** // * No-args constructor for GSON // */ // private Transaction() { // } // } } } }