diff options
Diffstat (limited to 'src')
27 files changed, 1082 insertions, 1662 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/util/render/RenderUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/core/util/render/RenderUtils.java index b3a84c52..5f501115 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/core/util/render/RenderUtils.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/core/util/render/RenderUtils.java @@ -311,27 +311,29 @@ public class RenderUtils { public static void renderBoundingBox( BlockPos worldPos, int rgb, - float partialTicks + float partialTicks, + boolean disableDepth ) { Vector3f interpolatedPlayerPosition = getInterpolatedPlayerPosition(partialTicks); renderBoundingBoxInViewSpace( worldPos.getX() - interpolatedPlayerPosition.x, worldPos.getY() - interpolatedPlayerPosition.y, worldPos.getZ() - interpolatedPlayerPosition.z, - rgb + rgb, + disableDepth ); } - private static void renderBoundingBoxInViewSpace(double x, double y, double z, int rgb) { + private static void renderBoundingBoxInViewSpace(double x, double y, double z, int rgb, boolean disableDepth) { AxisAlignedBB bb = new AxisAlignedBB(x, y, z, x + 1, y + 1, z + 1); - GlStateManager.disableDepth(); + if (disableDepth) GlStateManager.disableDepth(); GlStateManager.disableCull(); GlStateManager.disableTexture2D(); CustomItemEffects.drawFilledBoundingBox(bb, 1f, SpecialColour.special(0, (rgb >> 24) & 0xFF, rgb)); GlStateManager.enableTexture2D(); GlStateManager.enableCull(); - GlStateManager.enableDepth(); + if (disableDepth) GlStateManager.enableDepth(); } public static void renderBeaconBeam(BlockPos block, int rgb, float alphaMult, float partialTicks) { @@ -395,7 +397,7 @@ public class RenderUtils { if (distSq > 10 * 10) { RenderUtils.renderBeaconBeam(x, y, z, rgb, 1.0f, partialTicks, true); } else { - RenderUtils.renderBoundingBoxInViewSpace(x, y, z, rgb); + RenderUtils.renderBoundingBoxInViewSpace(x, y, z, rgb, true); } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/NEUEventListener.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/NEUEventListener.java index 4a5df63f..0b4e3934 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/listener/NEUEventListener.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/NEUEventListener.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 NotEnoughUpdates contributors + * Copyright (C) 2022-2023 NotEnoughUpdates contributors * * This file is part of NotEnoughUpdates. * @@ -45,6 +45,7 @@ import io.github.moulberry.notenoughupdates.util.Constants; import io.github.moulberry.notenoughupdates.util.NotificationHandler; import io.github.moulberry.notenoughupdates.util.ProfileApiSyncer; import io.github.moulberry.notenoughupdates.util.SBInfo; +import io.github.moulberry.notenoughupdates.util.TabSkillInfoParser; import io.github.moulberry.notenoughupdates.util.Utils; import io.github.moulberry.notenoughupdates.util.XPInformation; import net.minecraft.client.Minecraft; @@ -171,8 +172,7 @@ public class NEUEventListener { CrystalOverlay.tick(); FairySouls.getInstance().tick(); - XPInformation.getInstance().tick(); - ProfileApiSyncer.getInstance().tick(); + TabSkillInfoParser.parseSkillInfo(); ItemCustomizeManager.tick(); BackgroundBlur.markDirty(); NPCRetexturing.getInstance().tick(); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PetInfoOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PetInfoOverlay.java index 016c17f0..726856cb 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PetInfoOverlay.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PetInfoOverlay.java @@ -22,8 +22,6 @@ package io.github.moulberry.notenoughupdates.miscfeatures; import com.google.common.collect.Lists; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -36,11 +34,8 @@ import io.github.moulberry.notenoughupdates.listener.RenderListener; import io.github.moulberry.notenoughupdates.options.NEUConfig; import io.github.moulberry.notenoughupdates.overlays.TextOverlay; import io.github.moulberry.notenoughupdates.overlays.TextOverlayStyle; -import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer; -import io.github.moulberry.notenoughupdates.profileviewer.SkyblockProfiles; import io.github.moulberry.notenoughupdates.util.Constants; import io.github.moulberry.notenoughupdates.util.PetLeveling; -import io.github.moulberry.notenoughupdates.util.ProfileApiSyncer; import io.github.moulberry.notenoughupdates.util.Utils; import io.github.moulberry.notenoughupdates.util.XPInformation; import net.minecraft.client.Minecraft; @@ -54,7 +49,6 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ChatComponentText; import net.minecraft.util.EnumChatFormatting; import net.minecraftforge.client.event.ClientChatReceivedEvent; -import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; @@ -156,6 +150,10 @@ public class PetInfoOverlay extends TextOverlay { private static long lastPetSelect = -1; private static PetConfig config = new PetConfig(); + public static PetConfig getConfig() { + return config; + } + private static long lastUpdate = 0; private static float levelXpLast = 0; @@ -281,110 +279,6 @@ public class PetInfoOverlay extends TextOverlay { } } - private static void getAndSetPet(SkyblockProfiles profile) { - Map<String, ProfileViewer.Level> skyblockInfo = profile.getLatestProfile().getLevelingInfo(); - Map<String, JsonArray> invInfo = profile.getLatestProfile().getInventoryInfo(); - JsonObject profileInfo = profile.getLatestProfile().getProfileJson(); - if (invInfo != null && profileInfo != null) { - JsonObject stats = profileInfo.get("stats").getAsJsonObject(); - boolean hasBeastmasterCrest = false; - Rarity currentBeastRarity = Rarity.COMMON; - for (JsonElement talisman : invInfo.get("talisman_bag")) { - if (talisman.isJsonNull()) continue; - String internalName = talisman.getAsJsonObject().get("internalname").getAsString(); - if (internalName.startsWith("BEASTMASTER_CREST")) { - hasBeastmasterCrest = true; - try { - Rarity talismanRarity = Rarity.valueOf(internalName.replace("BEASTMASTER_CREST_", "")); - if (talismanRarity.beastcreatMultiplyer > currentBeastRarity.beastcreatMultiplyer) - currentBeastRarity = talismanRarity; - } catch (Exception ignored) { - } - } - } - if (hasBeastmasterCrest) { - if (stats.has("mythos_kills")) { - int mk = stats.get("mythos_kills").getAsInt(); - float petXpBoost = mk > 10000 ? 1f : mk > 7500 ? 0.9f : mk > 5000 ? 0.8f : mk > 2500 ? 0.7f : - mk > 1000 - ? 0.6f - : mk > 500 - ? 0.5f - : mk > 250 - ? 0.4f - : mk > 100 - ? 0.3f - : mk > 25 ? 0.2f : 0.1f; - config.beastMultiplier = petXpBoost * currentBeastRarity.beastcreatMultiplyer; - } else { - config.beastMultiplier = 0.1f * currentBeastRarity.beastcreatMultiplyer; - } - } - } - if (skyblockInfo != null && profile.getLatestProfile().skillsApiEnabled()) { - config.tamingLevel = (int) skyblockInfo.get("taming").level; - } - - //JsonObject petObject = profile.getPetsInfo(profile.getLatestProfile()); - /*JsonObject petsJson = Constants.PETS; - if(petsJson != null) { - if(petObject != null) { - boolean forceUpdateLevels = System.currentTimeMillis() - lastXpGain > 30000; - Set<String> foundPets = new HashSet<>(); - Set<Pet> addedPets = new HashSet<>(); - for(int i = 0; i < petObject.getAsJsonArray("pets").size(); i++) { - JsonElement petElement = petObject.getAsJsonArray("pets").get(i); - JsonObject petObj = petElement.getAsJsonObject(); - Pet pet = new Pet(); - pet.petType = petObj.get("type").getAsString(); - Rarity rarity; - try { - rarity = Rarity.valueOf(petObj.get("tier").getAsString()); - } catch(Exception ignored) { - rarity = Rarity.COMMON; - } - pet.rarity = rarity; - pet.petLevel = GuiProfileViewer.getPetLevel(petsJson.get("pet_levels").getAsJsonArray(), rarity.petOffset, petObj.get("exp").getAsFloat()); - JsonElement heldItem = petObj.get("heldItem"); - pet.petItem = heldItem.isJsonNull() ? null : heldItem.getAsString(); - if(rarity != Rarity.MYTHIC && pet.petItem != null && pet.petItem.equals("PET_ITEM_TIER_BOOST")) { - rarity = Rarity.values()[rarity.ordinal()+1]; - } - JsonObject petTypes = petsJson.get("pet_types").getAsJsonObject(); - pet.petXpType = petTypes.has(pet.petType) ? petTypes.get(pet.petType.toUpperCase()).getAsString().toLowerCase() : "unknown"; - - Pet closest = null; - if(petList.containsKey(pet.petType + ";" + pet.rarity.petId)) { - closest = getClosestPet(pet); - if(addedPets.contains(closest)) { - closest = null; - } - - if(closest != null) { - if(!forceUpdateLevels || Math.floor(pet.petLevel.level) < Math.floor(closest.petLevel.level)) { - pet.petLevel = closest.petLevel; - } - petList.get(pet.petType + ";" + pet.rarity.petId).remove(closest); - } - } - foundPets.add(pet.petType + ";" + pet.rarity.petId); - petList.computeIfAbsent(pet.petType + ";" + pet.rarity.petId, k->new HashSet<>()).add(pet); - addedPets.add(pet); - - if(petObj.get("active").getAsBoolean()) { - if(currentPet == null && !setActivePet) { - currentPet = pet; - } else if(closest == currentPet) { - currentPet = pet; - } - } - } - petList.keySet().retainAll(foundPets); - setActivePet = true; - } - }*/ - } - private float interp(float now, float last) { float interp = now; if (last >= 0 && last != now) { @@ -659,12 +553,6 @@ public class PetInfoOverlay extends TextOverlay { return; } - int updateTime = 60000; - - if (NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) { - ProfileApiSyncer.getInstance().requestResync("petinfo", updateTime, () -> {}, PetInfoOverlay::getAndSetPet); - } - Pet currentPet = getCurrentPet(); if (currentPet == null) { overlayStrings = null; @@ -1097,13 +985,6 @@ public class PetInfoOverlay extends TextOverlay { } } - @SubscribeEvent - public void switchWorld(WorldEvent.Load event) { - if (NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) { - ProfileApiSyncer.getInstance().requestResync("petinfo_quick", 10000, () -> {}, PetInfoOverlay::getAndSetPet); - } - } - private int lastLevelHovered = 0; private static final Pattern AUTOPET_EQUIP = Pattern.compile( diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/world/CrystalHollowChestHighlighter.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/world/CrystalHollowChestHighlighter.java new file mode 100644 index 00000000..61c96aad --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/world/CrystalHollowChestHighlighter.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2023 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * NotEnoughUpdates is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.miscfeatures.world; + +import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe; +import io.github.moulberry.notenoughupdates.core.util.render.RenderUtils; +import io.github.moulberry.notenoughupdates.util.SBInfo; +import io.github.moulberry.notenoughupdates.util.SpecialColour; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.init.Blocks; +import net.minecraft.network.play.server.S22PacketMultiBlockChange; +import net.minecraft.network.play.server.S23PacketBlockChange; +import net.minecraft.util.BlockPos; +import net.minecraft.util.Vec3; +import net.minecraft.world.World; +import net.minecraftforge.client.event.RenderWorldLastEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +@NEUAutoSubscribe +public class CrystalHollowChestHighlighter extends GenericBlockHighlighter { + + // Because ConcurrentModificationException is the bane of me + public static CopyOnWriteArrayList<BlockPos> markedBlocks = new CopyOnWriteArrayList<>(); + + public static void processBlockChangePacket(S23PacketBlockChange packetIn) { + BlockPos pos = packetIn.getBlockPosition(); + if (packetIn.blockState == null) return; + checkForChest(pos, packetIn.blockState); + } + + public static void processMultiBlockChangePacket(S22PacketMultiBlockChange packetIn) { + for (S22PacketMultiBlockChange.BlockUpdateData blockChanged : packetIn.getChangedBlocks()) { + BlockPos pos = blockChanged.getPos(); + checkForChest(pos, blockChanged.getBlockState()); + } + } + + public static void checkForChest(BlockPos pos, IBlockState blockState) { + IBlockState oldState = Minecraft.getMinecraft().theWorld.getBlockState(pos); + + if ((oldState.getBlock() == Blocks.air || oldState.getBlock() == Blocks.stone) && + blockState.getBlock() == Blocks.chest) { + + // Only add if in a 10x10x10 area. Minimises other players' chests being caught + if (Minecraft.getMinecraft().thePlayer.getEntityBoundingBox().expand(10, 10, 10).isVecInside(new Vec3(pos))) { + markedBlocks.add(pos); + } + } + } + + @SubscribeEvent + public void onTick(TickEvent.ClientTickEvent event) { + if (!isEnabled()) return; + + markedBlocks.forEach(this::tryRegisterInterest); + + // Here to catch chests that get highlighted by other people after they open them, and + // any highlighted blocks in which the chest despawned in + List<BlockPos> blockToRemove = new ArrayList<>(); + highlightedBlocks.forEach(it -> { + if (Minecraft.getMinecraft().theWorld.getBlockState(it).getBlock() != Blocks.chest) { + blockToRemove.add(it); + } + }); + + blockToRemove.forEach(highlightedBlocks::remove); + } + + @SubscribeEvent + public void onBlockInteraction(PlayerInteractEvent event) { + if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) { + markedBlocks.remove(event.pos); + highlightedBlocks.remove(event.pos); + } + } + + @Override + public void onWorldRenderLast(RenderWorldLastEvent event) { + if (!isEnabled()) return; + World w = Minecraft.getMinecraft().theWorld; + if (w == null) return; + for (BlockPos blockPos : highlightedBlocks) { + RenderUtils.renderBoundingBox(blockPos, getColor(blockPos), event.partialTicks, false); + } + } + + @Override + protected boolean isEnabled() { + return "crystal_hollows".equals(SBInfo.getInstance().getLocation()) && + NotEnoughUpdates.INSTANCE.config.world.highlightCrystalHollowChests; + } + + @Override + protected boolean isValidHighlightSpot(BlockPos key) { + World w = Minecraft.getMinecraft().theWorld; + if (w == null) return false; + Block b = w.getBlockState(key).getBlock(); + return b == Blocks.chest; + } + + @Override + protected int getColor(BlockPos blockPos) { + return SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.config.world.crystalHollowChestColor); + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/world/GenericBlockHighlighter.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/world/GenericBlockHighlighter.java index 67d6f46e..5cacff2b 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/world/GenericBlockHighlighter.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/world/GenericBlockHighlighter.java @@ -49,7 +49,7 @@ public abstract class GenericBlockHighlighter { World w = Minecraft.getMinecraft().theWorld; if (w == null) return; for (BlockPos blockPos : highlightedBlocks) { - RenderUtils.renderBoundingBox(blockPos, getColor(blockPos), event.partialTicks); + RenderUtils.renderBoundingBox(blockPos, getColor(blockPos), event.partialTicks, true); } } @@ -110,6 +110,10 @@ public abstract class GenericBlockHighlighter { highlightedBlocks.clear(); } + public boolean tryRegisterInterest(BlockPos pos) { + return tryRegisterInterest(pos.getX(), pos.getY(), pos.getZ()); + } + public boolean tryRegisterInterest(double x, double y, double z) { BlockPos blockPos = new BlockPos(x, y, z); boolean contains = highlightedBlocks.contains(blockPos); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/CalendarOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/CalendarOverlay.java index 61c5915d..c83b310c 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/CalendarOverlay.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/CalendarOverlay.java @@ -26,7 +26,9 @@ import com.google.gson.JsonPrimitive; import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe; import io.github.moulberry.notenoughupdates.core.BackgroundBlur; +import io.github.moulberry.notenoughupdates.events.RepositoryReloadEvent; import io.github.moulberry.notenoughupdates.util.ItemUtils; +import io.github.moulberry.notenoughupdates.util.JsonUtils; import io.github.moulberry.notenoughupdates.util.SkyBlockTime; import io.github.moulberry.notenoughupdates.util.Utils; import kotlin.Pair; @@ -53,6 +55,7 @@ import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; +import org.jetbrains.annotations.NotNull; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import org.lwjgl.opengl.GL11; @@ -63,13 +66,12 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.TreeMap; -import java.util.concurrent.TimeUnit; +import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -87,6 +89,11 @@ public class CalendarOverlay { private static boolean enabled = false; public static boolean ableToClickCalendar = true; + long thunderStormEpoch = 1692826500000L; + long rainInterval = 3600000L; + long thunderFrequency = 3; + long rainDuration = 1200 * 1000L; + List<Pair<Long, SBEvent>> externalEvents = new ArrayList<>(); public static void setEnabled(boolean enabled) { CalendarOverlay.enabled = enabled; @@ -127,6 +134,11 @@ public class CalendarOverlay { private static final ItemStack DA_STACK; // Dark Auction private static final ItemStack JF_STACK; // Jacob's Farming Contest + private static final ItemStack STAR_CULT_STACK = Utils.createItemStack( + Items.nether_star, + "Cult of the Fallen Star", + "NEU Calendar Item" + ); // Star Cult Stack static { NBTTagCompound tag = new NBTTagCompound(); @@ -209,7 +221,7 @@ public class CalendarOverlay { } public Set<SBEvent> getEventsAt(long timestamp) { - return eventMap.computeIfAbsent(timestamp, k -> new HashSet<>()); + return eventMap.computeIfAbsent(timestamp, k -> new TreeSet<>()); } JsonObject getFarmingEventTypes() { @@ -256,30 +268,70 @@ public class CalendarOverlay { } public void populateDefaultEvents() { - if (eventMap.isEmpty() || eventMap.size() <= 20) { + if (eventMap.size() <= 20) { fillRepeatingEvents(25 - eventMap.size()); fillSpecialMayors(4); fillWeather(); + fillRepoMandatedEvents(); + fillStarCult(); + } + } + + public void fillRepoMandatedEvents() { + for (Pair<Long, SBEvent> externalEvent : externalEvents) { + addEvent( + SkyBlockTime.Companion.fromInstant(Instant.ofEpochMilli(externalEvent.component1())), + externalEvent.component2() + ); + } + } + + public void fillStarCult() { + SkyBlockTime now = SkyBlockTime.now(); + + long STAR_CULT_DURATION = 60 * 1000L * 6; + List<SkyBlockTime> allTimes = new ArrayList<>(); + allTimes.add(new SkyBlockTime(now.getYear() - 1, 12, 28, 0, 0, 0)); + for (int i = 1; i <= 12; i++) { + for (int d = 7; d < 30; d += 7) { + allTimes.add(new SkyBlockTime(now.getYear(), i, d, 0, 0, 0)); + } + } + for (SkyBlockTime allTime : allTimes) { + addEvent( + allTime, + new SBEvent( + "starcult", + "§3Cult of the Fallen Star", + false, + STAR_CULT_STACK, + Arrays.asList( + "§3The Cult of the Fallen Star meets then.", + "§3Attending may give a reward", + "§3You can find them near the Star in the Dwarven Mines" + ), + STAR_CULT_DURATION, + true + ) + ); } } private void fillWeather() { - long rainInterval = 4850 * 1000L; - long rainingTime = 1000 * 1000L; - long thunderStormEpoch = 1668551956000L - rainingTime; + long currentTime = System.currentTimeMillis(); - long timeSinceLastThunderStart = (currentTime - thunderStormEpoch) % (rainInterval * 4); + long timeSinceLastThunderStart = (currentTime - thunderStormEpoch) % (rainInterval * thunderFrequency); long lastThunderStart = currentTime - timeSinceLastThunderStart; for (int i = 0; i < 11; i++) { long eventTimer = lastThunderStart + rainInterval * i; - if (i % 4 == 0) { + if (i % thunderFrequency == 0) { addEvent(SkyBlockTime.Companion.fromInstant(Instant.ofEpochMilli(eventTimer)), new SBEvent( "spiders_den_thunder", "§9Spider's Den Thunder", true, new ItemStack(Blocks.slime_block), Arrays.asList("§aIt will rain in the Spider's Den", "§aand Toxic Rain Slimes will spawn"), - rainingTime, + rainDuration, true )); } else { @@ -291,7 +343,7 @@ public class CalendarOverlay { false, new ItemStack(Items.slime_ball), Arrays.asList("§aIt will rain in the Spider's Den", "§aand Rain Slimes will spawn"), - rainingTime, + rainDuration, true ) ); @@ -301,6 +353,49 @@ public class CalendarOverlay { } @SubscribeEvent + public void tick(RepositoryReloadEvent event) { + JsonObject calendarJson = NotEnoughUpdates.INSTANCE.manager.getJsonFromFile(new File( + event.getRepositoryRoot(), + "constants/calendar.json" + )); + if (calendarJson == null) return; + if (calendarJson.has("thunderEpochStart")) { + thunderStormEpoch = calendarJson.get("thunderEpochStart").getAsLong(); + } + if (calendarJson.has("rainInterval")) { + rainInterval = calendarJson.get("rainInterval").getAsLong(); + } + if (calendarJson.has("thunderFrequency")) { + thunderFrequency = calendarJson.get("thunderFrequency").getAsLong(); + } + if (calendarJson.has("rainDuration")) { + rainDuration = calendarJson.get("rainDuration").getAsLong(); + } + if (calendarJson.has("external")) { + List<Pair<Long, SBEvent>> externalEvents = new ArrayList<>(); + for (JsonElement external : calendarJson.getAsJsonArray("external")) { + if (!(external instanceof JsonObject)) continue; + SBEvent sbEvent = new SBEvent( + Utils.getElementAsString(Utils.getElement(external, "id"), "external"), + Utils.getElementAsString(Utils.getElement(external, "display"), "§aExternal Event"), + Utils.getElementAsBool(Utils.getElement(external, "special"), false), + NotEnoughUpdates.INSTANCE.manager.createItem(Utils.getElementAsString(Utils.getElement( + external, + "itemStack" + ), "painting")), + JsonUtils.getJsonArrayOrEmpty((JsonObject) external, "description", it -> Utils.getElementAsString(it, "")), + Utils.getElementAsInt(Utils.getElement(external, "duration"), -1), + true + ); + long start = Utils.getElementAsLong(Utils.getElement(external, "start"), 0); + externalEvents.add(new Pair<>(start, sbEvent)); + } + this.externalEvents = externalEvents; + } + eventMap.clear(); + } + + @SubscribeEvent public void tick(TickEvent.ClientTickEvent event) { if (event.phase != TickEvent.Phase.START) return; handleJinglePlayer(); @@ -338,7 +433,7 @@ public class CalendarOverlay { } public void addEvent(SkyBlockTime time, SBEvent event) { - if (time.toInstant().isBefore(Instant.now())&& + if (time.toInstant().isBefore(Instant.now()) && time.toInstant().plus(event.lastsFor, ChronoUnit.MILLIS).isBefore(Instant.now())) return; getEventsAt(time.toMillis()).add(event); } @@ -1316,7 +1411,6 @@ public class CalendarOverlay { } } - if (nextEvent != null) { GlStateManager.translate(0, 0, 50); boolean toastRendered = renderToast(nextEvent, timeUntilNext); @@ -1449,7 +1543,7 @@ public class CalendarOverlay { GlStateManager.color(1, 1, 1, 1); } - private static class SBEvent { + private static class SBEvent implements Comparable<SBEvent> { String id; String display; ItemStack stack; @@ -1491,6 +1585,18 @@ public class CalendarOverlay { } return stack; } + + @Override + public int compareTo(@NotNull CalendarOverlay.SBEvent o) { + int i; + if ((i = id.compareTo(o.id)) != 0) return i; + if ((i = display.compareTo(o.display)) != 0) return i; + if ((i = Long.compare(lastsFor, o.lastsFor)) != 0) return i; + if ((i = Boolean.compare(isSpecial, o.isSpecial)) != 0) return i; + if ((i = Boolean.compare(isArtificial, o.isArtificial)) != 0) return i; + + return 0; + } } private String prettyTime(long millis, boolean trimmed) { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/StorageOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/StorageOverlay.java index 4a478d1f..13cafd98 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/StorageOverlay.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/StorageOverlay.java @@ -2131,6 +2131,7 @@ public class StorageOverlay extends GuiElement { for (Slot slot : container.inventorySlots.inventorySlots) { if (slot != null && ((AccessorGuiContainer) container).doIsMouseOverSlot(slot, mouseX, mouseY)) { String internalName = manager.createItemResolutionQuery().withItemStack(slot.getStack()).resolveInternalName(); + if (internalName == null) continue; JsonObject item = manager.getItemInformation().get(internalName); if (Keyboard.getEventKey() == manager.keybindViewRecipe.getKeyCode()) manager.showRecipe(item); if (Keyboard.getEventKey() == manager.keybindViewUsages.getKeyCode()) manager.displayGuiItemUsages(internalName); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/loaders/MinionHelperApiLoader.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/loaders/MinionHelperApiLoader.java index ecf02236..ed275c7a 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/loaders/MinionHelperApiLoader.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/loaders/MinionHelperApiLoader.java @@ -53,7 +53,7 @@ public class MinionHelperApiLoader { private ApiData apiData = null; private boolean notifyNoCollectionApi = false; private long lastLoaded = 0; - private boolean invalidApiKey = false; + private boolean invalidApiKey = true; public MinionHelperApiLoader(MinionHelperManager manager) { this.manager = manager; diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/render/MinionHelperOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/render/MinionHelperOverlay.java index 93a39ec0..a6a92a6a 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/render/MinionHelperOverlay.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/render/MinionHelperOverlay.java @@ -115,7 +115,7 @@ public class MinionHelperOverlay { if (!NotEnoughUpdates.INSTANCE.config.minionHelper.gui) return; if (manager.isInvalidApiKey()) { LinkedHashMap<String, OverviewLine> map = new LinkedHashMap<>(); - map.put("§cInvalid API Key!", new OverviewText(Collections.emptyList(), () -> {})); + map.put("§cNo data found, try running /pv", new OverviewText(Collections.emptyList(), () -> {})); render(map); return; } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java index 49f357e6..5245d604 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java @@ -26,6 +26,7 @@ import io.github.moulberry.notenoughupdates.miscfeatures.EnchantingSolvers; import io.github.moulberry.notenoughupdates.miscfeatures.ItemCooldowns; import io.github.moulberry.notenoughupdates.miscfeatures.MiningStuff; import io.github.moulberry.notenoughupdates.miscfeatures.StorageManager; +import io.github.moulberry.notenoughupdates.miscfeatures.world.CrystalHollowChestHighlighter; import io.github.moulberry.notenoughupdates.util.SBInfo; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.network.NetHandlerPlayClient; @@ -33,6 +34,7 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.network.Packet; import net.minecraft.network.play.client.C01PacketChatMessage; import net.minecraft.network.play.client.C0EPacketClickWindow; +import net.minecraft.network.play.server.S22PacketMultiBlockChange; import net.minecraft.network.play.server.S23PacketBlockChange; import net.minecraft.network.play.server.S2DPacketOpenWindow; import net.minecraft.network.play.server.S2EPacketCloseWindow; @@ -119,6 +121,12 @@ public class MixinNetHandlerPlayClient { public void handleBlockChange(S23PacketBlockChange packetIn, CallbackInfo ci) { MiningStuff.processBlockChangePacket(packetIn); ItemCooldowns.processBlockChangePacket(packetIn); + CrystalHollowChestHighlighter.processBlockChangePacket(packetIn); + } + + @Inject(method = "handleMultiBlockChange", at = @At("HEAD")) + public void handleMultiBlockChange(S22PacketMultiBlockChange packetIn, CallbackInfo ci) { + CrystalHollowChestHighlighter.processMultiBlockChangePacket(packetIn); } @Inject(method = "addToSendQueue", at = @At("HEAD"), cancellable = true) diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/WorldConfig.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/WorldConfig.java index 2f8adc0f..4e1118b7 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/WorldConfig.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/WorldConfig.java @@ -106,4 +106,29 @@ public class WorldConfig { @ConfigAccordionId(id = 3) public String frozenTreasuresColor2 = "0:100:0:255:0"; + @Expose + @ConfigOption( + name = "Crystal Hollow Chests", + desc = "" + ) + @ConfigEditorAccordion(id = 4) + public boolean crystalHollowChestsAccordion = true; + + @Expose + @ConfigOption( + name = "Crystal Hollow Chest Highlighter", + desc = "Highlights chests found in the crystal hollows whilst powder mining" + ) + @ConfigEditorBoolean + @ConfigAccordionId(id = 4) + public boolean highlightCrystalHollowChests = false; + + @Expose + @ConfigOption( + name = "Chest Highlight Color", + desc = "In which color should chests be highlighted" + ) + @ConfigEditorColour + @ConfigAccordionId(id = 4) + public String crystalHollowChestColor = "0:66:255:0:41"; } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java index a1135205..7db8a21c 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java @@ -766,6 +766,9 @@ public class BasicPage extends GuiProfileViewerPage { if (NotEnoughUpdates.INSTANCE.config.profileViewer.displayWeight) { renderWeight(mouseX, mouseY, selectedProfile); } + + selectedProfile.updateTamingLevel(); + selectedProfile.updateBeastMasterMultiplier(); } private String getIcon(String gameModeType) { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/SkyblockProfiles.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/SkyblockProfiles.java index c16d8df0..3bfac529 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/SkyblockProfiles.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/SkyblockProfiles.java @@ -24,6 +24,8 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.events.ProfileDataLoadedEvent; +import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay; import io.github.moulberry.notenoughupdates.profileviewer.bestiary.BestiaryData; import io.github.moulberry.notenoughupdates.profileviewer.weight.senither.SenitherWeight; import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.Weight; @@ -32,6 +34,7 @@ import io.github.moulberry.notenoughupdates.util.UrsaClient; import io.github.moulberry.notenoughupdates.util.Utils; import io.github.moulberry.notenoughupdates.util.hypixelapi.ProfileCollectionInfo; import lombok.Getter; +import net.minecraft.client.Minecraft; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompressedStreamTools; @@ -320,6 +323,12 @@ public class SkyblockProfiles { profileViewer.getManager().ursaClient .get(UrsaClient.profiles(Utils.parseDashlessUUID(uuid))) .handle((profilesJson, throwable) -> { + try { + if (Utils.parseDashlessUUID(uuid).toString().equals(Minecraft.getMinecraft().thePlayer.getUniqueID().toString())) { + new ProfileDataLoadedEvent(uuid, profilesJson).post(); + } + } catch (Exception ignored) { + } if (profilesJson != null && profilesJson.has("success") && profilesJson.get("success").getAsBoolean() && profilesJson.has("profiles")) { Map<String, SkyblockProfile> nameToProfile = new HashMap<>(); @@ -865,7 +874,6 @@ public class SkyblockProfiles { if (skillName.equals("farming")) { maxLevel += Utils.getElementAsInt(Utils.getElement(profileJson, "jacob2.perks.farming_level_cap"), 0); } - out.put(skillName, ProfileViewerUtils.getLevel(levelingArray, skillExperience, maxLevel, false)); } @@ -943,37 +951,7 @@ public class SkyblockProfiles { } public int getBestiaryLevel() { - int beLevel = 0; - for (ItemStack items : BestiaryData.getBestiaryLocations().keySet()) { - List<String> mobs = BestiaryData.getBestiaryLocations().get(items); - if (mobs != null) { - for (String mob : mobs) { - if (mob != null) { - float kills = Utils.getElementAsFloat(Utils.getElement(getProfileJson(), "bestiary.kills_" + mob), 0); - String type; - if (BestiaryData.getMobType().get(mob) != null) { - type = BestiaryData.getMobType().get(mob); - } else { - type = "MOB"; - } - JsonObject leveling = Constants.LEVELING; - ProfileViewer.Level level = null; - if (leveling != null && Utils.getElement(leveling, "bestiary." + type) != null) { - JsonArray levelingArray = Utils.getElement(leveling, "bestiary." + type).getAsJsonArray(); - int levelCap = Utils.getElementAsInt(Utils.getElement(leveling, "bestiary.caps." + type), 0); - level = ProfileViewerUtils.getLevel(levelingArray, kills, levelCap, false); - } - - float levelNum = 0; - if (level != null) { - levelNum = level.level; - } - beLevel += (int) Math.floor(levelNum); - } - } - } - } - return beLevel; + return BestiaryData.calculateTotalBestiaryLevel(BestiaryData.parseBestiaryData(getProfileJson())); } public JsonObject getPetsInfo() { @@ -1171,5 +1149,50 @@ public class SkyblockProfiles { loadMuseumData(); return new MuseumData(null).asLoading(); } + + public void updateBeastMasterMultiplier() { + if (!getUuid().equals(Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""))) return; + JsonObject stats = getProfileJson().get("stats").getAsJsonObject(); + boolean hasBeastmasterCrest = false; + PetInfoOverlay.Rarity currentBeastRarity = PetInfoOverlay.Rarity.COMMON; + for (JsonElement talisman : getInventoryInfo().get("talisman_bag")) { + if (talisman.isJsonNull()) continue; + String internalName = talisman.getAsJsonObject().get("internalname").getAsString(); + if (internalName.startsWith("BEASTMASTER_CREST")) { + hasBeastmasterCrest = true; + try { + PetInfoOverlay.Rarity talismanRarity = PetInfoOverlay.Rarity.valueOf(internalName.replace("BEASTMASTER_CREST_", "")); + if (talismanRarity.beastcreatMultiplyer > currentBeastRarity.beastcreatMultiplyer) + currentBeastRarity = talismanRarity; + } catch (Exception ignored) { + } + } + } + if (hasBeastmasterCrest) { + if (stats.has("mythos_kills")) { + int mk = stats.get("mythos_kills").getAsInt(); + float petXpBoost = mk > 10000 ? 1f : mk > 7500 ? 0.9f : mk > 5000 ? 0.8f : mk > 2500 ? 0.7f : + mk > 1000 + ? 0.6f + : mk > 500 + ? 0.5f + : mk > 250 + ? 0.4f + : mk > 100 + ? 0.3f + : mk > 25 ? 0.2f : 0.1f; + PetInfoOverlay.getConfig().beastMultiplier = petXpBoost * currentBeastRarity.beastcreatMultiplyer; + } else { + PetInfoOverlay.getConfig().beastMultiplier = 0.1f * currentBeastRarity.beastcreatMultiplyer; + } + } + } + + public void updateTamingLevel() { + if (!getUuid().equals(Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""))) return; + if (!getLatestProfile().skillsApiEnabled()) return; + + PetInfoOverlay.getConfig().tamingLevel = (int) getLevelingInfo().get("taming").level; + } } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryData.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryData.java deleted file mode 100644 index 36fc07aa..00000000 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryData.java +++ /dev/null @@ -1,1094 +0,0 @@ -/* - * Copyright (C) 2022 NotEnoughUpdates contributors - * - * This file is part of NotEnoughUpdates. - * - * NotEnoughUpdates is free software: you can redistribute it - * and/or modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * NotEnoughUpdates is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>. - */ - -package io.github.moulberry.notenoughupdates.profileviewer.bestiary; - -import io.github.moulberry.notenoughupdates.util.Utils; -import net.minecraft.init.Blocks; -import net.minecraft.init.Items; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumChatFormatting; - -import java.util.LinkedHashMap; -import java.util.List; - -public class BestiaryData { - - private static final LinkedHashMap<ItemStack, List<String>> bestiaryLocations = new LinkedHashMap<ItemStack, List<String>>() { - { - put( - Utils.createSkull( - EnumChatFormatting.AQUA + "Private Island", - "bdee7687-9c85-4e7a-b789-b55e90d21d68", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzljODg4MWU0MjkxNWE5ZDI5YmI2MWExNmZiMjZkMDU5OTEzMjA0ZDI2NWRmNWI0MzliM2Q3OTJhY2Q1NiJ9fX0=" - ), - Utils.createList( - "family_cave_spider", - "family_enderman_private", - "family_skeleton", - "family_slime", - "family_spider", - "family_witch", - "family_zombie" - ) - ); - put( - Utils.createSkull( - EnumChatFormatting.AQUA + "Hub", - "88208736-41cd-4ed8-8ed7-53179140a7fa", - "eyJ0aW1lc3RhbXAiOjE1NTkyMTU0MTY5MDksInByb2ZpbGVJZCI6IjQxZDNhYmMyZDc0OTQwMGM5MDkwZDU0MzRkMDM4MzFiIiwicHJvZmlsZU5hbWUiOiJNZWdha2xvb24iLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2Q3Y2M2Njg3NDIzZDA1NzBkNTU2YWM1M2UwNjc2Y2I1NjNiYmRkOTcxN2NkODI2OWJkZWJlZDZmNmQ0ZTdiZjgifX19" - ), - Utils.createList("family_unburried_zombie", "family_old_wolf", "family_ruin_wolf", "family_zombie_villager") - ); - put( - Utils.createSkull( - EnumChatFormatting.AQUA + "Spiders Den", - "acbeaf98-2081-40c5-b5a3-221a2957d532", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzc1NDMxOGEzMzc2ZjQ3MGU0ODFkZmNkNmM4M2E1OWFhNjkwYWQ0YjRkZDc1NzdmZGFkMWMyZWYwOGQ4YWVlNiJ9fX0" - ), - Utils.createList( - "family_arachne", - "family_arachne_brood", - "family_arachne_keeper", - "family_brood_mother_spider", - "family_dasher_spider", - "family_respawning_skeleton", - "family_random_slime", - "family_spider_jockey", - "family_splitter_spider", - "family_voracious_spider", - "family_weaver_spider" - ) - ); - put( - Utils.createSkull( - EnumChatFormatting.AQUA + "The End", - "e39ea8b1-a267-48a9-907a-1b97b85342bc", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzg0MGI4N2Q1MjI3MWQyYTc1NWRlZGM4Mjg3N2UwZWQzZGY2N2RjYzQyZWE0NzllYzE0NjE3NmIwMjc3OWE1In19fQ" - ), - Utils.createList( - "family_dragon", - "family_enderman", - "family_endermite", - "family_corrupted_protector", - "family_obsidian_wither", - "family_voidling_extremist", - "family_voidling_fanatic", - "family_watcher", - "family_zealot_enderman" - ) - ); - put( - Utils.createSkull( - EnumChatFormatting.AQUA + "Crimson Isles", - "d8489bfe-dcd7-41f0-bfbd-fb482bf61ecb", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzM2ODdlMjVjNjMyYmNlOGFhNjFlMGQ2NGMyNGU2OTRjM2VlYTYyOWVhOTQ0ZjRjZjMwZGNmYjRmYmNlMDcxIn19fQ" - ), - Utils.createList( - "family_ashfang", - "family_barbarian_duke_x", - "family_bladesoul", - "family_blaze", - "family_flaming_spider", - "family_ghast", - "family_mage_outlaw", - "family_magma_cube", - "family_magma_boss", - "family_matcho", - "family_charging_mushroom_cow", - "family_pigman", - "family_wither_skeleton", - "family_wither_spectre" - ) - ); - put( - Utils.createSkull( - EnumChatFormatting.AQUA + "Deep Caverns", - "896b5137-a2dd-4de2-8c63-d5a5649bfc70", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTY5YTFmMTE0MTUxYjQ1MjEzNzNmMzRiYzE0YzI5NjNhNTAxMWNkYzI1YTY1NTRjNDhjNzA4Y2Q5NmViZmMifX19" - ), - Utils.createList( - "family_automaton", - "family_butterfly", - "family_emerald_slime", - "family_caverns_ghost", - "family_goblin", - "family_team_treasurite", - "family_ice_walker", - "family_lapis_zombie", - "family_diamond_skeleton", - "family_diamond_zombie", - "family_redstone_pigman", - "family_sludge", - "family_invisible_creeper", - "family_thyst", - "family_treasure_hoarder", - "family_worms", - "family_yog" - ) - ); - put( - Utils.createSkull( - EnumChatFormatting.AQUA + "The Park", - "6473b2ff-0575-4aec-811f-5f0dca2131b6", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTIyMWY4MTNkYWNlZTBmZWY4YzU5Zjc2ODk0ZGJiMjY0MTU0NzhkOWRkZmM0NGMyZTcwOGE2ZDNiNzU0OWIifX19" - ), - Utils.createList("family_howling_spirit", "family_pack_spirit", "family_soul_of_the_alpha") - ); - put( - Utils.createItemStack(Item.getItemFromBlock(Blocks.lit_pumpkin), EnumChatFormatting.AQUA + "Spooky"), - Utils.createList( - "family_batty_witch", - "family_headless_horseman", - "family_phantom_spirit", - "family_scary_jerry", - "family_trick_or_treater", - "family_wither_gourd", - "family_wraith" - ) - ); - put( - Utils.createSkull( - EnumChatFormatting.AQUA + "Catacombs", - "00b3837d-9275-304c-8bf9-656659087e6b", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTY0ZTFjM2UzMTVjOGQ4ZmZmYzM3OTg1YjY2ODFjNWJkMTZhNmY5N2ZmZDA3MTk5ZThhMDVlZmJlZjEwMzc5MyJ9fX0" - ), - Utils.createList( - "family_diamond_guy", - "family_cellar_spider", - "family_crypt_dreadlord", - "family_crypt_lurker", - "family_crypt_souleater", - "family_king_midas", - "family_lonely_spider", - "family_lost_adventurer", - "family_scared_skeleton", - "family_shadow_assassin", - "family_skeleton_grunt", - "family_skeleton_master", - "family_skeleton_soldier", - "family_skeletor", - "family_sniper_skeleton", - "family_super_archer", - "family_super_tank_zombie", - "family_crypt_tank_zombie", - "family_watcher_summon_undead", - "family_dungeon_respawning_skeleton", - "family_crypt_witherskeleton", - "family_zombie_commander", - "family_zombie_grunt", - "family_zombie_knight", - "family_zombie_soldier" - ) - ); - } - }; - private static final LinkedHashMap<String, ItemStack> bestiaryMobs = new LinkedHashMap<String, ItemStack>() { - { - // Private Island - put( - "family_cave_spider", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aCave Spider", - "a8aee72d-0d1d-3db7-8cf8-be1ce6ec2dc4", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDE2NDVkZmQ3N2QwOTkyMzEwN2IzNDk2ZTk0ZWViNWMzMDMyOWY5N2VmYzk2ZWQ3NmUyMjZlOTgyMjQifX19" - ) - ); - put( - "family_enderman_private", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aEnderman", - "2005daad-730b-363c-abae-e6f3830816fb", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTZjMGIzNmQ1M2ZmZjY5YTQ5YzdkNmYzOTMyZjJiMGZlOTQ4ZTAzMjIyNmQ1ZTgwNDVlYzU4NDA4YTM2ZTk1MSJ9fX0=" - ) - ); - put( - "family_skeleton", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aSkeleton", - "53924f1a-87e6-4709-8e53-f1c7d13dc239", - "ewogICJ0aW1lc3RhbXAiIDogMTY1NTYzMTgzNjcwNCwKICAicHJvZmlsZUlkIiA6ICI1MzkyNGYxYTg3ZTY0NzA5OGU1M2YxYzdkMTNkYzIzOSIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaHJvd3BvIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzg4ZWI2OGE0ZDM4ZTlmNDQ2YjhlOTkyNzVmMTYwMzAyZjM2NmVmMTAyMTZhYmY5NDg0ODdlNTgyNTEyYmQwZjMiCiAgICB9CiAgfQp9=" - ) - ); - put( - "family_slime", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aSlime", - "3b70a2f3-319c-38d5-b7d1-5b2425770184", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODk1YWVlYzZiODQyYWRhODY2OWY4NDZkNjViYzQ5NzYyNTk3ODI0YWI5NDRmMjJmNDViZjNiYmI5NDFhYmU2YyJ9fX0=" - ) - ); - put( - "family_spider", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aSpider", - "7c63f3cf-a963-311a-aeca-3a075b417806", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2Q1NDE1NDFkYWFmZjUwODk2Y2QyNThiZGJkZDRjZjgwYzNiYTgxNjczNTcyNjA3OGJmZTM5MzkyN2U1N2YxIn19fQ==" - ) - ); - put( - "family_witch", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aWitch", - "cf4f97d7-2e1f-3678-9ca3-4a7b9666cc28", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmNlNjYwNDE1N2ZjNGFiNTU5MWU0YmNmNTA3YTc0OTkxOGVlOWM0MWUzNTdkNDczNzZlMGVlNzM0MjA3NGM5MCJ9fX0=" - ) - ); - put( - "family_zombie", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aZombie", - "9673d491-d589-44cb-b63e-5f8b3148b3df", - "ewogICJ0aW1lc3RhbXAiIDogMTY0Njc1NjU2MzM1MiwKICAicHJvZmlsZUlkIiA6ICJkYmQ4MDQ2M2EwMzY0Y2FjYjI3OGNhODBhMDBkZGIxMyIsCiAgInByb2ZpbGVOYW1lIiA6ICJ4bG9nMjEiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjM2NjZkMWJkZjQ1NThiMGQxNjk5MGIyNDFlODE4NWNiZjU4YzNlMDNjMjRkOTA0NTQ0ZThjYzY1YjFjMzhkMSIKICAgIH0KICB9Cn0=\", \"n8vct7fj3NdiODy/h6PJhjxSR2U7d8gQxHjdVq553HqG60SSczt1Tl9XhvQbZP14ZrJGWxCziauuYb/HjZza0ugNAhfwh9z8hqR1PjBJGdvp+wpxoWpP2wd5RT9i5/GYEqpiAIAt9vHY1YeyejFqKZhXaGgp7gZZNjOQWQqB0SZzTUTAPzRW9FiY8x2re7H7Y1POThRXOvvkeQ6qWdPV6Hk5hTumV0rfEGm971jQRIbfdzBZDJRcro+8y+dlje/NpF5qf0JLy78Xr4hc2cwbT9+wqOeoUTcM/r9mwL15OKgFLjB44jszauKRHNfoqb6B3+1fNQEJrJK/7hIyvswpde7C5uOxkE7oMFib6X68VVEhb6PGC1+HWNaMaGjI0wWEkCahp48ihN9+sBEBFXOxIAhXG/pvJcbEi742/cBS1CTtOI8qui6JSL9MKX5jmyhtjjibOYRZbacosqayCnwsJAdMmwS7zIxc8jGhpfKECiSni/baS4zRla0bns4hfEM0l7ASv0Dh99WQD0We2ZMqltmix8lMEaAILXJVBln3CFrjYvncfku2hrSaqu1lNAtfMYYSITEUCBJ7McVAVmUHOrER0XGoVs9L237H0BQNSLqlGGEQ7OM8HV6G0YfXGlbNgNBx6O9k8ZijuK60JeEoJapcmbNj/LVHEU+dsgcFAbo=" - ) - ); - - // Hub - put("family_unburried_zombie", Utils.createItemStack(Items.golden_sword, EnumChatFormatting.AQUA + "§aCrypt Ghoul")); - put( - "family_old_wolf", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aOld Wolf", - "26e6f2d9-8a27-3a77-965c-5bd2b5d2dc93", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDM1OTUzN2MxNTUzNGY2MWMxY2Q4ODZiYzExODc3NGVkMjIyODBlN2NkYWI2NjEzODcwMTYwYWFkNGNhMzkifX19" - ) - ); - put( - "family_ruin_wolf", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aWolf", - "7e9af289-f295-3f8c-bd54-58b7667d5759", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjlkMWQzMTEzZWM0M2FjMjk2MWRkNTlmMjgxNzVmYjQ3MTg4NzNjNmM0NDhkZmNhODcyMjMxN2Q2NyJ9fX0=" - ) - ); - put( - "family_zombie_villager", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aZombie Villager", - "3acb9940-fc42-328e-91e8-c9a9a57e8698", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTVlMDhhODc3NmMxNzY0YzNmZTZhNmRkZDQxMmRmY2I4N2Y0MTMzMWRhZDQ3OWFjOTZjMjFkZjRiZjNhYzg5YyJ9fX0=" - ) - ); - - // Spiders Den - put( - "family_arachne", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aArachne", - "7c63f3cf-a963-311a-aeca-3a075b417806", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2Q1NDE1NDFkYWFmZjUwODk2Y2QyNThiZGJkZDRjZjgwYzNiYTgxNjczNTcyNjA3OGJmZTM5MzkyN2U1N2YxIn19fQ==" - ) - ); - put( - "family_arachne_brood", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aArachne's Brood", - "7c63f3cf-a963-311a-aeca-3a075b417806", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2Q1NDE1NDFkYWFmZjUwODk2Y2QyNThiZGJkZDRjZjgwYzNiYTgxNjczNTcyNjA3OGJmZTM5MzkyN2U1N2YxIn19fQ==" - ) - ); - put( - "family_arachne_keeper", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aArachne's Keeper", - "7c63f3cf-a963-311a-aeca-3a075b417806", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2Q1NDE1NDFkYWFmZjUwODk2Y2QyNThiZGJkZDRjZjgwYzNiYTgxNjczNTcyNjA3OGJmZTM5MzkyN2U1N2YxIn19fQ==" - ) - ); - put( - "family_brood_mother_spider", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aBrood Mother", - "d7390e70-1e99-3c24-9b1c-bb098e0bbef1", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2YwNjIyYjM5OThkNDJiMzRkNWJjNzYwYmIyYzgzZmRiYzZlNjhmYWIwNWI3ZWExN2IzNTA5N2VkODExOTBkNiJ9fX0=" - ) - ); - put( - "family_dasher_spider", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aDasher Spider", - "7c63f3cf-a963-311a-aeca-3a075b417806", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2Q1NDE1NDFkYWFmZjUwODk2Y2QyNThiZGJkZDRjZjgwYzNiYTgxNjczNTcyNjA3OGJmZTM5MzkyN2U1N2YxIn19fQ==" - ) - ); - put( - "family_respawning_skeleton", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aGravel Skeleton", - "53924f1a-87e6-4709-8e53-f1c7d13dc239", - "ewogICJ0aW1lc3RhbXAiIDogMTY1NTYzMTgzNjcwNCwKICAicHJvZmlsZUlkIiA6ICI1MzkyNGYxYTg3ZTY0NzA5OGU1M2YxYzdkMTNkYzIzOSIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaHJvd3BvIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzg4ZWI2OGE0ZDM4ZTlmNDQ2YjhlOTkyNzVmMTYwMzAyZjM2NmVmMTAyMTZhYmY5NDg0ODdlNTgyNTEyYmQwZjMiCiAgICB9CiAgfQp9=" - ) - ); - put( - "family_random_slime", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aRain Slime", - "3b70a2f3-319c-38d5-b7d1-5b2425770184", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODk1YWVlYzZiODQyYWRhODY2OWY4NDZkNjViYzQ5NzYyNTk3ODI0YWI5NDRmMjJmNDViZjNiYmI5NDFhYmU2YyJ9fX0=" - ) - ); - put( - "family_spider_jockey", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aSpider Jockey", - "4eb8745c-80d2-356b-b4fa-f3ffa74082e7", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzA5MzkzNzNjYWZlNGIxZjUzOTdhYWZkMDlmM2JiMTY2M2U3YjYyOWE0MWE3NWZiZGMxODYwYjZiZjhiNDc1ZiJ9fX0=" - ) - ); - put( - "family_splitter_spider", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aSplitter Spider", - "50010472-fa22-3519-b941-2d6d22f47bf1", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmFjZjY5ZmM3YWY1NDk3YTE3NDE4OTFkMWU1YmYzMmI5NmFlMGQ2YzBiYmQzYzE0NzU4ZWE0NGEwM2M1NzI4MyJ9fX0=" - ) - ); - put( - "family_voracious_spider", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aVoracious Spider", - "3e5474d4-4365-3ea7-b4bc-b4edc54da341", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODMwMDk4NmVkMGEwNGVhNzk5MDRmNmFlNTNmNDllZDNhMGZmNWIxZGY2MmJiYTYyMmVjYmQzNzc3ZjE1NmRmOCJ9fX0=" - ) - ); - put( - "family_weaver_spider", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aWeaver Spider", - "97414c0c-623b-3df3-b1f6-bbcaddafc7fc", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTIxNDM4ZjY0NmRjMDQ1MTU5NjdlODE5NWNjYzNkMzFlMjNiMDJmOWFhMGFjOTE0ZWRjMjgyMmY5ODM5NGI4NiJ9fX0=" - ) - ); - - // The End - put("family_dragon", Utils.createItemStack(Item.getItemFromBlock(Blocks.dragon_egg), EnumChatFormatting.AQUA + "§aDragon")); - put( - "family_enderman", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aEnderman", - "2005daad-730b-363c-abae-e6f3830816fb", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTZjMGIzNmQ1M2ZmZjY5YTQ5YzdkNmYzOTMyZjJiMGZlOTQ4ZTAzMjIyNmQ1ZTgwNDVlYzU4NDA4YTM2ZTk1MSJ9fX0=" - ) - ); - put( - "family_endermite", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aEndermite", - "b3224e56-73d2-32f9-9081-a23b7512035b", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWJjN2I5ZDM2ZmI5MmI2YmYyOTJiZTczZDMyYzZjNWIwZWNjMjViNDQzMjNhNTQxZmFlMWYxZTY3ZTM5M2EzZSJ9fX0=" - ) - ); - put( - "family_corrupted_protector", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aEndstone Protector", - "a46a9adf-60a3-38f2-a3dd-335d85f1cc10", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjJiY2FjZWViNDE2MmY0MDBkNDQ3NDMzMTU5MzJhYzgyMGQzMTE5YWM4OTg2YTAxNjFhNzI2MTYxY2NjOTNmYyJ9fX0=" - ) - ); - put( - "family_obsidian_wither", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aObsidian Defender", - "d0e05de7-6067-454d-beae-c6d19d886191", - "ewogICJ0aW1lc3RhbXAiIDogMTY1NTYzMjg1MTE1NCwKICAicHJvZmlsZUlkIiA6ICJkMGUwNWRlNzYwNjc0NTRkYmVhZWM2ZDE5ZDg4NjE5MSIsCiAgInByb2ZpbGVOYW1lIiA6ICJNb3VsYmVycnkiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmNlMTU1MjI0ZWE0YmM0OWE4ZTkxOTA3MzdjYjA0MTdkOGE3YzM4YTAzN2Q4ZDAzODJkZGU0ODI5YzEwMzU5MCIsCiAgICAgICJtZXRhZGF0YSIgOiB7CiAgICAgICAgIm1vZGVsIiA6ICJzbGltIgogICAgICB9CiAgICB9CiAgfQp9" - ) - ); - put( - "family_voidling_extremist", - Utils.createSkull( - EnumChatFormatting.AQUA + "§a§dVoidling Extremist", - "159dcb01-74e3-382c-87d6-3afa022fb379", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWIwNzU5NGUyZGYyNzM5MjFhNzdjMTAxZDBiZmRmYTExMTVhYmVkNWI5YjIwMjllYjQ5NmNlYmE5YmRiYjRiMyJ9fX0=" - ) - ); - put( - "family_voidling_fanatic", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aVoidling Fanatic", - "e86aab24-6245-3967-bf3d-07e31999b602", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTUzYjdiY2Q1NmYwYjk1Zjg3ZGQ3OWVkMTc2MzZiZWI5ZDgzNDY3NDQwMTQyMjhlYTJmNmIxMTBiMTQ4YzEifX19" - ) - ); - put( - "family_watcher", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aWatcher", - "00a702b9-7bad-3205-a04b-52478d8c0e7f", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGFhOGZjOGRlNjQxN2I0OGQ0OGM4MGI0NDNjZjUzMjZlM2Q5ZGE0ZGJlOWIyNWZjZDQ5NTQ5ZDk2MTY4ZmMwIn19fQ==" - ) - ); - put( - "family_zealot_enderman", - Utils.createItemStack(Item.getItemFromBlock(Blocks.ender_chest), EnumChatFormatting.AQUA + "§aZealot") - ); - - // Crimson Isle - put( - "family_ashfang", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aAshfang", - "1bc8810e-2b57-3a89-8e00-a47a057d6ecc", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2QyYTViNGIxMDliZDc4OGVkYmEwMTcxZDBhYWI4YTU1MzA1YWMyZjU2MTg0ZGY3MGEzMTljZDQ4OGEzNmMzZSJ9fX0=" - ) - ); - put( - "family_barbarian_duke_x", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aBarbarian Duke X", - "6ddece1d-8227-35f3-b9ca-476a9f6cd8c5", - "ewogICJ0aW1lc3RhbXAiIDogMTY0MTI0OTYyNTU3NSwKICAicHJvZmlsZUlkIiA6ICIyNzZlMDQ2YjI0MDM0M2VkOTk2NmU0OTRlN2U2Y2IzNCIsCiAgInByb2ZpbGVOYW1lIiA6ICJBRFJBTlM3MTAiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmVlOWZjN2MxODFlMmY2MzBmNmIxYWY4NWQ0OTUxMzU5Y2FmY2ZhODJmZjVlYTNiYzI4M2UwZTYwODhjNmU1NCIKICAgIH0KICB9Cn0" - ) - ); - put( - "family_bladesoul", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aBladesoul", - "9a1699a4-9b61-37a5-be7a-ca23a1f092a1", - "ewogICJ0aW1lc3RhbXAiIDogMTY0NDA4Mjg1NzcxMCwKICAicHJvZmlsZUlkIiA6ICIwNTVhOTk2NTk2M2E0YjRmOGMwMjRmMTJmNDFkMmNmMiIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaGVWb3hlbGxlIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzdmNWYzMzg0Mzg0ZDdmMDNiZjk3YTczMDk5YjBiYWZiNzJjNTM4ZmMwNDE1YWM4NjEzYjY2NGY4NzU3OWEzNzkiCiAgICB9CiAgfQp9" - ) - ); - put( - "family_blaze", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aBlaze", - "118fe834-28aa-3b0d-afe6-f0c52d01afe8", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjc4ZWYyZTRjZjJjNDFhMmQxNGJmZGU5Y2FmZjEwMjE5ZjViMWJmNWIzNWE0OWViNTFjNjQ2Nzg4MmNiNWYwIn19fQ==" - ) - ); - put( - "family_flaming_spider", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aFlaming Spider", - "d27e14a2-f35e-3c7b-8062-089fa201a533", - "ewogICJ0aW1lc3RhbXAiIDogMTY0NDQ5OTUzOTQ2NywKICAicHJvZmlsZUlkIiA6ICJhYTZhNzUwNWVkYmU0NjNiYjk1NWYyMWY0MjNiYTM1NCIsCiAgInByb2ZpbGVOYW1lIiA6ICJub3RhbmR5d2FyaG9sIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzVhNjVlZjIzZWEzNTA0NzE1MGQzMzg4MDQ3M2E0N2ZlNjM1ZjBjMGUzYzgyM2JkNzZkYzg0OWNiMDI0NDE2NTUiLAogICAgICAibWV0YWRhdGEiIDogewogICAgICAgICJtb2RlbCIgOiAic2xpbSIKICAgICAgfQogICAgfQogIH0KfQ==" - ) - ); - put( - "family_ghast", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aGhast", - "69725d7d-1933-3dea-87bd-a3052482ab2c", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGU4YTM4ZTlhZmJkM2RhMTBkMTliNTc3YzU1YzdiZmQ2YjRmMmU0MDdlNDRkNDAxN2IyM2JlOTE2N2FiZmYwMiJ9fX0=" - ) - ); - put( - "family_mage_outlaw", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aMage Outlaw", - "1d16c26c-d937-336f-821a-371968d050c2", - "ewogICJ0aW1lc3RhbXAiIDogMTY0NDA4Mjg3Mzk2NywKICAicHJvZmlsZUlkIiA6ICJiNzQ3OWJhZTI5YzQ0YjIzYmE1NjI4MzM3OGYwZTNjNiIsCiAgInByb2ZpbGVOYW1lIiA6ICJTeWxlZXgiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWJlYzk5YjNhMDUwZmQyNzc1Mjg0MDc2NzYzNjZlMjBiOTIwMDZhZDg4ZDE0NzI3YTRkOTllYjhjYjI3M2I2MiIKICAgIH0KICB9Cn0" - ) - ); - put( - "family_magma_cube", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aMagma Cube", - "35f02923-7bec-3869-9ef5-b42a4794cac8", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzg5NTdkNTAyM2M5MzdjNGM0MWFhMjQxMmQ0MzQxMGJkYTIzY2Y3OWE5ZjZhYjM2Yjc2ZmVmMmQ3YzQyOSJ9fX0=" - ) - ); - put( - "family_magma_boss", - Utils.createSkull( - EnumChatFormatting.AQUA + "§a§4§lMagma Boss", - "35f02923-7bec-3869-9ef5-b42a4794cac8", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzg5NTdkNTAyM2M5MzdjNGM0MWFhMjQxMmQ0MzQxMGJkYTIzY2Y3OWE5ZjZhYjM2Yjc2ZmVmMmQ3YzQyOSJ9fX0=" - ) - ); - put( - "family_matcho", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aMatcho", - "61db73be-677f-554a-9450-e306a7ff0449", - "e3RleHR1cmVzOntTS0lOOnt1cmw6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWYyZGFhYmI3OGExZjdhYTEyZDE0NWQ4OGMwY2E0NmI5ZTg1NmY1NTM0ZTkyODZlNTU1ZmFmMGMyOTFmNGZkNSJ9fX0=" - ) - ); - put( - "family_charging_mushroom_cow", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aMushroom Bull", - "2b9eb675-2097-4b51-8fec-c1a51562f19c", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTE2M2JjNDE2YjhlNjA1OGY5MmIyMzFlOWE1MjRiN2ZlMTE4ZWI2ZTdlZWFiNGFkMTZkMWI1MmEzZWMwNGZjZCJ9fX0=" - ) - ); - put( - "family_pigman", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aPigman", - "3fc29372-e78e-3ad6-b0b0-05ca0a84babd", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzRlOWM2ZTk4NTgyZmZkOGZmOGZlYjMzMjJjZDE4NDljNDNmYjE2YjE1OGFiYjExY2E3YjQyZWRhNzc0M2ViIn19fQ==" - ) - ); - put( - "family_wither_skeleton", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aWither Skeleton", - "2141b934-c877-3db1-bc6c-7c9a347ffa95", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzk1M2I2YzY4NDQ4ZTdlNmI2YmY4ZmIyNzNkNzIwM2FjZDhlMWJlMTllODE0ODFlYWQ1MWY0NWRlNTlhOCJ9fX0=" - ) - ); - put( - "family_wither_spectre", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aWither Spectre", - "9a1699a4-9b61-37a5-be7a-ca23a1f092a1", - "ewogICJ0aW1lc3RhbXAiIDogMTY0NDA4Mjg1NzcxMCwKICAicHJvZmlsZUlkIiA6ICIwNTVhOTk2NTk2M2E0YjRmOGMwMjRmMTJmNDFkMmNmMiIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaGVWb3hlbGxlIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzdmNWYzMzg0Mzg0ZDdmMDNiZjk3YTczMDk5YjBiYWZiNzJjNTM4ZmMwNDE1YWM4NjEzYjY2NGY4NzU3OWEzNzkiCiAgICB9CiAgfQp9" - ) - ); - - // Deep Caverns - put( - "family_automaton", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aAutomaton", - "a46a9adf-60a3-38f2-a3dd-335d85f1cc10", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjJiY2FjZWViNDE2MmY0MDBkNDQ3NDMzMTU5MzJhYzgyMGQzMTE5YWM4OTg2YTAxNjFhNzI2MTYxY2NjOTNmYyJ9fX0=" - ) - ); - put( - "family_butterfly", - Utils.createSkull( - EnumChatFormatting.AQUA + "§a§eButterfly", - "9dd11ec6-cfea-34df-9336-416c946567bc", - "ewogICJ0aW1lc3RhbXAiIDogMTYyNTUxMjE4ODY3NCwKICAicHJvZmlsZUlkIiA6ICI3MzgyZGRmYmU0ODU0NTVjODI1ZjkwMGY4OGZkMzJmOCIsCiAgInByb2ZpbGVOYW1lIiA6ICJJb3lhbCIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS85ZmQ4MDZkZWZkZmRmNTliMWYyNjA5YzhlZTM2NDY2NmRlNjYxMjdhNjIzNDE1YjU0MzBjOTM1OGM2MDFlZjdjIgogICAgfQogIH0KfQ==" - ) - ); - put( - "family_emerald_slime", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aEmerald Slime", - "cb762e0d-a1e6-3888-8c05-eddabbbe49a2", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTc3NGU4NmFhNGNmZjc5MjM5NWI3N2FkZDU3YjAwYmIxYTEwMmY4ZjBmMDk4MGY0ZDU1YjNkN2FmZjFlNmRhOSJ9fX0=" - ) - ); - put( - "family_caverns_ghost", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aGhost", - "c5752211-7503-3e77-9890-d1cf6ba1d0e7", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTgxOTc3OTE4YTExODBlMGRlYzg3OWU2YmNkMWFhMzk0OTQ5NzdiYjkxM2JlMmFiMDFhZmYxZGIxZmE0In19fQ==" - ) - ); - put( - "family_goblin", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aGoblin", - "7c7d07db-4911-31f1-9a19-1589899cfe25", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjZiOTcyZTMyZDc2MWIxOTI2MjZlNWQ2ZDAxZWRjMDk0OTQwOTEwMTAzY2VhNWUyZTJkMWYyMzFhZGI3NTVkNSJ9fX0=" - ) - ); - put( - "family_team_treasurite", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aGrunt", - "a64ccd19-2a64-39a4-b2f5-cb6799c12a99", - "ewogICJ0aW1lc3RhbXAiIDogMTYxODE5NTA2MDUwMCwKICAicHJvZmlsZUlkIiA6ICI0ZTMwZjUwZTdiYWU0M2YzYWZkMmE3NDUyY2ViZTI5YyIsCiAgInByb2ZpbGVOYW1lIiA6ICJfdG9tYXRvel8iLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWY1ZTAzYjhkZTExOWY4NTg5YTgwODIyNGNiZWE3MzdmNWRjZjI0MjM1Nzk5YjczNzhhYzViZjA2YWJmNmRkNCIKICAgIH0KICB9Cn0=" - ) - ); - put( - "family_ice_walker", - Utils.createItemStack(Item.getItemFromBlock(Blocks.packed_ice), EnumChatFormatting.AQUA + "§aIce Walker") - ); - put("family_lapis_zombie", Utils.createItemStack(Items.dye, EnumChatFormatting.AQUA + "§aLapis Zombie", 4)); - put( - "family_diamond_skeleton", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aMiner Skeleton", - "39c843e6-237b-36b2-8a7b-c5ff5d3ebf99", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODM2YmJjNDIxNWNlYTFiNmE0ODRlODkzYjExNmU3MzQ1OWVmMzZiZmZjNjIyNzQxZTU3N2U5NDkzYTQxZTZlIn19fQ==" - ) - ); - put( - "family_diamond_zombie", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aMiner Zombie", - "468210c9-f4bd-34c7-aa8d-2c3d0d5e05c1", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDI4ZDlmZjU0MTg4YTFhZmVlNjViOTRmM2JmY2NlMzIxYzY0M2EzNDU5MGMxNGIxOTJiMmUzZWMyZjUyNWQzIn19fQ==" - ) - ); - put("family_redstone_pigman", Utils.createItemStack(Items.redstone, EnumChatFormatting.AQUA + "§aRedstone Pigman")); - put( - "family_sludge", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aSludge", - "3b70a2f3-319c-38d5-b7d1-5b2425770184", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODk1YWVlYzZiODQyYWRhODY2OWY4NDZkNjViYzQ5NzYyNTk3ODI0YWI5NDRmMjJmNDViZjNiYmI5NDFhYmU2YyJ9fX0=" - ) - ); - put( - "family_invisible_creeper", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aSneaky Creeper", - "81fb1385-b2fc-4d4f-b5bb-0fe9b1d37d60", - "ewogICJ0aW1lc3RhbXAiIDogMTYxOTE5MjI5MzI5OCwKICAicHJvZmlsZUlkIiA6ICI0ZjU2ZTg2ODk2OGU0ZWEwYmNjM2M2NzRlNzQ3ODdjOCIsCiAgInByb2ZpbGVOYW1lIiA6ICJDVUNGTDE1IiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2E2ODIyNGNmOGVkNGMwM2I0NTdiZjQ5YmViNmY1NDQxOTM2NzkyNjhiODQyMWIwMWZmY2U2ZDI3YjI1YWMzMmQiCiAgICB9CiAgfQp9" - ) - ); - put( - "family_thyst", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aThyst", - "b3224e56-73d2-32f9-9081-a23b7512035b", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWJjN2I5ZDM2ZmI5MmI2YmYyOTJiZTczZDMyYzZjNWIwZWNjMjViNDQzMjNhNTQxZmFlMWYxZTY3ZTM5M2EzZSJ9fX0=" - ) - ); - put( - "family_treasure_hoarder", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aTreasure Hoarder", - "b0f13fc2-07a5-3964-8303-784f802e5f0f", - "ewogICJ0aW1lc3RhbXAiIDogMTU5MDE1NjYzNDYzOCwKICAicHJvZmlsZUlkIiA6ICI5MWZlMTk2ODdjOTA0NjU2YWExZmMwNTk4NmRkM2ZlNyIsCiAgInByb2ZpbGVOYW1lIiA6ICJoaGphYnJpcyIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9iMmIxMmE4MTRjZWQ4YWYwMmNkZGYyOWEzN2U3ZjMwMTFlNDMwZThhMThiMzhiNzA2ZjI3YzZiZDMxNjUwYjY1IgogICAgfQogIH0KfQ==" - ) - ); - put( - "family_worms", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aWorm", - "29f95759-1a6f-3e85-9941-91a7a2275274", - "ewogICJ0aW1lc3RhbXAiIDogMTYyMDQ0NTc2NDQ1MSwKICAicHJvZmlsZUlkIiA6ICJmNDY0NTcxNDNkMTU0ZmEwOTkxNjBlNGJmNzI3ZGNiOSIsCiAgInByb2ZpbGVOYW1lIiA6ICJSZWxhcGFnbzA1IiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2RmMDNhZDk2MDkyZjNmNzg5OTAyNDM2NzA5Y2RmNjlkZTZiNzI3YzEyMWIzYzJkYWVmOWZmYTFjY2FlZDE4NmMiLAogICAgICAibWV0YWRhdGEiIDogewogICAgICAgICJtb2RlbCIgOiAic2xpbSIKICAgICAgfQogICAgfQogIH0KfQ==" - ) - ); - put( - "family_yog", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aYog", - "35f02923-7bec-3869-9ef5-b42a4794cac8", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzg5NTdkNTAyM2M5MzdjNGM0MWFhMjQxMmQ0MzQxMGJkYTIzY2Y3OWE5ZjZhYjM2Yjc2ZmVmMmQ3YzQyOSJ9fX0=" - ) - ); - - // The Park - put( - "family_howling_spirit", - Utils.createSkull( - EnumChatFormatting.AQUA + "§a§bHowling Spirit", - "802a167c-cbcd-3a1f-becd-5b1a25a4cf15", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjdjOGJlZjZiZWI3N2UyOWFmODYyN2VjZGMzOGQ4NmFhMmZlYTdjY2QxNjNkYzczYzAwZjlmMjU4ZjlhMTQ1NyJ9fX0=" - ) - ); - put( - "family_pack_spirit", - Utils.createSkull( - EnumChatFormatting.AQUA + "§a§bPack Spirit", - "802a167c-cbcd-3a1f-becd-5b1a25a4cf15", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjdjOGJlZjZiZWI3N2UyOWFmODYyN2VjZGMzOGQ4NmFhMmZlYTdjY2QxNjNkYzczYzAwZjlmMjU4ZjlhMTQ1NyJ9fX0=" - ) - ); - put( - "family_soul_of_the_alpha", - Utils.createSkull( - EnumChatFormatting.AQUA + "§a§3Soul of the Alpha", - "802a167c-cbcd-3a1f-becd-5b1a25a4cf15", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjdjOGJlZjZiZWI3N2UyOWFmODYyN2VjZGMzOGQ4NmFhMmZlYTdjY2QxNjNkYzczYzAwZjlmMjU4ZjlhMTQ1NyJ9fX0=" - ) - ); - - // Spooky - put( - "family_batty_witch", - Utils.createSkull( - EnumChatFormatting.AQUA + "§a§8Crazy Witch", - "cf4f97d7-2e1f-3678-9ca3-4a7b9666cc28", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmNlNjYwNDE1N2ZjNGFiNTU5MWU0YmNmNTA3YTc0OTkxOGVlOWM0MWUzNTdkNDczNzZlMGVlNzM0MjA3NGM5MCJ9fX0=" - ) - ); - put( - "family_headless_horseman", - Utils.createSkull( - EnumChatFormatting.AQUA + "§a§6Headless Horseman", - "2594a979-1302-3d6e-a1da-c9dbf0959539", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGM2NTcwZjEyNDI5OTJmNmViYTIzZWU1ODI1OThjMzllM2U3NDUzODMyNzNkZWVmOGIzOTc3NTgzZmUzY2Y1In19fQ==" - ) - ); - put( - "family_phantom_spirit", - Utils.createSkull( - EnumChatFormatting.AQUA + "§a§cPhantom Spirit", - "805d7035-5f25-37ea-8530-7c0d09156c8e", - "ewogICJ0aW1lc3RhbXAiIDogMTYwMzcyMjc5NzYzNywKICAicHJvZmlsZUlkIiA6ICJhMmY4MzQ1OTVjODk0YTI3YWRkMzA0OTcxNmNhOTEwYyIsCiAgInByb2ZpbGVOYW1lIiA6ICJiUHVuY2giLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjUzYjJmN2M1ZTE3N2JkNjdjZWFkMzBkMGVlNTM0MjVjNzY4NGM5NzVjOGMyYTUyNzNhMDljYTQ5YTFmNmNkZCIKICAgIH0KICB9Cn0=" - ) - ); - put( - "family_scary_jerry", - Utils.createSkull( - EnumChatFormatting.AQUA + "§a§6Scary Jerry", - "127e3dec-4ab7-3798-9410-5fce3f227632", - "ewogICJ0aW1lc3RhbXAiIDogMTYwMzczMzU4OTcxOSwKICAicHJvZmlsZUlkIiA6ICJhMmY4MzQ1OTVjODk0YTI3YWRkMzA0OTcxNmNhOTEwYyIsCiAgInByb2ZpbGVOYW1lIiA6ICJiUHVuY2giLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGYyMDJkYzI0ZDE1ZjdjZTM2ZTAyZmI0YjNlODE1M2IxNDZhYjljMTcyNGFhYTVkNDg0Yzc0MWRhMGVlYjZmZCIKICAgIH0KICB9Cn0=" - ) - ); - put( - "family_trick_or_treater", - Utils.createSkull( - EnumChatFormatting.AQUA + "§a§eTrick or Treater", - "79dd9434-1fde-3aac-87a7-bb09d91eba77", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDdjYmUwNjFiNDQ1Yjg4Y2IyZGY1OWFjY2M4ZDJjMWMxMjExOGZlMGIyMTI3ZTZlNzU4MTM1NTBhZGFjNjdjZiJ9fX0=" - ) - ); - put( - "family_wither_gourd", - Utils.createSkull( - EnumChatFormatting.AQUA + "§a§6Wither Gourd", - "3263c14e-c555-365e-a244-0ee97a8b2056", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjhmMmZmYzZmYjRlOTk1OWI5YTdhMzE3ZjUxYTY3NzVhMTU5ZGRjMjI0MWRiZDZjNzc0ZDNhYzA4YjYifX19" - ) - ); - put( - "family_wraith", - Utils.createSkull( - EnumChatFormatting.AQUA + "§a§8Wraith", - "bca22b11-8e4c-386a-8824-7b2bd6364cde", - "ewogICJ0aW1lc3RhbXAiIDogMTYwMzczMzcxNjI0MiwKICAicHJvZmlsZUlkIiA6ICJhMmY4MzQ1OTVjODk0YTI3YWRkMzA0OTcxNmNhOTEwYyIsCiAgInByb2ZpbGVOYW1lIiA6ICJiUHVuY2giLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWVhYmMzMDc1Y2Y0MWYzOGU2ZGYxMjM2Yjk1Y2FhZmNiYTFiZWUyMmM0OWQ4MDRiOTQyNzQ4OGMyZjZlMGVmYyIKICAgIH0KICB9Cn0=" - ) - ); - - // Dungeons - put( - "family_diamond_guy", - Utils.createSkull( - EnumChatFormatting.AQUA + "§a§d§lAngry Archeologist", - "db784d7a-fae1-3d60-9a5a-42a1814037f8", - "eyJ0aW1lc3RhbXAiOjE1NzU0NzAzOTQwMzEsInByb2ZpbGVJZCI6IjdkYTJhYjNhOTNjYTQ4ZWU4MzA0OGFmYzNiODBlNjhlIiwicHJvZmlsZU5hbWUiOiJHb2xkYXBmZWwiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2M0OGM3ODM0NThlNGNmODUxOGU4YWI1ODYzZmJjNGNiOTQ4ZjkwNTY4ZWViOWE2MGQxNmM0ZmRlMmI5NmMwMzMifX19" - ) - ); - put( - "family_cellar_spider", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aCellar Spider", - "a8aee72d-0d1d-3db7-8cf8-be1ce6ec2dc4", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDE2NDVkZmQ3N2QwOTkyMzEwN2IzNDk2ZTk0ZWViNWMzMDMyOWY5N2VmYzk2ZWQ3NmUyMjZlOTgyMjQifX19" - ) - ); - put( - "family_crypt_dreadlord", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aCrypt Dreadlord", - "68b4c885-7447-3382-b86b-b661b464d76e", - "eyJ0aW1lc3RhbXAiOjE1NjI0Mjc0MTA5MTQsInByb2ZpbGVJZCI6ImIwZDczMmZlMDBmNzQwN2U5ZTdmNzQ2MzAxY2Q5OGNhIiwicHJvZmlsZU5hbWUiOiJPUHBscyIsInNpZ25hdHVyZVJlcXVpcmVkIjp0cnVlLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjZmMzQ5MjcwYTNiODUxODk2Y2RhZDg0MmY1ZWVjNmUxNDBiZDkxMTliNzVjMDc0OTU1YzNiZTc4NjVlMjdjNyJ9fX0=" - ) - ); - put( - "family_crypt_lurker", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aCrypt Lurker", - "9673d491-d589-44cb-b63e-5f8b3148b3df", - "ewogICJ0aW1lc3RhbXAiIDogMTY0Njc1NjU2MzM1MiwKICAicHJvZmlsZUlkIiA6ICJkYmQ4MDQ2M2EwMzY0Y2FjYjI3OGNhODBhMDBkZGIxMyIsCiAgInByb2ZpbGVOYW1lIiA6ICJ4bG9nMjEiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjM2NjZkMWJkZjQ1NThiMGQxNjk5MGIyNDFlODE4NWNiZjU4YzNlMDNjMjRkOTA0NTQ0ZThjYzY1YjFjMzhkMSIKICAgIH0KICB9Cn0=\", \"n8vct7fj3NdiODy/h6PJhjxSR2U7d8gQxHjdVq553HqG60SSczt1Tl9XhvQbZP14ZrJGWxCziauuYb/HjZza0ugNAhfwh9z8hqR1PjBJGdvp+wpxoWpP2wd5RT9i5/GYEqpiAIAt9vHY1YeyejFqKZhXaGgp7gZZNjOQWQqB0SZzTUTAPzRW9FiY8x2re7H7Y1POThRXOvvkeQ6qWdPV6Hk5hTumV0rfEGm971jQRIbfdzBZDJRcro+8y+dlje/NpF5qf0JLy78Xr4hc2cwbT9+wqOeoUTcM/r9mwL15OKgFLjB44jszauKRHNfoqb6B3+1fNQEJrJK/7hIyvswpde7C5uOxkE7oMFib6X68VVEhb6PGC1+HWNaMaGjI0wWEkCahp48ihN9+sBEBFXOxIAhXG/pvJcbEi742/cBS1CTtOI8qui6JSL9MKX5jmyhtjjibOYRZbacosqayCnwsJAdMmwS7zIxc8jGhpfKECiSni/baS4zRla0bns4hfEM0l7ASv0Dh99WQD0We2ZMqltmix8lMEaAILXJVBln3CFrjYvncfku2hrSaqu1lNAtfMYYSITEUCBJ7McVAVmUHOrER0XGoVs9L237H0BQNSLqlGGEQ7OM8HV6G0YfXGlbNgNBx6O9k8ZijuK60JeEoJapcmbNj/LVHEU+dsgcFAbo=" - ) - ); - put( - "family_crypt_souleater", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aCrypt Souleater", - "68b4c885-7447-3382-b86b-b661b464d76e", - "eyJ0aW1lc3RhbXAiOjE1NjI0Mjc0MTA5MTQsInByb2ZpbGVJZCI6ImIwZDczMmZlMDBmNzQwN2U5ZTdmNzQ2MzAxY2Q5OGNhIiwicHJvZmlsZU5hbWUiOiJPUHBscyIsInNpZ25hdHVyZVJlcXVpcmVkIjp0cnVlLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjZmMzQ5MjcwYTNiODUxODk2Y2RhZDg0MmY1ZWVjNmUxNDBiZDkxMTliNzVjMDc0OTU1YzNiZTc4NjVlMjdjNyJ9fX0=" - ) - ); - put( - "family_king_midas", - Utils.createSkull( - EnumChatFormatting.AQUA + "§a§d§lKing Midas", - "1a85d923-f8dd-35b8-899a-8f13b9469b0c", - "ewogICJ0aW1lc3RhbXAiIDogMTU5MTU3NjA3MDMwMCwKICAicHJvZmlsZUlkIiA6ICJkYTQ5OGFjNGU5Mzc0ZTVjYjYxMjdiMzgwODU1Nzk4MyIsCiAgInByb2ZpbGVOYW1lIiA6ICJOaXRyb2hvbGljXzIiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjJiY2EwODU3NTAwNDM1MDNmNWRmOWY3ZGVmODI0YTJlM2FjZmMyNzg0MmJjZDA5ZDJiNjY5NTg4MWU4MzJmNSIKICAgIH0KICB9Cn0=" - ) - ); - put( - "family_lonely_spider", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aLonely Spider", - "7c63f3cf-a963-311a-aeca-3a075b417806", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2Q1NDE1NDFkYWFmZjUwODk2Y2QyNThiZGJkZDRjZjgwYzNiYTgxNjczNTcyNjA3OGJmZTM5MzkyN2U1N2YxIn19fQ==" - ) - ); - put( - "family_lost_adventurer", - Utils.createSkull( - EnumChatFormatting.AQUA + "§a§d§lLost Adventurer", - "f69ba621-a8b6-31a7-8de1-dc7ade140e1d", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHBzOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzFlMDMyOWY0MjE5MmVlN2MxYTBjNzA0ZjgyZGJiYmU3YzAwZmJmYTNmMDIwYzEwNjdhMjA4NjMwYjk5MWI5ODgifX19" - ) - ); - put( - "family_scared_skeleton", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aScared Skeleton", - "53924f1a-87e6-4709-8e53-f1c7d13dc239", - "ewogICJ0aW1lc3RhbXAiIDogMTY1NTYzMTgzNjcwNCwKICAicHJvZmlsZUlkIiA6ICI1MzkyNGYxYTg3ZTY0NzA5OGU1M2YxYzdkMTNkYzIzOSIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaHJvd3BvIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzg4ZWI2OGE0ZDM4ZTlmNDQ2YjhlOTkyNzVmMTYwMzAyZjM2NmVmMTAyMTZhYmY5NDg0ODdlNTgyNTEyYmQwZjMiCiAgICB9CiAgfQp9=" - ) - ); - put( - "family_shadow_assassin", - Utils.createSkull( - EnumChatFormatting.AQUA + "§a§d§lShadow Assassin", - "ef18719c-db6a-3ffb-97ca-4ed764ce9464", - "ewogICJ0aW1lc3RhbXAiIDogMTU5MjI2ODE3MDkxMSwKICAicHJvZmlsZUlkIiA6ICJkYTQ5OGFjNGU5Mzc0ZTVjYjYxMjdiMzgwODU1Nzk4MyIsCiAgInByb2ZpbGVOYW1lIiA6ICJOaXRyb2hvbGljXzIiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzM5OWUwMGY0MDQ0MTFlNDY1ZDc0Mzg4ZGYxMzJkNTFmZTg2OGVjZjg2ZjFjMDczZmFmZmExZDkxNzJlYzBmMyIKICAgIH0KICB9Cn0=" - ) - ); - put( - "family_skeleton_grunt", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aSkeleton Grunt", - "dfed3415-919e-3358-b563-0abd0513f74c", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzA0NzE2NzdiMzdhZTg0MmMyYmQyMzJlMTZlZWI4NGQ1YTQ5MzIzMWVlY2VjMDcyZGEzOGJlMzEyN2RkNWM4In19fQ==" - ) - ); - put( - "family_skeleton_master", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aSkeleton Master", - "ce22e0d7-c78e-3c8d-907a-2368c927808c", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzRlOTVlMWI3ZGM4MmJhNzg0NWE2OGZjNmEzMTJmNGNkOTBlZTJmNmNjZTI2YTY4Yzg4YjA0YjEwNzJkODc5In19fQ==" - ) - ); - put( - "family_skeleton_soldier", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aSkeleton Soldier", - "cab75065-c896-338e-a399-c4a6da16d678", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjE5Njg4ZTBjMmYwNWFlYjk3OWQ2YTFiOGM5MTE5NTdiN2QzNjU3ZTE0YjU3YWY5M2M1ZWY2ZjZhNTk1NjlkZCJ9fX0=" - ) - ); - put( - "family_skeletor", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aSkeletor", - "49fcfb3e-da7e-3fda-b4f9-37df5ac8fbd3", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODlkMDc0YWQ5Yjk5NzE4NzllYjMyNWJkZGZmMzY3NWY3MjI0ODU2YmQ2ZDU2OWZjOGQ0ODNjMTMzZDczMDA1ZCJ9fX0K" - ) - ); - put( - "family_sniper_skeleton", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aSniper", - "848130dc-9c46-3818-a099-b429cb2f1d75", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjE4YzA3MWYwODBkYmE1MGE2MmE2MjYzZmY3MjRlZGMxNTdjZTRmYjQ4ODNjY2VmZjI0OTFkNWJiZGU4MzBjMSJ9fX0K" - ) - ); - put( - "family_super_archer", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aSuper Archer", - "8ebf155b-7b8f-386f-91f1-2e425db4230f", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGNhZTZkYjBiNTlhNjQzMDUwNzZkOTY2ZDhlN2I5YTk3YmU0NmRhZTNhODA3NzE0ZmE4NmQzNzg0OGY2In19fQ==" - ) - ); - put( - "family_super_tank_zombie", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aSuper Tank Zombie", - "9673d491-d589-44cb-b63e-5f8b3148b3df", - "ewogICJ0aW1lc3RhbXAiIDogMTY0Njc1NjU2MzM1MiwKICAicHJvZmlsZUlkIiA6ICJkYmQ4MDQ2M2EwMzY0Y2FjYjI3OGNhODBhMDBkZGIxMyIsCiAgInByb2ZpbGVOYW1lIiA6ICJ4bG9nMjEiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjM2NjZkMWJkZjQ1NThiMGQxNjk5MGIyNDFlODE4NWNiZjU4YzNlMDNjMjRkOTA0NTQ0ZThjYzY1YjFjMzhkMSIKICAgIH0KICB9Cn0=\", \"n8vct7fj3NdiODy/h6PJhjxSR2U7d8gQxHjdVq553HqG60SSczt1Tl9XhvQbZP14ZrJGWxCziauuYb/HjZza0ugNAhfwh9z8hqR1PjBJGdvp+wpxoWpP2wd5RT9i5/GYEqpiAIAt9vHY1YeyejFqKZhXaGgp7gZZNjOQWQqB0SZzTUTAPzRW9FiY8x2re7H7Y1POThRXOvvkeQ6qWdPV6Hk5hTumV0rfEGm971jQRIbfdzBZDJRcro+8y+dlje/NpF5qf0JLy78Xr4hc2cwbT9+wqOeoUTcM/r9mwL15OKgFLjB44jszauKRHNfoqb6B3+1fNQEJrJK/7hIyvswpde7C5uOxkE7oMFib6X68VVEhb6PGC1+HWNaMaGjI0wWEkCahp48ihN9+sBEBFXOxIAhXG/pvJcbEi742/cBS1CTtOI8qui6JSL9MKX5jmyhtjjibOYRZbacosqayCnwsJAdMmwS7zIxc8jGhpfKECiSni/baS4zRla0bns4hfEM0l7ASv0Dh99WQD0We2ZMqltmix8lMEaAILXJVBln3CFrjYvncfku2hrSaqu1lNAtfMYYSITEUCBJ7McVAVmUHOrER0XGoVs9L237H0BQNSLqlGGEQ7OM8HV6G0YfXGlbNgNBx6O9k8ZijuK60JeEoJapcmbNj/LVHEU+dsgcFAbo=" - ) - ); - put( - "family_crypt_tank_zombie", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aTank Zombie", - "9673d491-d589-44cb-b63e-5f8b3148b3df", - "ewogICJ0aW1lc3RhbXAiIDogMTY0Njc1NjU2MzM1MiwKICAicHJvZmlsZUlkIiA6ICJkYmQ4MDQ2M2EwMzY0Y2FjYjI3OGNhODBhMDBkZGIxMyIsCiAgInByb2ZpbGVOYW1lIiA6ICJ4bG9nMjEiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjM2NjZkMWJkZjQ1NThiMGQxNjk5MGIyNDFlODE4NWNiZjU4YzNlMDNjMjRkOTA0NTQ0ZThjYzY1YjFjMzhkMSIKICAgIH0KICB9Cn0=\", \"n8vct7fj3NdiODy/h6PJhjxSR2U7d8gQxHjdVq553HqG60SSczt1Tl9XhvQbZP14ZrJGWxCziauuYb/HjZza0ugNAhfwh9z8hqR1PjBJGdvp+wpxoWpP2wd5RT9i5/GYEqpiAIAt9vHY1YeyejFqKZhXaGgp7gZZNjOQWQqB0SZzTUTAPzRW9FiY8x2re7H7Y1POThRXOvvkeQ6qWdPV6Hk5hTumV0rfEGm971jQRIbfdzBZDJRcro+8y+dlje/NpF5qf0JLy78Xr4hc2cwbT9+wqOeoUTcM/r9mwL15OKgFLjB44jszauKRHNfoqb6B3+1fNQEJrJK/7hIyvswpde7C5uOxkE7oMFib6X68VVEhb6PGC1+HWNaMaGjI0wWEkCahp48ihN9+sBEBFXOxIAhXG/pvJcbEi742/cBS1CTtOI8qui6JSL9MKX5jmyhtjjibOYRZbacosqayCnwsJAdMmwS7zIxc8jGhpfKECiSni/baS4zRla0bns4hfEM0l7ASv0Dh99WQD0We2ZMqltmix8lMEaAILXJVBln3CFrjYvncfku2hrSaqu1lNAtfMYYSITEUCBJ7McVAVmUHOrER0XGoVs9L237H0BQNSLqlGGEQ7OM8HV6G0YfXGlbNgNBx6O9k8ZijuK60JeEoJapcmbNj/LVHEU+dsgcFAbo=" - ) - ); - put( - "family_watcher_summon_undead", - Utils.createSkull( - EnumChatFormatting.AQUA + "§a§4§lUndead", - "0ac53e90-4e60-388c-a754-092dd4578592", - "eyJ0aW1lc3RhbXAiOjE1ODYwNDAyMDM1NzMsInByb2ZpbGVJZCI6ImRhNDk4YWM0ZTkzNzRlNWNiNjEyN2IzODA4NTU3OTgzIiwicHJvZmlsZU5hbWUiOiJOaXRyb2hvbGljXzIiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2Y0NjI0YTlhOGM2OWNhMjA0NTA0YWJiMDQzZDQ3NDU2Y2Q5YjA5NzQ5YTM2MzU3NDYyMzAzZjI3NmEyMjlkNCJ9fX0=" - ) - ); - put( - "family_dungeon_respawning_skeleton", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aUndead Skeleton", - "53924f1a-87e6-4709-8e53-f1c7d13dc239", - "ewogICJ0aW1lc3RhbXAiIDogMTY1NTYzMTgzNjcwNCwKICAicHJvZmlsZUlkIiA6ICI1MzkyNGYxYTg3ZTY0NzA5OGU1M2YxYzdkMTNkYzIzOSIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaHJvd3BvIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzg4ZWI2OGE0ZDM4ZTlmNDQ2YjhlOTkyNzVmMTYwMzAyZjM2NmVmMTAyMTZhYmY5NDg0ODdlNTgyNTEyYmQwZjMiCiAgICB9CiAgfQp9=" - ) - ); - put( - "family_crypt_witherskeleton", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aWithermancer", - "d0e05de7-6067-454d-beae-c6d19d886191", - "ewogICJ0aW1lc3RhbXAiIDogMTY1NTYzMjg1MTE1NCwKICAicHJvZmlsZUlkIiA6ICJkMGUwNWRlNzYwNjc0NTRkYmVhZWM2ZDE5ZDg4NjE5MSIsCiAgInByb2ZpbGVOYW1lIiA6ICJNb3VsYmVycnkiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmNlMTU1MjI0ZWE0YmM0OWE4ZTkxOTA3MzdjYjA0MTdkOGE3YzM4YTAzN2Q4ZDAzODJkZGU0ODI5YzEwMzU5MCIsCiAgICAgICJtZXRhZGF0YSIgOiB7CiAgICAgICAgIm1vZGVsIiA6ICJzbGltIgogICAgICB9CiAgICB9CiAgfQp9" - ) - ); - put( - "family_zombie_commander", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aZombie Commander", - "9673d491-d589-44cb-b63e-5f8b3148b3df", - "ewogICJ0aW1lc3RhbXAiIDogMTY0Njc1NjU2MzM1MiwKICAicHJvZmlsZUlkIiA6ICJkYmQ4MDQ2M2EwMzY0Y2FjYjI3OGNhODBhMDBkZGIxMyIsCiAgInByb2ZpbGVOYW1lIiA6ICJ4bG9nMjEiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjM2NjZkMWJkZjQ1NThiMGQxNjk5MGIyNDFlODE4NWNiZjU4YzNlMDNjMjRkOTA0NTQ0ZThjYzY1YjFjMzhkMSIKICAgIH0KICB9Cn0=\", \"n8vct7fj3NdiODy/h6PJhjxSR2U7d8gQxHjdVq553HqG60SSczt1Tl9XhvQbZP14ZrJGWxCziauuYb/HjZza0ugNAhfwh9z8hqR1PjBJGdvp+wpxoWpP2wd5RT9i5/GYEqpiAIAt9vHY1YeyejFqKZhXaGgp7gZZNjOQWQqB0SZzTUTAPzRW9FiY8x2re7H7Y1POThRXOvvkeQ6qWdPV6Hk5hTumV0rfEGm971jQRIbfdzBZDJRcro+8y+dlje/NpF5qf0JLy78Xr4hc2cwbT9+wqOeoUTcM/r9mwL15OKgFLjB44jszauKRHNfoqb6B3+1fNQEJrJK/7hIyvswpde7C5uOxkE7oMFib6X68VVEhb6PGC1+HWNaMaGjI0wWEkCahp48ihN9+sBEBFXOxIAhXG/pvJcbEi742/cBS1CTtOI8qui6JSL9MKX5jmyhtjjibOYRZbacosqayCnwsJAdMmwS7zIxc8jGhpfKECiSni/baS4zRla0bns4hfEM0l7ASv0Dh99WQD0We2ZMqltmix8lMEaAILXJVBln3CFrjYvncfku2hrSaqu1lNAtfMYYSITEUCBJ7McVAVmUHOrER0XGoVs9L237H0BQNSLqlGGEQ7OM8HV6G0YfXGlbNgNBx6O9k8ZijuK60JeEoJapcmbNj/LVHEU+dsgcFAbo=" - ) - ); - put( - "family_zombie_grunt", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aZombie Grunt", - "9673d491-d589-44cb-b63e-5f8b3148b3df", - "ewogICJ0aW1lc3RhbXAiIDogMTY0Njc1NjU2MzM1MiwKICAicHJvZmlsZUlkIiA6ICJkYmQ4MDQ2M2EwMzY0Y2FjYjI3OGNhODBhMDBkZGIxMyIsCiAgInByb2ZpbGVOYW1lIiA6ICJ4bG9nMjEiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjM2NjZkMWJkZjQ1NThiMGQxNjk5MGIyNDFlODE4NWNiZjU4YzNlMDNjMjRkOTA0NTQ0ZThjYzY1YjFjMzhkMSIKICAgIH0KICB9Cn0=\", \"n8vct7fj3NdiODy/h6PJhjxSR2U7d8gQxHjdVq553HqG60SSczt1Tl9XhvQbZP14ZrJGWxCziauuYb/HjZza0ugNAhfwh9z8hqR1PjBJGdvp+wpxoWpP2wd5RT9i5/GYEqpiAIAt9vHY1YeyejFqKZhXaGgp7gZZNjOQWQqB0SZzTUTAPzRW9FiY8x2re7H7Y1POThRXOvvkeQ6qWdPV6Hk5hTumV0rfEGm971jQRIbfdzBZDJRcro+8y+dlje/NpF5qf0JLy78Xr4hc2cwbT9+wqOeoUTcM/r9mwL15OKgFLjB44jszauKRHNfoqb6B3+1fNQEJrJK/7hIyvswpde7C5uOxkE7oMFib6X68VVEhb6PGC1+HWNaMaGjI0wWEkCahp48ihN9+sBEBFXOxIAhXG/pvJcbEi742/cBS1CTtOI8qui6JSL9MKX5jmyhtjjibOYRZbacosqayCnwsJAdMmwS7zIxc8jGhpfKECiSni/baS4zRla0bns4hfEM0l7ASv0Dh99WQD0We2ZMqltmix8lMEaAILXJVBln3CFrjYvncfku2hrSaqu1lNAtfMYYSITEUCBJ7McVAVmUHOrER0XGoVs9L237H0BQNSLqlGGEQ7OM8HV6G0YfXGlbNgNBx6O9k8ZijuK60JeEoJapcmbNj/LVHEU+dsgcFAbo=" - ) - ); - put( - "family_zombie_knight", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aZombie Knight", - "34af9e21-dff4-3b94-9fb5-07816e41af75", - "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjVkMmYzMWJhMTYyZmU2MjcyZTgzMWFlZDE3ZjUzMjEzZGI2ZmExYzRjYmU0ZmM4MjdmMzk2M2NjOThiOSJ9fX0=" - ) - ); - put( - "family_zombie_soldier", - Utils.createSkull( - EnumChatFormatting.AQUA + "§aZombie Soldier", - "9673d491-d589-44cb-b63e-5f8b3148b3df", - "ewogICJ0aW1lc3RhbXAiIDogMTY0Njc1NjU2MzM1MiwKICAicHJvZmlsZUlkIiA6ICJkYmQ4MDQ2M2EwMzY0Y2FjYjI3OGNhODBhMDBkZGIxMyIsCiAgInByb2ZpbGVOYW1lIiA6ICJ4bG9nMjEiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjM2NjZkMWJkZjQ1NThiMGQxNjk5MGIyNDFlODE4NWNiZjU4YzNlMDNjMjRkOTA0NTQ0ZThjYzY1YjFjMzhkMSIKICAgIH0KICB9Cn0=\", \"n8vct7fj3NdiODy/h6PJhjxSR2U7d8gQxHjdVq553HqG60SSczt1Tl9XhvQbZP14ZrJGWxCziauuYb/HjZza0ugNAhfwh9z8hqR1PjBJGdvp+wpxoWpP2wd5RT9i5/GYEqpiAIAt9vHY1YeyejFqKZhXaGgp7gZZNjOQWQqB0SZzTUTAPzRW9FiY8x2re7H7Y1POThRXOvvkeQ6qWdPV6Hk5hTumV0rfEGm971jQRIbfdzBZDJRcro+8y+dlje/NpF5qf0JLy78Xr4hc2cwbT9+wqOeoUTcM/r9mwL15OKgFLjB44jszauKRHNfoqb6B3+1fNQEJrJK/7hIyvswpde7C5uOxkE7oMFib6X68VVEhb6PGC1+HWNaMaGjI0wWEkCahp48ihN9+sBEBFXOxIAhXG/pvJcbEi742/cBS1CTtOI8qui6JSL9MKX5jmyhtjjibOYRZbacosqayCnwsJAdMmwS7zIxc8jGhpfKECiSni/baS4zRla0bns4hfEM0l7ASv0Dh99WQD0We2ZMqltmix8lMEaAILXJVBln3CFrjYvncfku2hrSaqu1lNAtfMYYSITEUCBJ7McVAVmUHOrER0XGoVs9L237H0BQNSLqlGGEQ7OM8HV6G0YfXGlbNgNBx6O9k8ZijuK60JeEoJapcmbNj/LVHEU+dsgcFAbo=" - ) - ); - } - }; - private static final LinkedHashMap<String, String> mobTypeMap = new LinkedHashMap<String, String>() { - { - // Island - put("family_cave_spider", "ISLAND"); - put("family_enderman_private", "ISLAND"); - put("family_skeleton", "ISLAND"); - put("family_slime", "ISLAND"); - put("family_spider", "ISLAND"); - put("family_witch", "ISLAND"); - put("family_zombie", "ISLAND"); - - // Hub - put("family_unburried_zombie", "MOB"); - put("family_old_wolf", "MOB"); - put("family_ruin_wolf", "MOB"); - put("family_zombie_villager", "MOB"); - - // Spiders Den - put("family_arachne", "BOSS"); - put("family_arachne_brood", "MOB"); - put("family_arachne_keeper", "MOB"); - put("family_brood_mother_spider", "BOSS"); - put("family_dasher_spider", "MOB"); - put("family_respawning_skeleton", "MOB"); - put("family_random_slime", "MOB"); - put("family_spider_jockey", "MOB"); - put("family_splitter_spider", "MOB"); - put("family_voracious_spider", "MOB"); - put("family_weaver_spider", "MOB"); - - // The End - put("family_dragon", "BOSS"); - put("family_enderman", "MOB"); - put("family_endermite", "MOB"); - put("family_corrupted_protector", "BOSS"); - put("family_obsidian_wither", "MOB"); - put("family_voidling_extremist", "MOB"); - put("family_voidling_fanatic", "MOB"); - put("family_watcher", "MOB"); - put("family_zealot_enderman", "MOB"); - - // Crimson Isles - put("family_ashfang", "BOSS"); - put("family_barbarian_duke_x", "BOSS"); - put("family_bladesoul", "BOSS"); - put("family_blaze", "MOB"); - put("family_flaming_spider", "MOB"); - put("family_ghast", "MOB"); - put("family_mage_outlaw", "BOSS"); - put("family_magma_cube", "MOB"); - put("family_magma_boss", "BOSS"); - put("family_matcho", "MOB"); - put("family_charging_mushroom_cow", "MOB"); - put("family_pigman", "MOB"); - put("family_wither_skeleton", "MOB"); - put("family_wither_spectre", "MOB"); - - // Deep Caverns - put("family_automaton", "MOB"); - put("family_butterfly", "MOB"); - put("family_emerald_slime", "MOB"); - put("family_caverns_ghost", "MOB"); - put("family_goblin", "MOB"); - put("family_team_treasurite", "MOB"); - put("family_ice_walker", "MOB"); - put("family_lapis_zombie", "MOB"); - put("family_diamond_skeleton", "MOB"); - put("family_diamond_zombie", "MOB"); - put("family_redstone_pigman", "MOB"); - put("family_sludge", "MOB"); - put("family_invisible_creeper", "MOB"); - put("family_thyst", "MOB"); - put("family_treasure_hoarder", "MOB"); - put("family_worms", "MOB"); - put("family_yog", "MOB"); - - // The Park - put("family_howling_spirit", "MOB"); - put("family_pack_spirit", "MOB"); - put("family_soul_of_the_alpha", "MOB"); - - // Spooky - put("family_batty_witch", "MOB"); - put("family_headless_horseman", "BOSS"); - put("family_phantom_spirit", "MOB"); - put("family_scary_jerry", "MOB"); - put("family_trick_or_treater", "MOB"); - put("family_wither_gourd", "MOB"); - put("family_wraith", "MOB"); - - // Catacombs - put("family_diamond_guy", "MOB"); - put("family_cellar_spider", "MOB"); - put("family_crypt_dreadlord", "MOB"); - put("family_crypt_lurker", "MOB"); - put("family_crypt_souleater", "MOB"); - put("family_king_midas", "MOB"); - put("family_lonely_spider", "MOB"); - put("family_lost_adventurer", "MOB"); - put("family_scared_skeleton", "MOB"); - put("family_shadow_assassin", "MOB"); - put("family_skeleton_grunt", "MOB"); - put("family_skeleton_master", "MOB"); - put("family_skeleton_soldier", "MOB"); - put("family_skeletor", "MOB"); - put("family_sniper_skeleton", "MOB"); - put("family_super_archer", "MOB"); - put("family_super_tank_zombie", "MOB"); - put("family_crypt_tank_zombie", "MOB"); - put("family_watcher_summon_undead", "MOB"); - put("family_dungeon_respawning_skeleton", "MOB"); - put("family_crypt_witherskeleton", "MOB"); - put("family_zombie_commander", "MOB"); - put("family_zombie_grunt", "MOB"); - put("family_zombie_knight", "MOB"); - put("family_zombie_soldier", "MOB"); - } - }; - - public static LinkedHashMap<ItemStack, List<String>> getBestiaryLocations() { - return bestiaryLocations; - } - - public static LinkedHashMap<String, ItemStack> getBestiaryMobs() { - return bestiaryMobs; - } - - public static LinkedHashMap<String, String> getMobType() { - return mobTypeMap; - } -} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryData.kt b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryData.kt new file mode 100644 index 00000000..ff2d2288 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryData.kt @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2023 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * NotEnoughUpdates is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.profileviewer.bestiary + +import com.google.gson.JsonObject +import io.github.moulberry.notenoughupdates.util.Constants +import io.github.moulberry.notenoughupdates.util.ItemUtils +import io.github.moulberry.notenoughupdates.util.Utils + +object BestiaryData { + private val categoriesToParse = listOf( + "dynamic", + "hub", + "farming_1", + "combat_1", + "combat_3", + "crimson_isle", + "mining_2", + "mining_3", + "crystal_hollows", + "foraging_1", + "spooky_festival", + "mythological_creatures", + "jerry", + "kuudra", + "catacombs", + "fishing" + ) + + /** + * Calculates the sum of all individual tiers for this profile + * + * @param computedCategories List of parsed categories + * @see BestiaryPage.parseBestiaryData + */ + @JvmStatic + fun calculateTotalBestiaryLevel(computedCategories: List<Category>): Int { + var level = 0.0 + computedCategories.forEach { + level += countTotalLevels(it) + } + return level.toInt() - 1 + } + + private fun countTotalLevels(category: Category): Int { + var levels = 0 + for (mob in category.mobs) { + levels += mob.mobLevelData.level + } + category.subCategories.forEach { levels += countTotalLevels(it) } + return levels + } + + /** + * Checks if a user profile has migrated. + * + * @param profileInfo skyblock profile information + */ + fun hasMigrated(profileInfo: JsonObject): Boolean { + val bestiaryObject = profileInfo.getAsJsonObject("bestiary") ?: return false + + return (bestiaryObject.get("migration") ?: return false).asBoolean + } + + /** + * Parse the bestiary data for the profile. Categories are taken from the `constants/bestiary.json` repo file + * + * @param profileInfo the JsonObject containing the bestiary data + */ + @JvmStatic + fun parseBestiaryData(profileInfo: JsonObject): MutableList<Category> { + if (!hasMigrated(profileInfo) || Constants.BESTIARY == null) { + return mutableListOf() + } + + val parsedCategories = mutableListOf<Category>() + + val apiKills = profileInfo.getAsJsonObject("bestiary")!!.getAsJsonObject("kills") ?: return mutableListOf() + val apiDeaths = profileInfo.getAsJsonObject("bestiary").getAsJsonObject("deaths") + val killsMap: HashMap<String, Int> = HashMap() + for (entry in apiKills.entrySet()) { + killsMap[entry.key] = entry.value.asInt + } + val deathsMap: HashMap<String, Int> = HashMap() + for (entry in apiDeaths.entrySet()) { + deathsMap[entry.key] = entry.value.asInt + } + + for (categoryId in categoriesToParse) { + val categoryData = Constants.BESTIARY.getAsJsonObject(categoryId)!! + parsedCategories.add(parseCategory(categoryData, categoryId, killsMap, deathsMap)) + } + + return parsedCategories + } + + /** + * Parse one individual category, including potential subcategories + */ + private fun parseCategory( + categoryData: JsonObject, + categoryId: String, + killsMap: HashMap<String, Int>, + deathsMap: HashMap<String, Int> + ): Category { + val categoryName = categoryData["name"].asString + val computedMobs: MutableList<Mob> = mutableListOf() + val categoryIconData = categoryData["icon"].asJsonObject + + val categoryIcon = if (categoryIconData.has("skullOwner")) { + Utils.createSkull( + categoryName, categoryIconData["skullOwner"].asString, categoryIconData["texture"].asString + ) + } else { + ItemUtils.createItemStackFromId(categoryIconData["item"].asString, categoryName) + } + if (categoryData.has("hasSubcategories")) { // It must have some subcategories + val subCategories: MutableList<Category> = mutableListOf() + + val reserved = listOf("name", "icon", "hasSubcategories") + for (entry in categoryData.entrySet()) { + if (!reserved.contains(entry.key)) { + subCategories.add( + parseCategory( + entry.value.asJsonObject, + "${categoryId}_${entry.key}", + killsMap, + deathsMap + ) + ) + } + } + return Category(categoryId, categoryName, categoryIcon, emptyList(), subCategories) + } else { + val categoryMobs = categoryData["mobs"].asJsonArray.map { it.asJsonObject } + + for (mobData in categoryMobs) { + val mobName = mobData["name"].asString + val mobIcon = if (mobData.has("skullOwner")) { + Utils.createSkull( + mobName, mobData["skullOwner"].asString, mobData["texture"].asString + ) + } else { + ItemUtils.createItemStackFromId(mobData["item"].asString, mobName) + } + + val cap = mobData["cap"].asDouble + val bracket = mobData["bracket"].asInt + + var kills = 0.0 + var deaths = 0.0 + + // The mobs array contains the individual names returned by the API + val mobsArray = mobData["mobs"].asJsonArray.map { it.asString } + for (s in mobsArray) { + kills += killsMap.getOrDefault(s, 0) + deaths += deathsMap.getOrDefault(s, 0) + } + + val levelData = calculateLevel(bracket, kills, cap) + computedMobs.add(Mob(mobName, mobIcon, kills, deaths, levelData)) + } + return Category(categoryId, categoryName, categoryIcon, computedMobs, emptyList()) + } + } + + /** + * Calculates the level for a given mob + * + * @param bracket applicable bracket number + * @param kills number of kills the player has on that mob type + * @param cap maximum kill limit for the mob + */ + private fun calculateLevel(bracket: Int, kills: Double, cap: Double): MobLevelData { + val bracketData = + Constants.BESTIARY["brackets"].asJsonObject[bracket.toString()].asJsonArray.map { it.asDouble } + var maxLevel = false + + val effectiveKills = if (kills >= cap) { + maxLevel = true + cap + } else { + kills + } + + var level = 0 + for (requiredKills in bracketData) { + if (effectiveKills >= requiredKills) { + level++ + } else { + break + } + } + return MobLevelData(level, maxLevel) + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.java deleted file mode 100644 index 17cd6787..00000000 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (C) 2022 NotEnoughUpdates contributors - * - * This file is part of NotEnoughUpdates. - * - * NotEnoughUpdates is free software: you can redistribute it - * and/or modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * NotEnoughUpdates is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>. - */ - -package io.github.moulberry.notenoughupdates.profileviewer.bestiary; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import io.github.moulberry.notenoughupdates.core.util.StringUtils; -import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer; -import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewerPage; -import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer; -import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewerUtils; -import io.github.moulberry.notenoughupdates.profileviewer.SkyblockProfiles; -import io.github.moulberry.notenoughupdates.util.Constants; -import io.github.moulberry.notenoughupdates.util.Utils; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.ScaledResolution; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.RenderHelper; -import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumChatFormatting; -import net.minecraft.util.ResourceLocation; -import org.lwjgl.opengl.GL11; - -import java.awt.*; -import java.util.ArrayList; -import java.util.List; - -import static io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer.pv_elements; - -public class BestiaryPage extends GuiProfileViewerPage { - - private static final ResourceLocation BESTIARY_TEXTURE = new ResourceLocation("notenoughupdates:pv_bestiary_tab.png"); - private static final int XCOUNT = 7; - private static final int YCOUNT = 5; - private static final float XPADDING = (190 - XCOUNT * 20) / (float) (XCOUNT + 1); - private static final float YPADDING = (202 - YCOUNT * 20) / (float) (YCOUNT + 1); - private ItemStack selectedBestiaryLocation = null; - private List<String> tooltipToDisplay = null; - - public BestiaryPage(GuiProfileViewer instance) { - super(instance); - } - - @Override - public void drawPage(int mouseX, int mouseY, float partialTicks) { - int guiLeft = GuiProfileViewer.getGuiLeft(); - int guiTop = GuiProfileViewer.getGuiTop(); - - SkyblockProfiles.SkyblockProfile selectedProfile = getSelectedProfile(); - if (selectedProfile == null) { - return; - } - - JsonObject profileInfo = selectedProfile.getProfileJson(); - - int bestiarySize = BestiaryData.getBestiaryLocations().size(); - int bestiaryXSize = (int) (350f / (bestiarySize - 1 + 0.0000001f)); - - { - int yIndex = 0; - for (ItemStack stack : BestiaryData.getBestiaryLocations().keySet()) { - Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements); - if (mouseX > guiLeft + 30 + bestiaryXSize * yIndex && mouseX < guiLeft + 30 + bestiaryXSize * yIndex + 20) { - if (mouseY > guiTop + 10 && mouseY < guiTop + 10 + 20) { - tooltipToDisplay = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false); - } - } - if (stack == selectedBestiaryLocation) { - Utils.drawTexturedRect( - guiLeft + 30 + bestiaryXSize * yIndex, - guiTop + 10, - 20, - 20, - 20 / 256f, - 0, - 20 / 256f, - 0, - GL11.GL_NEAREST - ); - Utils.drawItemStack(stack, guiLeft + 32 + bestiaryXSize * yIndex, guiTop + 12); - } else { - Utils.drawTexturedRect( - guiLeft + 30 + bestiaryXSize * yIndex, - guiTop + 10, - 20, - 20, - 0, - 20 / 256f, - 0, - 20 / 256f, - GL11.GL_NEAREST - ); - Utils.drawItemStack(stack, guiLeft + 32 + bestiaryXSize * yIndex, guiTop + 12); - } - yIndex++; - } - } - ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); - int width = scaledResolution.getScaledWidth(); - int height = scaledResolution.getScaledHeight(); - - Minecraft.getMinecraft().getTextureManager().bindTexture(BESTIARY_TEXTURE); - Utils.drawTexturedRect(guiLeft, guiTop, 431, 202, GL11.GL_NEAREST); - - GlStateManager.color(1, 1, 1, 1); - Color color = new Color(128, 128, 128, 255); - Utils.renderAlignedString( - EnumChatFormatting.RED + "Bestiary Level: ", - EnumChatFormatting.GRAY + "" + (float) getSelectedProfile().getBestiaryLevel() / 10, - guiLeft + 220, - guiTop + 50, - 110 - ); - - GlStateManager.disableLighting(); - RenderHelper.enableGUIStandardItemLighting(); - List<String> mobs = BestiaryData.getBestiaryLocations().get(selectedBestiaryLocation); - if (mobs != null) { - for (int i = 0; i < mobs.size(); i++) { - String mob = mobs.get(i); - if (mob != null) { - ItemStack mobItem = BestiaryData.getBestiaryMobs().get(mob); - if (mobItem != null) { - int xIndex = i % XCOUNT; - int yIndex = i / XCOUNT; - - float x = 23 + XPADDING + (XPADDING + 20) * xIndex; - float y = 30 + YPADDING + (YPADDING + 20) * yIndex; - - float completedness = 0; - - GlStateManager.color(1, 1, 1, 1); - Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements); - Utils.drawTexturedRect( - guiLeft + x, - guiTop + y, - 20, - 20 * (1 - completedness), - 0, - 20 / 256f, - 0, - 20 * (1 - completedness) / 256f, - GL11.GL_NEAREST - ); - //GlStateManager.color(1, 185 / 255f, 0, 1); - Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements); - Utils.drawTexturedRect( - guiLeft + x, - guiTop + y + 20 * (1 - completedness), - 20, - 20 * (completedness), - 0, - 20 / 256f, - 20 * (1 - completedness) / 256f, - 20 / 256f, - GL11.GL_NEAREST - ); - Utils.drawItemStack(mobItem, guiLeft + (int) x + 2, guiTop + (int) y + 2); - float kills = Utils.getElementAsFloat(Utils.getElement(profileInfo, "bestiary.kills_" + mob), 0); - float deaths = Utils.getElementAsFloat(Utils.getElement(profileInfo, "bestiary.deaths_" + mob), 0); - - String type; - if (BestiaryData.getMobType().get(mob) != null) { - type = BestiaryData.getMobType().get(mob); - } else { - type = "MOB"; - } - JsonObject leveling = Constants.LEVELING; - ProfileViewer.Level level = null; - if (leveling != null && Utils.getElement(leveling, "bestiary." + type) != null) { - JsonArray levelingArray = Utils.getElement(leveling, "bestiary." + type).getAsJsonArray(); - int levelCap = Utils.getElementAsInt(Utils.getElement(leveling, "bestiary.caps." + type), 0); - level = ProfileViewerUtils.getLevel(levelingArray, kills, levelCap, false); - } else { - Utils.showOutdatedRepoNotification(); - } - - float levelNum = -1; - if (level != null) { - levelNum = level.level; - } - if (mouseX > guiLeft + (int) x + 2 && mouseX < guiLeft + (int) x + 18) { - if (mouseY > guiTop + (int) y + 2 && mouseY < guiTop + (int) y + 18) { - tooltipToDisplay = new ArrayList<>(); - tooltipToDisplay.add( - mobItem.getDisplayName() + " " + ((levelNum == -1) ? "?" : (int) Math.floor(levelNum)) - ); - tooltipToDisplay.add( - EnumChatFormatting.GRAY + "Kills: " + EnumChatFormatting.GREEN + StringUtils.formatNumber(kills) - ); - tooltipToDisplay.add( - EnumChatFormatting.GRAY + "Deaths: " + EnumChatFormatting.GREEN + StringUtils.formatNumber(deaths) - ); - if (level != null) { - String progressStr; - if (level.maxed) { - progressStr = EnumChatFormatting.GOLD + "MAXED!"; - } else { - progressStr = EnumChatFormatting.AQUA + - StringUtils.shortNumberFormat(Math.round((levelNum % 1) * level.maxXpForLevel)) + - "/" + - StringUtils.shortNumberFormat(level.maxXpForLevel); - } - tooltipToDisplay.add(EnumChatFormatting.GRAY + "Progress: " + progressStr); - } - } - } - - GlStateManager.color(1, 1, 1, 1); - // if (tier >= 0) { - // Utils.drawStringCentered(tierString, - // guiLeft + x + 10, guiTop + y - 4, true, - // tierStringColour - // ); - // } - Utils.drawStringCentered( - (int) Math.floor(levelNum) + "", - guiLeft + x + 10, guiTop + y + 26, true, color.getRGB() - ); - } - } - } - } - if (tooltipToDisplay != null) { - List<String> grayTooltip = new ArrayList<>(tooltipToDisplay.size()); - for (String line : tooltipToDisplay) { - grayTooltip.add(EnumChatFormatting.GRAY + line); - } - Utils.drawHoveringText(grayTooltip, mouseX, mouseY, width, height, -1); - tooltipToDisplay = null; - } - } - - @Override - public void mouseReleased(int mouseX, int mouseY, int mouseButton) { - int guiLeft = GuiProfileViewer.getGuiLeft(); - int guiTop = GuiProfileViewer.getGuiTop(); - - int bestiarySize = BestiaryData.getBestiaryLocations().size(); - int bestiaryYSize = (int) (350f / (bestiarySize - 1 + 0.0000001f)); - int yIndex = 0; - for (ItemStack stack : BestiaryData.getBestiaryLocations().keySet()) { - if (mouseX > guiLeft + 30 + bestiaryYSize * yIndex && mouseX < guiLeft + 30 + bestiaryYSize * yIndex + 20) { - if (mouseY > guiTop + 10 && mouseY < guiTop + 10 + 20) { - selectedBestiaryLocation = stack; - Utils.playPressSound(); - return; - } - } - yIndex++; - } - } -} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.kt b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.kt new file mode 100644 index 00000000..ea5a576b --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.kt @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2022-2023 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * NotEnoughUpdates is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>. + */ +package io.github.moulberry.notenoughupdates.profileviewer.bestiary + +import io.github.moulberry.notenoughupdates.core.util.StringUtils +import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer +import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewerPage +import io.github.moulberry.notenoughupdates.profileviewer.bestiary.BestiaryData.calculateTotalBestiaryLevel +import io.github.moulberry.notenoughupdates.profileviewer.bestiary.BestiaryData.hasMigrated +import io.github.moulberry.notenoughupdates.profileviewer.bestiary.BestiaryData.parseBestiaryData +import io.github.moulberry.notenoughupdates.util.Constants +import io.github.moulberry.notenoughupdates.util.Utils +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.ScaledResolution +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.client.renderer.RenderHelper +import net.minecraft.item.ItemStack +import net.minecraft.util.EnumChatFormatting +import net.minecraft.util.ResourceLocation +import org.lwjgl.input.Mouse +import org.lwjgl.opengl.GL11 +import java.awt.Color + +/** + * Individual mob entry in the Bestiary + */ +data class Mob( + val name: String, val icon: ItemStack, val kills: Double, val deaths: Double, val mobLevelData: MobLevelData +) + +/** + * A Bestiary category as defined in `constants/bestiary.json` + */ +data class Category( + val id: String, val name: String, val icon: ItemStack, val mobs: List<Mob>, val subCategories: List<Category> +) + +/** + * Level data for one specific mob + */ +data class MobLevelData(val level: Int, val maxLevel: Boolean) + +class BestiaryPage(instance: GuiProfileViewer?) : GuiProfileViewerPage(instance) { + private var selectedCategory = "dynamic" + private var lastSelectedCategory = "" + private var selectedSubCategory = "" + private var tooltipToDisplay: MutableList<String> = mutableListOf() + private var bestiaryLevel = 0 + private var computedCategories: MutableList<Category> = mutableListOf() + + private val bestiaryTexture = ResourceLocation("notenoughupdates:pv_bestiary_tab.png") + private val mobListXCount = 9 + private val mobListYCount = 5 + private val mobListXPadding = (240 - mobListXCount * 20) / (mobListXCount + 1).toFloat() + private val mobListYPadding = (202 - mobListYCount * 20) / (mobListYCount + 1).toFloat() + + override fun drawPage(mouseX: Int, mouseY: Int, partialTicks: Float) { + val guiLeft = GuiProfileViewer.getGuiLeft() + val guiTop = GuiProfileViewer.getGuiTop() + + val selectedProfile = selectedProfile ?: return + val profileInfo = selectedProfile.profileJson + + if (!hasMigrated(profileInfo) || Constants.BESTIARY == null) { + Utils.drawStringCentered( + "${EnumChatFormatting.RED}No valid bestiary data!", + guiLeft + 431 / 2f, + (guiTop + 101).toFloat(), + true, + 0 + ) + return + } + // Do the initial parsing only once + if (computedCategories.isEmpty()) { + computedCategories = parseBestiaryData(profileInfo) + bestiaryLevel = calculateTotalBestiaryLevel(computedCategories) + } + val bestiarySize = computedCategories.size + val bestiaryXSize = (350f / (bestiarySize - 1 + 0.0000001f)).toInt() + + + // Render the category list + for ((categoryXIndex, category) in computedCategories.withIndex()) { + Minecraft.getMinecraft().textureManager.bindTexture(GuiProfileViewer.pv_elements) + + if (mouseX > guiLeft + 30 + bestiaryXSize * categoryXIndex && + mouseX < guiLeft + 30 + bestiaryXSize * categoryXIndex + 20 + && mouseY > guiTop + 10 && mouseY < guiTop + 10 + 20 + ) { + tooltipToDisplay = category.icon.getTooltip(Minecraft.getMinecraft().thePlayer, false) + if (Mouse.getEventButtonState() && selectedCategory != category.id) { + selectedCategory = category.id + Utils.playPressSound() + } + } + + + if (category.id == selectedCategory) { + Utils.drawTexturedRect( + (guiLeft + 30 + bestiaryXSize * categoryXIndex).toFloat(), + (guiTop + 10).toFloat(), + 20f, + 20f, + 20 / 256f, + 0f, + 20 / 256f, + 0f, + GL11.GL_NEAREST + ) + } else { + Utils.drawTexturedRect( + (guiLeft + 30 + bestiaryXSize * categoryXIndex).toFloat(), + (guiTop + 10).toFloat(), + 20f, + 20f, + 0f, + 20 / 256f, + 0f, + 20 / 256f, + GL11.GL_NEAREST + ) + } + Utils.drawItemStack(category.icon, guiLeft + 32 + bestiaryXSize * categoryXIndex, guiTop + 12) + } + + val scaledResolution = ScaledResolution(Minecraft.getMinecraft()) + val width = scaledResolution.scaledWidth + val height = scaledResolution.scaledHeight + + Minecraft.getMinecraft().textureManager.bindTexture(bestiaryTexture) + Utils.drawTexturedRect(guiLeft.toFloat(), guiTop.toFloat(), 431f, 202f, GL11.GL_NEAREST) + GlStateManager.color(1f, 1f, 1f, 1f) + val color = Color(128, 128, 128, 255) + Utils.renderAlignedString( + EnumChatFormatting.RED.toString() + "Milestone: ", + "${EnumChatFormatting.GRAY}${(bestiaryLevel / 10) - 1}", + (guiLeft + 280).toFloat(), + (guiTop + 50).toFloat(), + 110 + ) + + // Render the subcategories in the bottom right corner, if applicable + val selectedCategory = computedCategories.first { it.id == selectedCategory } + if (selectedCategory.subCategories.isNotEmpty()) { + if (selectedSubCategory == "") { + selectedSubCategory = selectedCategory.subCategories.first().id + } + + Utils.renderShadowedString( + "${EnumChatFormatting.RED}Subcategories", (guiLeft + 317).toFloat(), (guiTop + 165).toFloat(), 1000 + ) + GlStateManager.color(1f, 1f, 1f, 1f) + + val xStart = (guiLeft + 280).toFloat() + val y = (guiTop + 175).toFloat() + for ((i, subCategory) in selectedCategory.subCategories.withIndex()) { + Minecraft.getMinecraft().textureManager.bindTexture(GuiProfileViewer.pv_elements) + + if (subCategory.id == selectedSubCategory) { + Utils.drawTexturedRect( + (xStart + 24 * i.toFloat()), + y, + 20f, + 20f, + 20 / 256f, + 0f, + 20 / 256f, + 0f, + GL11.GL_NEAREST + ) + } else { + Utils.drawTexturedRect( + (xStart + 24 * i.toFloat()), + y, + 20f, + 20f, + 0f, + 20 / 256f, + 0f, + 20 / 256f, + GL11.GL_NEAREST + ) + } + Utils.drawItemStack(subCategory.icon, (xStart + 24 * i + 2).toInt(), y.toInt() + 2) + if (mouseX > xStart + 24 * i + && mouseX < xStart + 24 * (i + 1) + && mouseY > y + && mouseY < y + 16 + ) { + tooltipToDisplay.add(subCategory.name) + if (Mouse.getEventButtonState() && selectedSubCategory != subCategory.id) { + selectedSubCategory = subCategory.id + Utils.playPressSound() + } + } + } + } else { + selectedSubCategory = "" + } + + // Determine which mobs should be displayed + val mobs = if (selectedSubCategory != "") { + selectedCategory.subCategories.first { it.id == selectedSubCategory }.mobs + } else { + selectedCategory.mobs + } + + // Render the mob list + for ((i, mob) in mobs.withIndex()) { + val stack = mob.icon + val xIndex = i % mobListXCount + val yIndex = i / mobListXCount + val x = 23 + mobListXPadding + (mobListXPadding + 20) * xIndex + val y = 30 + mobListYPadding + (mobListYPadding + 20) * yIndex + val completedness = 0f + + GlStateManager.disableLighting() + RenderHelper.enableGUIStandardItemLighting() + GlStateManager.color(1f, 1f, 1f, 1f) + Minecraft.getMinecraft().textureManager.bindTexture(GuiProfileViewer.pv_elements) + Utils.drawTexturedRect( + guiLeft + x, + guiTop + y, + 20f, + 20 * (1 - completedness), + 0f, + 20 / 256f, + 0f, + 20 * (1 - completedness) / 256f, + GL11.GL_NEAREST + ) + //GlStateManager.color(1, 185 / 255f, 0, 1); + Minecraft.getMinecraft().textureManager.bindTexture(GuiProfileViewer.pv_elements) + Utils.drawTexturedRect( + guiLeft + x, + guiTop + y + 20 * (1 - completedness), + 20f, + 20 * completedness, + 0f, + 20 / 256f, + 20 * (1 - completedness) / 256f, + 20 / 256f, + GL11.GL_NEAREST + ) + Utils.drawItemStack(stack, guiLeft + x.toInt() + 2, guiTop + y.toInt() + 2) + val kills = mob.kills + val deaths = mob.deaths + + if (mouseX > guiLeft + x.toInt() + 2 && mouseX < guiLeft + x.toInt() + 18) { + if (mouseY > guiTop + y.toInt() + 2 && mouseY < guiTop + y.toInt() + 18) { + tooltipToDisplay = ArrayList() + tooltipToDisplay.add( + "${mob.name} ${mob.mobLevelData.level}" + ) + tooltipToDisplay.add( + EnumChatFormatting.GRAY.toString() + "Kills: " + EnumChatFormatting.GREEN + + StringUtils.formatNumber(kills) + ) + tooltipToDisplay.add( + EnumChatFormatting.GRAY.toString() + "Deaths: " + EnumChatFormatting.GREEN + + StringUtils.formatNumber(deaths) + ) + } + } + GlStateManager.color(1f, 1f, 1f, 1f) + Utils.drawStringCentered( + if (mob.mobLevelData.maxLevel) { + "${EnumChatFormatting.GOLD}${mob.mobLevelData.level}" + } else { + mob.mobLevelData.level.toString() + }, guiLeft + x + 10, guiTop + y + 26, true, color.rgb + ) + } + + // Render the accumulated tooltip, if applicable + if (tooltipToDisplay.isNotEmpty()) { + val grayTooltip: MutableList<String> = ArrayList(tooltipToDisplay.size) + for (line in tooltipToDisplay) { + grayTooltip.add(EnumChatFormatting.GRAY.toString() + line) + } + Utils.drawHoveringText(grayTooltip, mouseX, mouseY, width, height, -1) + tooltipToDisplay.clear() + } + } +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/MiscTaskLevel.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/MiscTaskLevel.java index 992b2609..291bf4cf 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/MiscTaskLevel.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/level/task/MiscTaskLevel.java @@ -166,12 +166,28 @@ public class MiscTaskLevel extends GuiTaskLevel { } int sbXpTimeCharm = 0; - if (object.has("rift") && - object.getAsJsonObject("rift").has("gallery") && - object.getAsJsonObject("rift").getAsJsonObject("gallery").has("secured_trophies")) { - JsonArray timeCharms = object.getAsJsonObject("rift").getAsJsonObject("gallery").getAsJsonArray( - "secured_trophies"); - sbXpTimeCharm += timeCharms.size() * miscellaneousTask.get("timecharm_xp").getAsInt(); + int sbXpBurger = 0; + if (object.has("rift")) { + JsonObject rift = object.getAsJsonObject("rift"); + if (rift.has("gallery") && + rift.getAsJsonObject("gallery").has("secured_trophies")) { + JsonArray timeCharms = rift.getAsJsonObject("gallery").getAsJsonArray( + "secured_trophies"); + sbXpTimeCharm += timeCharms.size() * miscellaneousTask.get("timecharm_xp").getAsInt(); + } + + + if (rift.has("castle") && rift.getAsJsonObject("castle").has("grubber_stacks") && miscellaneousTask.has("mcgrubber_burger_xp")) { + sbXpBurger = miscellaneousTask.get("mcgrubber_burger_xp").getAsInt() + * rift.getAsJsonObject("castle").get("grubber_stacks").getAsInt(); + } + } + + int sbXpSerum = 0; + if (object.has("experimentation") && + object.getAsJsonObject("experimentation").has("serums_drank") + && miscellaneousTask.has("metaphysical_serum_xp")) { + sbXpSerum = miscellaneousTask.get("metaphysical_serum_xp").getAsInt() * object.getAsJsonObject("experimentation").get("serums_drank").getAsInt(); } List<String> lore = new ArrayList<>(); @@ -179,8 +195,9 @@ public class MiscTaskLevel extends GuiTaskLevel { lore.add(levelPage.buildLore("Accessory Bag Upgrades", sbXpAccessoryUpgrade, 0, true )); - lore.add(levelPage.buildLore("Reaper Peppers", - sbXpReaperPeppers, miscellaneousTask.get("reaper_peppers").getAsInt(), false + int xpConsumableItems = sbXpReaperPeppers + sbXpBurger + sbXpSerum; + lore.add(levelPage.buildLore("Consumable Items", + xpConsumableItems, miscellaneousTask.get("consumable_items").getAsInt(), false )); lore.add(levelPage.buildLore("Timecharms", sbXpTimeCharm, miscellaneousTask.get("timecharm").getAsInt(), false @@ -208,8 +225,9 @@ public class MiscTaskLevel extends GuiTaskLevel { sbXpRelays, miscellaneousTask.get("unlocking_relays").getAsInt(), false )); - int totalXp = sbXpReaperPeppers + sbXpDojo + sbXpGainedHarp + sbXpAbiphone + - sbXpCommunityUpgrade + sbXpPersonalBank + sbXpTimeCharm + sbXpRelays; + + int totalXp =sbXpDojo + sbXpGainedHarp + sbXpAbiphone + + sbXpCommunityUpgrade + sbXpPersonalBank + sbXpTimeCharm + sbXpRelays + xpConsumableItems; levelPage.renderLevelBar( "Misc. Task", new ItemStack(Items.map), diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/rift/RiftPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/rift/RiftPage.java index bff6834c..9dc1ea8d 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/rift/RiftPage.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/rift/RiftPage.java @@ -121,7 +121,7 @@ public class RiftPage extends GuiProfileViewerPage { Utils.drawTexturedRect(guiLeft + 35, guiTop + 156, 20, 20, 0, 20 / 256f, 0, 20 / 256f, GL11.GL_NEAREST); JsonObject deadCats = riftData.getAsJsonObject("dead_cats"); - if (!deadCats.entrySet().isEmpty() && deadCats.has("found_cata")) { + if (!deadCats.entrySet().isEmpty() && deadCats.has("found_cats")) { JsonArray foundCats = deadCats.getAsJsonArray("found_cats"); int size = foundCats.size(); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java b/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java index e96043fa..9611f197 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java @@ -109,6 +109,7 @@ public class ApiUtil { } public void updateProfileData(String playerUuid) { + if (true) return; if (!updateTasks.getOrDefault(playerUuid, CompletableFuture.completedFuture(null)).isDone()) return; String uuid = Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java index 5f1cc247..c30f869e 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java @@ -83,6 +83,7 @@ public class Constants { public static JsonObject ESSENCESHOPS; public static JsonObject SBLEVELS; public static JsonObject MUSEUM; + public static JsonObject BESTIARY; private static final ReentrantLock lock = new ReentrantLock(); @@ -109,6 +110,7 @@ public class Constants { ESSENCESHOPS = Utils.getConstant("essenceshops", gson); SBLEVELS = Utils.getConstant("sblevels", gson); MUSEUM = Utils.getConstant("museum", gson); + BESTIARY = Utils.getConstant("bestiary", gson); parseEssenceCosts(); } catch (Exception ex) { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java index d10ae721..bdea26d5 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java @@ -29,6 +29,7 @@ import io.github.moulberry.notenoughupdates.core.util.StringUtils; import io.github.moulberry.notenoughupdates.listener.ItemTooltipListener; import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay; import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.JsonToNBT; import net.minecraft.nbt.NBTException; @@ -40,7 +41,6 @@ import net.minecraft.util.MathHelper; import java.nio.charset.StandardCharsets; import java.text.DecimalFormat; -import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; @@ -469,4 +469,15 @@ public class ItemUtils { return id; } + public static ItemStack createItemStackFromId(String id, String displayname) { + Item item = Item.getByNameOrId(id); + if (item == null) { + return null; + } + + ItemStack itemStack = new ItemStack(item); + itemStack.setStackDisplayName(displayname); + return itemStack; + } + } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/ProfileApiSyncer.java b/src/main/java/io/github/moulberry/notenoughupdates/util/ProfileApiSyncer.java index ed88a6a5..5a4e1c9e 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/ProfileApiSyncer.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/ProfileApiSyncer.java @@ -19,10 +19,7 @@ package io.github.moulberry.notenoughupdates.util; -import com.google.gson.JsonObject; -import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.profileviewer.SkyblockProfiles; -import net.minecraft.client.Minecraft; import java.util.HashMap; import java.util.function.Consumer; @@ -65,40 +62,4 @@ public class ProfileApiSyncer { } return time; } - - public void tick() { - if (Minecraft.getMinecraft().thePlayer == null) return; - - long resyncTime = getCurrentResyncTime(); - - if (resyncTime < 0) return; - - long currentTime = System.currentTimeMillis(); - - if (currentTime - lastResync > resyncTime) { - lastResync = currentTime; - resyncTimes.clear(); - - for (Runnable r : syncingCallbacks.values()) r.run(); - syncingCallbacks.clear(); - - forceResync(); - } - } - - private void forceResync() { - if (Minecraft.getMinecraft().thePlayer == null) return; - - String uuid = Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""); - NotEnoughUpdates.INSTANCE.manager.apiUtils - .newHypixelApiRequest("/skyblock/profiles") - .queryArgument("uuid", uuid) - .requestJson() - .thenAcceptAsync((profile) -> { - SkyblockProfiles skyblockProfiles = new SkyblockProfiles(NotEnoughUpdates.profileViewer, uuid); - for (Consumer<SkyblockProfiles> c : finishSyncCallbacks.values()) - c.accept((skyblockProfiles)); - finishSyncCallbacks.clear(); - }, MinecraftExecutor.OnThread); - } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/StarCultCalculator.java b/src/main/java/io/github/moulberry/notenoughupdates/util/StarCultCalculator.java index 4c4fe02d..fadfef40 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/StarCultCalculator.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/StarCultCalculator.java @@ -55,8 +55,32 @@ public class StarCultCalculator { private static long activeTill = 0; public static String getNextStarCult() { - Instant instantNow = Instant.now(); - long nowEpoch = instantNow.toEpochMilli(); + Instant cultStart = getNextStarCultTime(); + + long l = System.currentTimeMillis(); + if (cultStart.toEpochMilli() - l <= 1000) { + active = true; + activeTill = l + 300000; + } + + if (l > activeTill) { + active = false; + activeTill = 0; + } + + if (active && activeTill != 0) { + return "Active! (" + Utils.prettyTime(activeTill - System.currentTimeMillis()) + ")"; + } + + return Utils.prettyTime(cultStart.toEpochMilli() - l); + } + + public static Instant getNextStarCultTime() { + return getNextStarCultTime(Instant.now()); + } + + public static Instant getNextStarCultTime(Instant after) { + long nowEpoch = after.toEpochMilli(); long currentOffset = (nowEpoch - YEAR_0) % YEAR_MS; int currentMonth = (int) Math.floorDiv(currentOffset, MONTH_MS); @@ -72,7 +96,7 @@ public class StarCultCalculator { } Instant cultStart = Instant.ofEpochMilli( YEAR_0 + (getSkyblockYear() - 1) * YEAR_MS + currentMonth * MONTH_MS + (out - 1) * DAY_MS); - if (cultStart.isBefore(instantNow)) { + if (cultStart.isBefore(after)) { int curYearCult = getSkyblockYear() - 1; if (out == 28) { out = 7; @@ -88,23 +112,7 @@ public class StarCultCalculator { out--; cultStart = Instant.ofEpochMilli(YEAR_0 + (curYearCult) * YEAR_MS + currentMonth * MONTH_MS + out * DAY_MS); } - - long l = System.currentTimeMillis(); - if (cultStart.toEpochMilli() - l <= 1000) { - active = true; - activeTill = l + 300000; - } - - if (l > activeTill) { - active = false; - activeTill = 0; - } - - if (active && activeTill != 0) { - return "Active! (" + Utils.prettyTime(activeTill - System.currentTimeMillis()) + ")"; - } - - return Utils.prettyTime(cultStart.toEpochMilli() - l); + return cultStart; } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java index 052ea33f..847b9430 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java @@ -1571,6 +1571,13 @@ public class Utils { if (!prim.isNumber()) return def; return prim.getAsInt(); } + public static long getElementAsLong(JsonElement element, long def) { + if (element == null) return def; + if (!element.isJsonPrimitive()) return def; + JsonPrimitive prim = element.getAsJsonPrimitive(); + if (!prim.isNumber()) return def; + return prim.getAsLong(); + } public static String getElementAsString(JsonElement element, String def) { if (element == null) return def; @@ -1580,6 +1587,14 @@ public class Utils { return prim.getAsString(); } + public static boolean getElementAsBool(JsonElement element, boolean def) { + if (element == null) return def; + if (!element.isJsonPrimitive()) return def; + JsonPrimitive prim = element.getAsJsonPrimitive(); + if (!prim.isBoolean()) return def; + return prim.getAsBoolean(); + } + public static JsonElement getElement(JsonElement element, String path) { List<String> path_split = PATH_SPLITTER.splitToList(path); if (element instanceof JsonObject) { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/XPInformation.java b/src/main/java/io/github/moulberry/notenoughupdates/util/XPInformation.java index 0a501415..117545c9 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/XPInformation.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/XPInformation.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 NotEnoughUpdates contributors + * Copyright (C) 2022-2023 NotEnoughUpdates contributors * * This file is part of NotEnoughUpdates. * @@ -24,15 +24,12 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe; import io.github.moulberry.notenoughupdates.core.util.StringUtils; -import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer; -import io.github.moulberry.notenoughupdates.profileviewer.SkyblockProfiles; import net.minecraftforge.client.event.ClientChatReceivedEvent; import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -210,46 +207,4 @@ public class XPInformation { } updateWithPercentage.clear(); } - - public void tick() { - ProfileApiSyncer.getInstance().requestResync("xpinformation", 5 * 60 * 1000, - () -> { - }, this::onApiUpdated - ); - } - - private static final String[] skills = { - "taming", - "mining", - "foraging", - "enchanting", - "carpentry", - "farming", - "combat", - "fishing", - "alchemy", - "runecrafting" - }; - - private void onApiUpdated(SkyblockProfiles profile) { - Map<String, ProfileViewer.Level> skyblockInfo = profile.getLatestProfile().getLevelingInfo(); - if (skyblockInfo == null) { - return; - } - - for (String skill : skills) { - SkillInfo info = new SkillInfo(); - - ProfileViewer.Level levelInfo = skyblockInfo.get(skill); - float level = levelInfo.level; - - info.totalXp = levelInfo.totalXp; - info.currentXpMax = levelInfo.maxXpForLevel; - info.level = (int) level; - info.currentXp = (level % 1) * info.currentXpMax; - info.fromApi = true; - - skillInfoMap.put(skill.toLowerCase(), info); - } - } } diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/TabSkillInfoParser.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/TabSkillInfoParser.kt new file mode 100644 index 00000000..b4bfdf28 --- /dev/null +++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/TabSkillInfoParser.kt @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2023 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * NotEnoughUpdates is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>. + */ + +package io.github.moulberry.notenoughupdates.util + +import com.google.gson.JsonArray +import net.minecraft.util.EnumChatFormatting +import java.util.regex.Pattern +import kotlin.math.abs + +object TabSkillInfoParser { + private val skillTabPattern: Pattern = + Pattern.compile("^§r§e§lSkills: §r§a(?<type>\\w+) (?<level>\\d+): §r§3(?<progress>.+)%§r\$") + private val maxSkillTabPattern: Pattern = + Pattern.compile("^§r§e§lSkills: §r§a(?<type>\\w+) (?<level>\\d+): §r§c§lMAX§r\$") + private var sentErrorOnce = false + + private fun calculateLevelXp(levelingArray: JsonArray, level: Int): Double { + var totalXp = 0.0 + for (i in 0 until level + 1) { + val xp = levelingArray[i].asDouble + totalXp += xp + } + return totalXp + } + + private fun isWithinPercentageRange(xp: Double, existingXp: Double, percentage: Double): Boolean { + val diff = (abs(xp - existingXp) / existingXp) * 100 + return diff <= percentage + } + + private fun sendError(message: String) { + if (!sentErrorOnce) { + Utils.addChatMessage(message) + sentErrorOnce = true + } + } + + private fun levelArray(skillType: String) = + if (skillType == "runecrafting") Utils.getElement(Constants.LEVELING, "runecrafting_xp").asJsonArray + else Utils.getElement(Constants.LEVELING, "leveling_xp").asJsonArray + + @JvmStatic + fun parseSkillInfo() { + if (Constants.LEVELING == null) { + sendError("${EnumChatFormatting.RED}[NEU] There is an error with your repo, please report this in the discord at ${EnumChatFormatting.AQUA}discord.gg/moulberry") + return + } + + for (s in TabListUtils.getTabList()) { + val matcher = skillTabPattern.matcher(s) + val maxLevelMatcher = maxSkillTabPattern.matcher(s) + if (matcher.matches()) { + // All the groups are guaranteed to match + val name = matcher.group("type")!!.lowercase() + val level = matcher.group("level")!!.toInt() + val progress = matcher.group("progress")!!.toFloatOrNull() + if (progress == null) { + sendError("${EnumChatFormatting.RED}[NEU] Error while parsing skill level from tab list") + return + } + val levelingArray = levelArray(name) + val levelXp = calculateLevelXp(levelingArray, level - 1) + // This *should* not cause problems, since skills that are max Level won't be picked up + val nextLevelDiff = levelingArray[level].asDouble + val nextLevelProgress = nextLevelDiff * progress / 100 + + val totalXp = levelXp + nextLevelProgress + val existingLevel = XPInformation.getInstance().getSkillInfo(name) ?: XPInformation.SkillInfo() + + // Only update if the numbers are substantially different + if (!isWithinPercentageRange(totalXp, existingLevel.totalXp.toDouble(), 1.0)) { + existingLevel.level = level + existingLevel.totalXp = totalXp.toFloat() + existingLevel.currentXp = nextLevelProgress.toFloat() + existingLevel.currentXpMax = nextLevelDiff.toFloat() + XPInformation.getInstance().skillInfoMap[name] = existingLevel + } + + // There is only one skill at a time in the tab list + break + } else if (maxLevelMatcher.matches()) { + val name = maxLevelMatcher.group("type")!!.lowercase() + val level = maxLevelMatcher.group("level")!!.toInt() + + val existingLevel = XPInformation.getInstance().getSkillInfo(name) ?: XPInformation.SkillInfo() + if (existingLevel.level != level) { + existingLevel.level = level + val levelingArray = levelArray(name) + + val totalXp = calculateLevelXp(levelingArray, level - 1) + existingLevel.totalXp = totalXp.toFloat() + XPInformation.getInstance().skillInfoMap[name] = existingLevel + } + } + } + } +} |