diff options
Diffstat (limited to 'src/main/java/me/xmrvizzy')
17 files changed, 349 insertions, 219 deletions
diff --git a/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java b/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java index 577c87e4..127bc601 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java +++ b/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java @@ -435,7 +435,7 @@ public class SkyblockerConfig implements ConfigData { public int mapX = 2; public int mapY = 2; @ConfigEntry.Gui.Tooltip - public boolean starredMobGlow = false; + public boolean starredMobGlow = true; public boolean solveThreeWeirdos = true; @ConfigEntry.Gui.Tooltip public boolean blazesolver = true; diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/BatEntityMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/BatEntityMixin.java new file mode 100644 index 00000000..86c4e672 --- /dev/null +++ b/src/main/java/me/xmrvizzy/skyblocker/mixin/BatEntityMixin.java @@ -0,0 +1,22 @@ +package me.xmrvizzy.skyblocker.mixin; + +import me.xmrvizzy.skyblocker.skyblock.dungeon.secrets.DungeonSecrets; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.mob.AmbientEntity; +import net.minecraft.entity.passive.BatEntity; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(BatEntity.class) +public abstract class BatEntityMixin extends AmbientEntity { + protected BatEntityMixin(EntityType<? extends AmbientEntity> entityType, World world) { + super(entityType, world); + } + + @Override + public void onRemoved() { + super.onRemoved(); + DungeonSecrets.onBatRemoved(this); + } +} diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/TeleportOverlay.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/TeleportOverlay.java index f1d6e986..c7ab926e 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/TeleportOverlay.java +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/TeleportOverlay.java @@ -26,7 +26,7 @@ public class TeleportOverlay { private static void render(WorldRenderContext wrc) { if (Utils.isOnSkyblock() && SkyblockerConfig.get().general.teleportOverlay.enableTeleportOverlays && client.player != null && client.world != null) { ItemStack heldItem = client.player.getMainHandStack(); - String itemId = PriceInfoTooltip.getInternalNameFromNBT(heldItem); + String itemId = PriceInfoTooltip.getInternalNameFromNBT(heldItem, true); NbtCompound nbt = heldItem.getNbt(); if (itemId != null) { diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/CroesusHelper.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/CroesusHelper.java index 1e949cd1..bf3cc36d 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/CroesusHelper.java +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/CroesusHelper.java @@ -25,7 +25,7 @@ public class CroesusHelper extends ContainerSolver { List<ColorHighlight> highlights = new ArrayList<>(); for (Map.Entry<Integer, ItemStack> entry : slots.entrySet()) { ItemStack stack = entry.getValue(); - if (stack != null && stack.getNbt() != null && stack.getNbt().toString().contains("Opened Chest:")) { + if (stack != null && stack.getNbt() != null && (stack.getNbt().toString().contains("No more Chests to open!") || stack.getNbt().toString().contains("Opened Chest:"))) { highlights.add(ColorHighlight.gray(entry.getKey())); } } diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/StarredMobGlow.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/StarredMobGlow.java index 64a28712..f614662b 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/StarredMobGlow.java +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/StarredMobGlow.java @@ -1,51 +1,56 @@ package me.xmrvizzy.skyblocker.skyblock.dungeon; -import java.util.List; - import me.xmrvizzy.skyblocker.utils.Utils; import me.xmrvizzy.skyblocker.utils.render.culling.OcclusionCulling; import net.minecraft.entity.Entity; import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.entity.passive.BatEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.util.math.Box; +import java.util.List; + public class StarredMobGlow { public static boolean shouldMobGlow(Entity entity) { Box box = entity.getBoundingBox(); - + if (Utils.isInDungeons() && !entity.isInvisible() && OcclusionCulling.isVisible(box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ)) { - //Minibosses + // Minibosses if (entity instanceof PlayerEntity) { switch (entity.getName().getString()) { - case "Lost Adventurer": return true; - case "Shadow Assassin": return true; - case "Diamond Guy": return true; + case "Lost Adventurer", "Shadow Assassin", "Diamond Guy" -> { + return true; + } } } - - //Regular Mobs + + // Regular Mobs if (!(entity instanceof ArmorStandEntity)) { Box searchBox = box.expand(0, 2, 0); List<ArmorStandEntity> armorStands = entity.getWorld().getEntitiesByClass(ArmorStandEntity.class, searchBox, EntityPredicates.NOT_MOUNTED); - + if (!armorStands.isEmpty() && armorStands.get(0).getName().getString().contains("✯")) return true; } + + // Bats + return entity instanceof BatEntity; } - + return false; } - + public static int getGlowColor(Entity entity) { if (entity instanceof PlayerEntity) { - switch (entity.getName().getString()) { - case "Lost Adventurer": return 0xfee15c; - case "Shadow Assassin": return 0x5b2cb2; - case "Diamond Guy": return 0x57c2f7; - } + return switch (entity.getName().getString()) { + case "Lost Adventurer" -> 0xfee15c; + case "Shadow Assassin" -> 0x5b2cb2; + case "Diamond Guy" -> 0x57c2f7; + default -> 0xf57738; + }; } - + return 0xf57738; } } diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java index c916a5e4..a7420bf5 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java @@ -24,6 +24,8 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.mob.AmbientEntity; +import net.minecraft.entity.passive.BatEntity; import net.minecraft.item.FilledMapItem; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; @@ -348,7 +350,7 @@ public class DungeonSecrets { /** * Calls {@link Room#onItemPickup(ItemEntity, LivingEntity)} on the room the {@code collector} is in if that room {@link #isRoomMatched(Room)}. - * Used to detect finding {@link SecretWaypoint.Category.ITEM} and {@link SecretWaypoint.Category.BAT} secrets. + * Used to detect finding {@link SecretWaypoint.Category.ITEM} secrets. * If the collector is the player, {@link #currentRoom} is used as an optimization. */ @SuppressWarnings("JavadocReference") @@ -365,6 +367,18 @@ public class DungeonSecrets { } } + /** + * Calls {@link Room#onBatRemoved(BatEntity)} on the room the {@code bat} is in if that room {@link #isRoomMatched(Room)}. + * Used to detect finding {@link SecretWaypoint.Category.BAT} secrets. + */ + @SuppressWarnings("JavadocReference") + public static void onBatRemoved(AmbientEntity bat) { + Room room = getRoomAtPhysical(bat.getPos()); + if (isRoomMatched(room)) { + room.onBatRemoved(bat); + } + } + public static boolean markSecrets(int secretIndex, boolean found) { if (isCurrentRoomMatched()) { return currentRoom.markSecrets(secretIndex, found); diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/Room.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/Room.java index fc62150c..6825d779 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/Room.java +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/Room.java @@ -19,6 +19,7 @@ import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.mob.AmbientEntity; import net.minecraft.registry.Registries; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; @@ -374,7 +375,7 @@ public class Room { } /** - * Marks the closest secret no greater than 6 blocks away as found when the player picks up a secret item. + * Marks the closest secret that requires item pickup no greater than 6 blocks away as found when the player picks up a secret item. * * @param itemEntity the item entity being picked up * @param collector the collector of the item @@ -389,6 +390,17 @@ public class Room { } /** + * Marks the closest bat secret as found when a bat is killed. + * + * @param bat the bat being killed + * @see #onSecretFound(SecretWaypoint, String, Object...) + */ + protected void onBatRemoved(AmbientEntity bat) { + secretWaypoints.values().stream().filter(SecretWaypoint::isBat).min(Comparator.comparingDouble(SecretWaypoint.getSquaredDistanceToFunction(bat))) + .ifPresent(secretWaypoint -> onSecretFound(secretWaypoint, "[Skyblocker] Detected {} killed for a {} secret, setting secret #{} as found", bat.getName().getString(), secretWaypoint.category, secretWaypoint.secretIndex)); + } + + /** * Marks all secret waypoints with the same index as the given {@link SecretWaypoint} as found. * * @param secretWaypoint the secret waypoint to read the index from. diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java index edf18f85..3fdd683c 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java @@ -57,6 +57,10 @@ public class SecretWaypoint { return category.needsItemPickup(); } + boolean isBat() { + return category.isBat(); + } + void setFound() { this.missing = false; } @@ -122,7 +126,11 @@ public class SecretWaypoint { } boolean needsItemPickup() { - return this == ITEM || this == BAT; + return this == ITEM; + } + + boolean isBat() { + return this == BAT; } boolean isEnabled() { diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/PriceInfoTooltip.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/PriceInfoTooltip.java index dc2a89f8..84325042 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/PriceInfoTooltip.java +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/PriceInfoTooltip.java @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.zip.GZIPInputStream; @@ -48,8 +49,9 @@ public class PriceInfoTooltip { public static void onInjectTooltip(ItemStack stack, TooltipContext context, List<Text> lines) { if (!Utils.isOnSkyblock() || client.player == null) return; - String name = getInternalNameFromNBT(stack); - if (name == null) return; + String name = getInternalNameFromNBT(stack, false); + String internalID = getInternalNameFromNBT(stack, true); + if (name == null || internalID == null) return; int count = stack.getCount(); boolean bazaarOpened = lines.stream().anyMatch(each -> each.getString().contains("Buy price:") || each.getString().contains("Sell price:")); @@ -57,31 +59,29 @@ public class PriceInfoTooltip { if (SkyblockerConfig.get().general.itemTooltip.enableNPCPrice) { if (npcPricesJson == null) { nullWarning(); - } - else if (npcPricesJson.has(name)) { + } else if (npcPricesJson.has(internalID)) { lines.add(Text.literal(String.format("%-21s", "NPC Price:")) .formatted(Formatting.YELLOW) - .append(getCoinsMessage(npcPricesJson.get(name).getAsDouble(), count))); + .append(getCoinsMessage(npcPricesJson.get(internalID).getAsDouble(), count))); } } - + if (SkyblockerConfig.get().general.itemTooltip.enableMotesPrice && Utils.isInTheRift()) { - if(motesPricesJson == null) { - nullWarning(); - } - else if (motesPricesJson.has(name)) { - lines.add(Text.literal(String.format("%-20s", "Motes Price:")) - .formatted(Formatting.LIGHT_PURPLE) - .append(getMotesMessage(motesPricesJson.get(name).getAsInt(), count))); - } + if (motesPricesJson == null) { + nullWarning(); + } else if (motesPricesJson.has(internalID)) { + lines.add(Text.literal(String.format("%-20s", "Motes Price:")) + .formatted(Formatting.LIGHT_PURPLE) + .append(getMotesMessage(motesPricesJson.get(internalID).getAsInt(), count))); + } } boolean bazaarExist = false; + if (SkyblockerConfig.get().general.itemTooltip.enableBazaarPrice && !bazaarOpened) { if (bazaarPricesJson == null) { nullWarning(); - } - else if (bazaarPricesJson.has(name)) { + } else if (bazaarPricesJson.has(name)) { JsonObject getItem = bazaarPricesJson.getAsJsonObject(name); lines.add(Text.literal(String.format("%-18s", "Bazaar buy Price:")) .formatted(Formatting.GOLD) @@ -102,8 +102,7 @@ public class PriceInfoTooltip { if (SkyblockerConfig.get().general.itemTooltip.enableLowestBIN && !bazaarOpened && !bazaarExist) { if (lowestPricesJson == null) { nullWarning(); - } - else if (lowestPricesJson.has(name)) { + } else if (lowestPricesJson.has(name)) { lines.add(Text.literal(String.format("%-19s", "Lowest BIN Price:")) .formatted(Formatting.GOLD) .append(getCoinsMessage(lowestPricesJson.get(name).getAsDouble(), count))); @@ -114,28 +113,31 @@ public class PriceInfoTooltip { if (SkyblockerConfig.get().general.itemTooltip.enableAvgBIN) { if (threeDayAvgPricesJson == null || oneDayAvgPricesJson == null) { nullWarning(); - } - else { + } else { /* We are skipping check average prices for potions, runes and enchanted books because there is no data for their in API. */ - if (name.contains("PET-")) { - name = name.replace("PET-", "") - .replace("UNCOMMON", "1") - .replace("COMMON", "0") - .replace("RARE", "2") - .replace("EPIC", "3") - .replace("LEGENDARY", "4") - .replace("MYTHIC", "5") - .replace("-", ";"); - } else if (name.contains("RUNE-")) { - name = name.replace("RUNE-", ""); - name = name.substring(0, name.indexOf("-")) + "_RUNE;" + name.substring(name.lastIndexOf("-") + 1); - } else if (name.contains("POTION-") || name.contains("ENCHANTED_BOOK-")) { - name = ""; - } else { - name = name.replace(":", "-"); + switch (internalID) { + case "PET" -> { + name = name.replaceAll("LVL_\\d*_", ""); + String[] parts = name.split("_"); + String type = parts[0]; + name = name.replaceAll(type + "_", ""); + name = name + "-" + type; + name = name.replace("UNCOMMON", "1") + .replace("COMMON", "0") + .replace("RARE", "2") + .replace("EPIC", "3") + .replace("LEGENDARY", "4") + .replace("MYTHIC", "5") + .replace("-", ";"); + } + case "RUNE" -> name = name.replaceAll("_(?!.*_)", ";"); + case "POTION" -> name = ""; + case "ATTRIBUTE_SHARD" -> + name = internalID + "+" + name.replace("SHARD-", "").replaceAll("_(?!.*_)", ";"); + default -> name = name.replace(":", "-"); } if (!name.isEmpty() && lbinExist) { @@ -169,12 +171,11 @@ public class PriceInfoTooltip { if (SkyblockerConfig.get().general.itemTooltip.enableMuseumDate && !bazaarOpened) { if (isMuseumJson == null) { nullWarning(); - } - else { + } else { String timestamp = getTimestamp(stack); - if (isMuseumJson.has(name)) { - String itemCategory = isMuseumJson.get(name).toString().replaceAll("\"", ""); + if (isMuseumJson.has(internalID)) { + String itemCategory = isMuseumJson.get(internalID).getAsString(); String format = switch (itemCategory) { case "Weapons" -> "%-18s"; case "Armor" -> "%-19s"; @@ -191,7 +192,7 @@ public class PriceInfoTooltip { } } } - + private static void nullWarning() { if (!nullMsgSend && client.player != null) { client.player.sendMessage(Text.translatable("skyblocker.itemTooltip.nullMessage"), false); @@ -240,88 +241,110 @@ public class PriceInfoTooltip { return ""; } - public static String getInternalNameFromNBT(ItemStack stack) { + public static String getInternalNameFromNBT(ItemStack stack, boolean internalIDOnly) { NbtCompound tag = getItemNBT(stack); - if (tag != null && tag.contains("ExtraAttributes", 10)) { - NbtCompound ea = tag.getCompound("ExtraAttributes"); + if (tag == null || !tag.contains("ExtraAttributes", 10)) { + return null; + } + NbtCompound ea = tag.getCompound("ExtraAttributes"); - if (ea.contains("id", 8)) { - String internalName = ea.getString("id"); + if (!ea.contains("id", 8)) { + return null; + } + String internalName = ea.getString("id"); - // Transformation to API format. - if ("ENCHANTED_BOOK".equals(internalName)) { - if (ea.contains("enchantments")) { - NbtCompound enchants = ea.getCompound("enchantments"); - String enchant = enchants.getKeys().stream().findFirst().get(); - return internalName + "-" + enchant.toUpperCase(Locale.ENGLISH) + "-" + enchants.getInt(enchant); - } - } else if ("PET".equals(internalName)) { - if (ea.contains("petInfo")) { - JsonObject petInfo = gson.fromJson(ea.getString("petInfo"), JsonObject.class); - return internalName + "-" + petInfo.get("type").getAsString() + "-" + petInfo.get("tier").getAsString(); - } - } else if ("POTION".equals(internalName)) { - // New API just contains 'enhanced' tag. - String enhanced = ea.contains("enhanced") ? "-ENHANCED" : ""; - //String extended = ea.contains("extended") ? "-EXTENDED" : ""; - //String splash = ea.contains("splash") ? "-SPLASH" : ""; - if (ea.contains("potion") && ea.contains("potion_level")) { - return internalName + "-" + ea.getString("potion").toUpperCase(Locale.ENGLISH) + "-" + ea.getInt("potion_level") - + enhanced; //+ extended + splash; - } - } else if ("RUNE".equals(internalName)) { - if (ea.contains("runes")) { - NbtCompound runes = ea.getCompound("runes"); - String rune = runes.getKeys().stream().findFirst().get(); - return internalName + "-" + rune.toUpperCase(Locale.ENGLISH) + "-" + runes.getInt(rune); - } - } + if (internalIDOnly) { + return internalName; + } - return internalName; + // Transformation to API format. + switch (internalName) { + case "ENCHANTED_BOOK" -> { + if (ea.contains("enchantments")) { + NbtCompound enchants = ea.getCompound("enchantments"); + Optional<String> firstEnchant = enchants.getKeys().stream().findFirst(); + String enchant = firstEnchant.orElse(""); + return "ENCHANTMENT_" + enchant.toUpperCase(Locale.ENGLISH) + "_" + enchants.getInt(enchant); + } + } + case "PET" -> { + if (ea.contains("petInfo")) { + JsonObject petInfo = gson.fromJson(ea.getString("petInfo"), JsonObject.class); + return "LVL_1_" + petInfo.get("tier").getAsString() + "_" + petInfo.get("type").getAsString(); + } + } + case "POTION" -> { + String enhanced = ea.contains("enhanced") ? "_ENHANCED" : ""; + String extended = ea.contains("extended") ? "_EXTENDED" : ""; + String splash = ea.contains("splash") ? "_SPLASH" : ""; + if (ea.contains("potion") && ea.contains("potion_level")) { + return (ea.getString("potion") + "_" + internalName + "_" + ea.getInt("potion_level") + + enhanced + extended + splash).toUpperCase(Locale.ENGLISH); + } + } + case "RUNE" -> { + if (ea.contains("runes")) { + NbtCompound runes = ea.getCompound("runes"); + Optional<String> firstRunes = runes.getKeys().stream().findFirst(); + String rune = firstRunes.orElse(""); + return rune.toUpperCase(Locale.ENGLISH) + "_RUNE_" + runes.getInt(rune); + } + } + case "ATTRIBUTE_SHARD" -> { + if (ea.contains("attributes")) { + NbtCompound shards = ea.getCompound("attributes"); + Optional<String> firstShards = shards.getKeys().stream().findFirst(); + String shard = firstShards.orElse(""); + return internalName + "-" + shard.toUpperCase(Locale.ENGLISH) + "_" + shards.getInt(shard); + } } - else - return null; } - else - return null; + return internalName; } + private static Text getCoinsMessage(double price, int count) { + // Format the price string once + String priceString = String.format(Locale.ENGLISH, "%1$,.1f", price); + + // If count is 1, return a simple message if (count == 1) { - String priceString = String.format(Locale.ENGLISH, "%1$,.1f", price); return Text.literal(priceString + " Coins").formatted(Formatting.DARK_AQUA); } - else { - String priceStringTotal = String.format(Locale.ENGLISH, "%1$,.1f", price * count); - MutableText priceTextTotal = Text.literal(priceStringTotal + " Coins ").formatted(Formatting.DARK_AQUA); - String priceStringEach = String.format(Locale.ENGLISH, "%1$,.1f", price); - MutableText priceTextEach = Text.literal( "(" + priceStringEach + " each)").formatted(Formatting.GRAY); + // If count is greater than 1, include the "each" information + String priceStringTotal = String.format(Locale.ENGLISH, "%1$,.1f", price * count); + MutableText message = Text.literal(priceStringTotal + " Coins ").formatted(Formatting.DARK_AQUA); + message.append(Text.literal("(" + priceString + " each)").formatted(Formatting.GRAY)); - return priceTextTotal.append(priceTextEach); - } + return message; } - + + private static Text getMotesMessage(int price, int count) { float motesMultiplier = SkyblockerConfig.get().locations.rift.mcGrubberStacks * 0.05f + 1; + + // Calculate the total price + int totalPrice = price * count; + String totalPriceString = String.format(Locale.ENGLISH, "%1$,.1f", totalPrice * motesMultiplier); + + // If count is 1, return a simple message if (count == 1) { - String priceString = String.format(Locale.ENGLISH, "%1$,.1f", price * motesMultiplier).replace(".0", ""); - return Text.literal(priceString + " Motes").formatted(Formatting.DARK_AQUA); + return Text.literal(totalPriceString.replace(".0", "") + " Motes").formatted(Formatting.DARK_AQUA); } - else { - String priceStringTotal = String.format(Locale.ENGLISH, "%1$,.1f", price * count * motesMultiplier).replace(".0", ""); - MutableText priceTextTotal = Text.literal(priceStringTotal + " Motes ").formatted(Formatting.DARK_AQUA); - String priceStringEach = String.format(Locale.ENGLISH, "%1$,.1f", price * motesMultiplier).replace(".0", ""); - MutableText priceTextEach = Text.literal( "(" + priceStringEach + " each)").formatted(Formatting.GRAY); + // If count is greater than 1, include the "each" information + String eachPriceString = String.format(Locale.ENGLISH, "%1$,.1f", price * motesMultiplier); + MutableText message = Text.literal(totalPriceString.replace(".0", "") + " Motes ").formatted(Formatting.DARK_AQUA); + message.append(Text.literal("(" + eachPriceString.replace(".0", "") + " each)").formatted(Formatting.GRAY)); - return priceTextTotal.append(priceTextEach); - } + return message; } // If these options is true beforehand, the client will get first data of these options while loading. // After then, it will only fetch the data if it is on Skyblock. public static int minute = -1; + public static void init() { skyblocker.scheduler.scheduleCyclic(() -> { if (!Utils.isOnSkyblock() && 0 < minute++) { @@ -330,17 +353,17 @@ public class PriceInfoTooltip { } List<CompletableFuture<Void>> futureList = new ArrayList<>(); - if ((SkyblockerConfig.get().general.itemTooltip.enableAvgBIN) && (oneDayAvgPricesJson == null || threeDayAvgPricesJson == null || minute % 5 == 0)) { + if (SkyblockerConfig.get().general.itemTooltip.enableAvgBIN) { SkyblockerConfig.Average type = SkyblockerConfig.get().general.itemTooltip.avg; - if (type == SkyblockerConfig.Average.BOTH || oneDayAvgPricesJson == null || threeDayAvgPricesJson == null) { + if (type == SkyblockerConfig.Average.BOTH || oneDayAvgPricesJson == null || threeDayAvgPricesJson == null || minute % 5 == 0) { + futureList.add(CompletableFuture.runAsync(() -> { + oneDayAvgPricesJson = downloadPrices("1 day avg"); + threeDayAvgPricesJson = downloadPrices("3 day avg"); + })); + } else if (type == SkyblockerConfig.Average.ONE_DAY) { futureList.add(CompletableFuture.runAsync(() -> oneDayAvgPricesJson = downloadPrices("1 day avg"))); - futureList.add(CompletableFuture.runAsync(() -> threeDayAvgPricesJson = downloadPrices("3 day avg"))); - } - else if (type == SkyblockerConfig.Average.ONE_DAY) { - futureList.add(CompletableFuture.runAsync(() -> oneDayAvgPricesJson = downloadPrices("1 day avg"))); - } - else if (type == SkyblockerConfig.Average.THREE_DAY) { + } else if (type == SkyblockerConfig.Average.THREE_DAY) { futureList.add(CompletableFuture.runAsync(() -> threeDayAvgPricesJson = downloadPrices("3 day avg"))); } } @@ -355,9 +378,9 @@ public class PriceInfoTooltip { if (SkyblockerConfig.get().general.itemTooltip.enableMuseumDate && isMuseumJson == null) futureList.add(CompletableFuture.runAsync(() -> isMuseumJson = downloadPrices("museum"))); - + if (SkyblockerConfig.get().general.itemTooltip.enableMotesPrice && motesPricesJson == null) - futureList.add(CompletableFuture.runAsync(() -> motesPricesJson = downloadPrices("motes"))); + futureList.add(CompletableFuture.runAsync(() -> motesPricesJson = downloadPrices("motes"))); minute++; CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0])) @@ -383,7 +406,7 @@ public class PriceInfoTooltip { apiAddresses.put("1 day avg", "https://moulberry.codes/auction_averages_lbin/1day.json.gz"); apiAddresses.put("3 day avg", "https://moulberry.codes/auction_averages_lbin/3day.json.gz"); apiAddresses.put("bazaar", "https://hysky.de/api/bazaar"); - apiAddresses.put("lowest bins", "https://lb.tricked.pro/lowestbins"); + apiAddresses.put("lowest bins", "https://hysky.de/api/auctions/lowestbins"); apiAddresses.put("npc", "https://hysky.de/api/npcprice"); apiAddresses.put("museum", "https://hysky.de/api/museum"); apiAddresses.put("motes", "https://hysky.de/api/motesprice"); diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/util/PlayerListMgr.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/util/PlayerListMgr.java index 7b35bcce..446b7d81 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/util/PlayerListMgr.java +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/util/PlayerListMgr.java @@ -43,7 +43,11 @@ public class PlayerListMgr { } public static void updateFooter(Text f) { - footer = f.getString(); + if (f == null) { + footer = null; + } else { + footer = f.getString(); + } } public static String getFooter() { diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/AdvertisementWidget.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/AdvertisementWidget.java index 88e3a5cd..8d50fc2f 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/AdvertisementWidget.java +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/AdvertisementWidget.java @@ -18,12 +18,18 @@ public class AdvertisementWidget extends Widget { @Override public void updateContent() { + boolean added = false; for (int i = 73; i < 80; i++) { Text text = PlayerListMgr.textAt(i); - if (text != null) + if (text != null) { this.addComponent(new PlainTextComponent(text)); + added = true; + } } + if (!added) { + this.addComponent(new PlainTextComponent(Text.literal("No Advertisements").formatted(Formatting.GRAY))); + } } } diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/GoodToKnowWidget.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/GoodToKnowWidget.java index e3b462a9..d1a3df1f 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/GoodToKnowWidget.java +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/GoodToKnowWidget.java @@ -22,26 +22,38 @@ public class GoodToKnowWidget extends Widget { // that // In beginning it only shows montezuma, then timecharms and enigma souls are // added - Text pos49 = PlayerListMgr.textAt(49); // Can be times visited rift - Text pos51 = PlayerListMgr.textAt(51); // Can be lifetime motes or visited rift - Text pos53 = PlayerListMgr.textAt(53); // Can be lifetime motes + + int headerPos = 0; + // this seems suboptimal, but I'm not sure if there's a way to do it better. + // search for the GTK header and offset the rest accordingly. + for (int i = 45; i <= 49; i++) { + String str = PlayerListMgr.strAt(i); + if (str != null && str.startsWith("Good to")) { + headerPos = i; + break; + } + } + + Text posA = PlayerListMgr.textAt(headerPos + 2); // Can be times visited rift + Text posB = PlayerListMgr.textAt(headerPos + 4); // Can be lifetime motes or visited rift + Text posC = PlayerListMgr.textAt(headerPos + 6); // Can be lifetime motes int visitedRiftPos = 0; int lifetimeMotesPos = 0; // Check each position to see what is or isn't there so we don't try adding // invalid components - if (pos49.getString().contains("times")) - visitedRiftPos = 49; - if (pos51.getString().contains("Motes")) - lifetimeMotesPos = 51; - if (pos51.getString().contains("times")) - visitedRiftPos = 51; - if (pos53.getString().contains("Motes")) - lifetimeMotesPos = 53; - - Text timesVisitedRift = (visitedRiftPos == 51) ? pos51 : (visitedRiftPos == 49) ? pos49 : null; - Text lifetimeMotesEarned = (lifetimeMotesPos == 53) ? pos53 : (lifetimeMotesPos == 51) ? pos51 : null; + if (posA != null && posA.getString().contains("times")) + visitedRiftPos = headerPos + 2; + if (posB != null && posB.getString().contains("Motes")) + lifetimeMotesPos = headerPos + 4; + if (posB != null && posB.getString().contains("times")) + visitedRiftPos = headerPos + 4; + if (posC != null && posC.getString().contains("Motes")) + lifetimeMotesPos = headerPos + 6; + + Text timesVisitedRift = (visitedRiftPos == headerPos + 4) ? posB : (visitedRiftPos == headerPos + 2) ? posA : Text.literal("No Data").formatted(Formatting.GRAY); + Text lifetimeMotesEarned = (lifetimeMotesPos == headerPos + 6) ? posC : (lifetimeMotesPos == headerPos + 4) ? posB : Text.literal("No Data").formatted(Formatting.GRAY); if (visitedRiftPos != 0) { this.addComponent(new IcoTextComponent(Ico.EXPERIENCE_BOTTLE, diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/RiftProfileWidget.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/RiftProfileWidget.java index 0b6ff5bf..785850d5 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/RiftProfileWidget.java +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/RiftProfileWidget.java @@ -7,9 +7,9 @@ import net.minecraft.text.Text; import net.minecraft.util.Formatting; public class RiftProfileWidget extends Widget { - + private static final MutableText TITLE = Text.literal("Profile").formatted(Formatting.DARK_AQUA, Formatting.BOLD); - + public RiftProfileWidget() { super(TITLE, Formatting.DARK_AQUA.getColorValue()); } diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/RiftProgressWidget.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/RiftProgressWidget.java index 375a41b9..ad43c9f4 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/RiftProgressWidget.java +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/RiftProgressWidget.java @@ -6,6 +6,7 @@ import java.util.regex.Pattern; import me.xmrvizzy.skyblocker.skyblock.tabhud.util.Ico; import me.xmrvizzy.skyblocker.skyblock.tabhud.util.PlayerListMgr; import me.xmrvizzy.skyblocker.skyblock.tabhud.widget.Widget; +import me.xmrvizzy.skyblocker.skyblock.tabhud.widget.component.PlainTextComponent; import me.xmrvizzy.skyblocker.skyblock.tabhud.widget.component.ProgressComponent; import net.minecraft.text.MutableText; import net.minecraft.text.Text; @@ -14,86 +15,109 @@ import net.minecraft.util.math.MathHelper; public class RiftProgressWidget extends Widget { - private static final MutableText TITLE = Text.literal("Rift Progress").formatted(Formatting.BLUE, Formatting.BOLD); + private static final MutableText TITLE = Text.literal("Rift Progress").formatted(Formatting.BLUE, Formatting.BOLD); - private static final Pattern TIMECHARMS_PATTERN = Pattern.compile("Timecharms: (?<current>[0-9]+)\\/(?<total>[0-9]+)"); - private static final Pattern ENIGMA_SOULS_PATTERN = Pattern.compile("Enigma Souls: (?<current>[0-9]+)\\/(?<total>[0-9]+)"); - private static final Pattern MONTEZUMA_PATTERN = Pattern.compile("Montezuma: (?<current>[0-9]+)\\/(?<total>[0-9]+)"); + private static final Pattern TIMECHARMS_PATTERN = Pattern.compile("Timecharms: (?<current>[0-9]+)\\/(?<total>[0-9]+)"); + private static final Pattern ENIGMA_SOULS_PATTERN = Pattern.compile("Enigma Souls: (?<current>[0-9]+)\\/(?<total>[0-9]+)"); + private static final Pattern MONTEZUMA_PATTERN = Pattern.compile("Montezuma: (?<current>[0-9]+)\\/(?<total>[0-9]+)"); - public RiftProgressWidget() { - super(TITLE, Formatting.BLUE.getColorValue()); + public RiftProgressWidget() { + super(TITLE, Formatting.BLUE.getColorValue()); } @Override public void updateContent() { - // After you progress further the tab adds more info so we need to be careful of - // that - // In beginning it only shows montezuma, then timecharms and enigma souls are - // added - String pos45 = PlayerListMgr.strAt(45); // Can be Montezuma or Timecharms - String pos46 = PlayerListMgr.strAt(46); // Can be Enigma Souls or Empty - String pos47 = PlayerListMgr.strAt(47); // Can be Montezuma or "Good to know" heading + // After you progress further, the tab adds more info so we need to be careful + // of that. + // In beginning it only shows montezuma, then timecharms and enigma souls are + // added. + + String pos44 = PlayerListMgr.strAt(44); + + // LHS short-circuits, so the RHS won't be evaluated on pos44 == null + if (pos44 == null || !pos44.contains("Rift Progress")) { + this.addComponent(new PlainTextComponent(Text.literal("No Progress").formatted(Formatting.GRAY))); + return; + } + + // let's try to be clever by assuming what progress item may appear where and + // when to skip testing every slot for every thing. + + // always non-null, as this holds the topmost item. + // if there is none, there shouldn't be a header. + String pos45 = PlayerListMgr.strAt(45); + + // Can be Montezuma, Enigma Souls or Timecharms. + // assume timecharms can only appear here and that they're the last thing to + // appear, so if this exists, we know the rest. + if (pos45.contains("Timecharms")) { + addTimecharmsComponent(45); + addEnigmaSoulsComponent(46); + addMontezumaComponent(47); + return; + } + + // timecharms didn't appear at the top, so there's two or one entries. + // assume that if there's two, souls is always top. + String pos46 = PlayerListMgr.strAt(46); + + if (pos45.contains("Enigma Souls")) { + addEnigmaSoulsComponent(45); + if (pos46 != null) { + // souls might appear alone. + // if there's a second entry, it has to be montezuma + addMontezumaComponent(46); + } + } else { + // first entry isn't souls, so it's just montezuma and nothing else. + addMontezumaComponent(45); + } - boolean hasTimecharms = false; - boolean hasEnigmaSouls = false; - int montezumaPos; - - // Check each position to see what is or isn't there so we don't try adding - // invalid components - if (pos45.contains("Timecharms")) - hasTimecharms = true; - if (pos46.contains("Enigma Souls")) - hasEnigmaSouls = true; - - // Small ternary to account for positions, defaults to -1 if it for some reason - // does not exist (which shouldn't be the case!) - montezumaPos = (pos47.contains("Montezuma")) ? 47 : (pos45.contains("Montezuma")) ? 45 : -1; - - if (hasTimecharms) { - Matcher m = PlayerListMgr.regexAt(45, TIMECHARMS_PATTERN); + } - int current = Integer.parseInt(m.group("current")); - int total = Integer.parseInt(m.group("total")); - float pcnt = ((float) current / (float) total) * 100f; - Text progressText = Text.literal(current + "/" + total); + private static int pcntToCol(float pcnt) { + return MathHelper.hsvToRgb(pcnt / 300f, 0.9f, 0.9f); + } - ProgressComponent pc = new ProgressComponent(Ico.NETHER_STAR, Text.literal("Timecharms"), progressText, - pcnt, pcntToCol(pcnt)); + private void addTimecharmsComponent(int pos) { + Matcher m = PlayerListMgr.regexAt(pos, TIMECHARMS_PATTERN); - this.addComponent(pc); - } + int current = Integer.parseInt(m.group("current")); + int total = Integer.parseInt(m.group("total")); + float pcnt = ((float) current / (float) total) * 100f; + Text progressText = Text.literal(current + "/" + total); - if (hasEnigmaSouls) { - Matcher m = PlayerListMgr.regexAt(46, ENIGMA_SOULS_PATTERN); + ProgressComponent pc = new ProgressComponent(Ico.NETHER_STAR, Text.literal("Timecharms"), progressText, + pcnt, pcntToCol(pcnt)); - int current = Integer.parseInt(m.group("current")); - int total = Integer.parseInt(m.group("total")); - float pcnt = ((float) current / (float) total) * 100f; - Text progressText = Text.literal(current + "/" + total); + this.addComponent(pc); + } - ProgressComponent pc = new ProgressComponent(Ico.HEART_OF_THE_SEA, Text.literal("Enigma Souls"), - progressText, pcnt, pcntToCol(pcnt)); + private void addEnigmaSoulsComponent(int pos) { + Matcher m = PlayerListMgr.regexAt(pos, ENIGMA_SOULS_PATTERN); - this.addComponent(pc); - } + int current = Integer.parseInt(m.group("current")); + int total = Integer.parseInt(m.group("total")); + float pcnt = ((float) current / (float) total) * 100f; + Text progressText = Text.literal(current + "/" + total); - if (montezumaPos != -1) { - Matcher m = PlayerListMgr.regexAt(montezumaPos, MONTEZUMA_PATTERN); + ProgressComponent pc = new ProgressComponent(Ico.HEART_OF_THE_SEA, Text.literal("Enigma Souls"), + progressText, pcnt, pcntToCol(pcnt)); - int current = Integer.parseInt(m.group("current")); - int total = Integer.parseInt(m.group("total")); - float pcnt = ((float) current / (float) total) * 100f; - Text progressText = Text.literal(current + "/" + total); + this.addComponent(pc); + } - ProgressComponent pc = new ProgressComponent(Ico.BONE, Text.literal("Montezuma"), progressText, pcnt, - pcntToCol(pcnt)); + private void addMontezumaComponent(int pos) { + Matcher m = PlayerListMgr.regexAt(pos, MONTEZUMA_PATTERN); - this.addComponent(pc); - } + int current = Integer.parseInt(m.group("current")); + int total = Integer.parseInt(m.group("total")); + float pcnt = ((float) current / (float) total) * 100f; + Text progressText = Text.literal(current + "/" + total); - } + ProgressComponent pc = new ProgressComponent(Ico.BONE, Text.literal("Montezuma"), progressText, pcnt, + pcntToCol(pcnt)); - private static int pcntToCol(float pcnt) { - return MathHelper.hsvToRgb(pcnt / 300f, 0.9f, 0.9f); - } + this.addComponent(pc); + } } diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/RiftServerInfoWidget.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/RiftServerInfoWidget.java index cab38a86..1ec3771e 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/RiftServerInfoWidget.java +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/RiftServerInfoWidget.java @@ -11,7 +11,7 @@ import net.minecraft.util.Formatting; * */ public class RiftServerInfoWidget extends Widget { - + private static final MutableText TITLE = Text.literal("Server Info").formatted(Formatting.LIGHT_PURPLE, Formatting.BOLD); public RiftServerInfoWidget() { diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/RiftStatsWidget.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/RiftStatsWidget.java index 8fab3dd4..95a587a9 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/RiftStatsWidget.java +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/RiftStatsWidget.java @@ -21,22 +21,22 @@ public class RiftStatsWidget extends Widget { public void updateContent() { Text riftDamage = Widget.simpleEntryText(64, "RDG", Formatting.DARK_PURPLE); IcoTextComponent rdg = new IcoTextComponent(Ico.DIASWORD, riftDamage); - + Text speed = Widget.simpleEntryText(65, "SPD", Formatting.WHITE); IcoTextComponent spd = new IcoTextComponent(Ico.SUGAR, speed); - + Text intelligence = Widget.simpleEntryText(66, "INT", Formatting.AQUA); IcoTextComponent intel = new IcoTextComponent(Ico.ENCHANTED_BOOK, intelligence); - + Text manaRegen = Widget.simpleEntryText(67, "MRG", Formatting.AQUA); IcoTextComponent mrg = new IcoTextComponent(Ico.DIAMOND, manaRegen); - + TableComponent tc = new TableComponent(2, 2, Formatting.AQUA.getColorValue()); tc.addToCell(0, 0, rdg); tc.addToCell(0, 1, spd); tc.addToCell(1, 0, intel); tc.addToCell(1, 1, mrg); - + this.addComponent(tc); } diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/ShenWidget.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/ShenWidget.java index a1345c49..1f432406 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/ShenWidget.java +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/rift/ShenWidget.java @@ -8,7 +8,7 @@ import net.minecraft.text.Text; import net.minecraft.util.Formatting; public class ShenWidget extends Widget { - + private static final MutableText TITLE = Text.literal("Shen's Countdown").formatted(Formatting.DARK_AQUA, Formatting.BOLD); public ShenWidget() { |