diff options
10 files changed, 287 insertions, 48 deletions
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java index 033a919d..5bc98894 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java @@ -10,7 +10,6 @@ import net.minecraft.text.Text; import net.minecraft.util.Formatting; public class Kuudra { - public static final String LOCATION = "kuudra"; static KuudraPhase phase = KuudraPhase.OTHER; public static void init() { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java index 32f0b7e3..a207ddc7 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java @@ -563,7 +563,9 @@ public class DungeonManager { if (room != null && currentRoom != room) { if (currentRoom != null && room.getType() == Room.Type.FAIRY) { currentRoom.nextRoom = room; - room.keyFound = currentRoom.keyFound; + if (currentRoom.keyFound) { + room.keyFound = true; + } } currentRoom = room; } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java index b12bba62..8e0073f7 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java @@ -3,12 +3,12 @@ package de.hysky.skyblocker.skyblock.dungeon.secrets; import com.google.gson.JsonObject; import it.unimi.dsi.fastutil.ints.IntSortedSet; import it.unimi.dsi.fastutil.objects.ObjectIntPair; -import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.MapColor; import net.minecraft.item.map.MapIcon; import net.minecraft.item.map.MapState; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3i; import net.minecraft.world.World; @@ -286,14 +286,13 @@ public class DungeonMapUtils { } private static boolean hasWitherOrBloodDoor(World world, Vector2ic pos, BlockPos.Mutable doorPos) { - return isWitherOrBloodDoor(world, doorPos.set(pos.x() - 2, 69, pos.y() + 14)) || - isWitherOrBloodDoor(world, doorPos.set(pos.x() + 14, 69, pos.y() - 2)) || - isWitherOrBloodDoor(world, doorPos.set(pos.x() + 14, 69, pos.y() + 30)) || - isWitherOrBloodDoor(world, doorPos.set(pos.x() + 30, 69, pos.y() + 14)); + return isWitherOrBloodDoor(world, doorPos.set(pos.x() + 1, 72, pos.y() + 17)) || + isWitherOrBloodDoor(world, doorPos.set(pos.x() + 17, 72, pos.y() + 1)) || + isWitherOrBloodDoor(world, doorPos.set(pos.x() + 17, 72, pos.y() + 33)) || + isWitherOrBloodDoor(world, doorPos.set(pos.x() + 33, 72, pos.y() + 17)); } - private static boolean isWitherOrBloodDoor(World world, BlockPos pos) { - BlockState state = world.getBlockState(pos); - return state.isOf(Blocks.COAL_BLOCK) || state.isOf(Blocks.RED_TERRACOTTA); + private static boolean isWitherOrBloodDoor(World world, BlockPos.Mutable pos) { + return world.getStatesInBox(Box.enclosing(pos, pos.move(-3, -3, -3))).allMatch(state -> state.isOf(Blocks.COAL_BLOCK) || state.isOf(Blocks.RED_TERRACOTTA)); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java index 19f2e6fd..d5be7eee 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java @@ -140,15 +140,37 @@ public class ItemTooltip { } } + final Map<Integer, String> itemTierFloors = new HashMap<>() {{ + put(1, "F1"); + put(2, "F2"); + put(3, "F3"); + put(4, "F4/M1"); + put(5, "F5/M2"); + put(6, "F6/M3"); + put(7, "F7/M4"); + put(8, "M5"); + put(9, "M6"); + put(10, "M7"); + }}; + if (SkyblockerConfigManager.get().general.dungeonQuality) { NbtCompound ea = ItemUtils.getExtraAttributes(stack); if (ea != null && ea.contains("baseStatBoostPercentage")) { int baseStatBoostPercentage = ea.getInt("baseStatBoostPercentage"); - if (baseStatBoostPercentage == 50) { + boolean maxQuality = baseStatBoostPercentage == 50; + if (maxQuality) { lines.add(Text.literal(String.format("%-17s", "Item Quality:") + baseStatBoostPercentage + "/50").formatted(Formatting.RED).formatted(Formatting.BOLD)); } else { lines.add(Text.literal(String.format("%-21s", "Item Quality:") + baseStatBoostPercentage + "/50").formatted(Formatting.BLUE)); } + if (ea.contains("item_tier")) { // sometimes it just isn't here? + int itemTier = ea.getInt("item_tier"); + if (maxQuality) { + lines.add(Text.literal(String.format("%-17s", "Floor Tier:") + itemTier + " (" + itemTierFloors.get(itemTier) + ")").formatted(Formatting.RED).formatted(Formatting.BOLD)); + } else { + lines.add(Text.literal(String.format("%-21s", "Floor Tier:") + itemTier + " (" + itemTierFloors.get(itemTier) + ")").formatted(Formatting.BLUE)); + } + } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/rift/TheRift.java b/src/main/java/de/hysky/skyblocker/skyblock/rift/TheRift.java index 02b694b6..7413e06f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/rift/TheRift.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/rift/TheRift.java @@ -8,11 +8,6 @@ import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; public class TheRift { - /** - * @see de.hysky.skyblocker.utils.Utils#isInTheRift() Utils#isInTheRift(). - */ - public static final String LOCATION = "rift"; - public static void init() { WorldRenderEvents.AFTER_TRANSLUCENT.register(MirrorverseWaypoints::render); WorldRenderEvents.AFTER_TRANSLUCENT.register(EffigyWaypoints::render); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/Widget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/Widget.java index 5f0d2c3c..e37da755 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/Widget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/Widget.java @@ -67,6 +67,11 @@ public abstract class Widget { this.addComponent(new IcoTextComponent(ico, txt)); } + public final void addSimpleIcoText(ItemStack ico, String string, Formatting fmt, String content) { + Text txt = Widget.simpleEntryText(content, string, fmt); + this.addComponent(new IcoTextComponent(ico, txt)); + } + /** * Calculate the size of this widget. * <b>Must be called before returning from the widget constructor and after all diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/hud/HudPowderWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/hud/HudPowderWidget.java index 1d11c2a6..fe23f19a 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/hud/HudPowderWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/hud/HudPowderWidget.java @@ -1,17 +1,47 @@ package de.hysky.skyblocker.skyblock.tabhud.widget.hud; +import de.hysky.skyblocker.skyblock.dwarven.DwarvenHud; import de.hysky.skyblocker.skyblock.tabhud.util.Ico; import de.hysky.skyblocker.skyblock.tabhud.widget.Widget; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Formatting; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Locale; + // this widget shows the status of the king's commissions. // (dwarven mines and crystal hollows) // USE ONLY WITH THE DWARVEN HUD! public class HudPowderWidget extends Widget { + /** + * American number format instance + */ + private static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance(Locale.US); + /** + * current value of Mithril Powder + */ + private static int mithrilPowder = 0; + /** + * current value of Gemstone Powder + */ + private static int gemstonePowder = 0; + /** + * the difference between the previous and current value of Mithril Powder + */ + private static int mithrilPowderDiff = 0; + /** + * the difference between the previous and current value of Gemstone Powder + */ + private static int gemstonePowderDiff = 0; + /** + * The initial value of the timer for the difference update delay countdown. + */ + private static long startTime = System.currentTimeMillis(); + private static final MutableText TITLE = Text.literal("Powders").formatted(Formatting.DARK_AQUA, Formatting.BOLD); @@ -30,11 +60,60 @@ public class HudPowderWidget extends Widget { super(TITLE, Formatting.DARK_AQUA.getColorValue()); } + /** + * Converts a string with a number and commas between digits to an integer value. + * + * @param str a string with a number and commas between digits + * @return integer value + */ + private static int parsePowder(String str) { + try { + return NUMBER_FORMAT.parse(str).intValue(); + } catch (ParseException e) { + return 0; + } + } + + /** + * Converts Powder and difference values to a string and adds commas to the digits of the numbers. + * + * @param powder the value of Mithril or Gemstone Powder + * @param diff the difference between the previous and current value of Mithril or Gemstone Powder + * @return formatted string + */ + private static String formatPowderString(int powder, int diff) { + if (diff == 0) return NUMBER_FORMAT.format(powder); + return NUMBER_FORMAT.format(powder) + (diff > 0 ? " (+" : " (") + NUMBER_FORMAT.format(diff) + ")"; + } + + /** + * Updates Powders and difference values when Powder values change or every 2 seconds. + */ + private static void updatePowders() { + long elapsedTime = System.currentTimeMillis() - startTime; + + int newMithrilPowder = parsePowder(DwarvenHud.mithrilPowder); + int newGemstonePowder = parsePowder(DwarvenHud.gemStonePowder); + + if (newMithrilPowder != mithrilPowder || newGemstonePowder != gemstonePowder || elapsedTime > 2000) { + startTime = System.currentTimeMillis(); + + mithrilPowderDiff = newMithrilPowder - mithrilPowder; + gemstonePowderDiff = newGemstonePowder - gemstonePowder; + + mithrilPowder = newMithrilPowder; + gemstonePowder = newGemstonePowder; + } + } @Override public void updateContent() { - this.addSimpleIcoText(Ico.MITHRIL, "Mithril:", Formatting.AQUA, 46); - this.addSimpleIcoText(Ico.AMETHYST_SHARD, "Gemstone:", Formatting.DARK_PURPLE, 47); + updatePowders(); + String mithrilPowderString = formatPowderString(mithrilPowder, mithrilPowderDiff); + String gemstonePowderString = formatPowderString(gemstonePowder, gemstonePowderDiff); + + this.addSimpleIcoText(Ico.MITHRIL, "Mithril: ", Formatting.AQUA, mithrilPowderString); + this.addSimpleIcoText(Ico.AMETHYST_SHARD, "Gemstone: ", Formatting.DARK_PURPLE, gemstonePowderString); } } diff --git a/src/main/java/de/hysky/skyblocker/utils/Location.java b/src/main/java/de/hysky/skyblocker/utils/Location.java new file mode 100644 index 00000000..bd2773fd --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/Location.java @@ -0,0 +1,116 @@ +package de.hysky.skyblocker.utils; + +import java.util.Arrays; + +/** + * All Skyblock locations + */ +public enum Location { + /** + * mode: dynamic + */ + PRIVATE_ISLAND("dynamic"), + /** + * mode: garden + */ + GARDEN("garden"), + /** + * mode: hub + */ + HUB("hub"), + /** + * mode: farming_1 + */ + THE_FARMING_ISLAND("farming_1"), + /** + * mode: foraging_1 + */ + THE_PARK("foraging_1"), + /** + * mode: combat_1 + */ + SPIDERS_DEN("combat_1"), + /** + * mode: combat_2 + */ + BLAZING_FORTRESS("combat_2"), + /** + * mode: combat_3 + */ + THE_END("combat_3"), + /** + * mode: crimson_isle + */ + CRIMSON_ISLE("crimson_isle"), + /** + * mode: mining_1 + */ + GOLD_MINE("mining_1"), + /** + * mode: mining_2 + */ + DEEP_CAVERNS("mining_2"), + /** + * mode: mining_3 + */ + DWARVEN_MINES("mining_3"), + /** + * mode: dungeon_hub + */ + DUNGEON_HUB("dungeon_hub"), + /** + * mode: winter + */ + WINTER_ISLAND("winter"), + /** + * mode: rift + */ + THE_RIFT("rift"), + /** + * mode: dark_auction + */ + DARK_AUCTION("dark_auction"), + /** + * mode: crystal_hollows + */ + CRYSTAL_HOLLOWS("crystal_hollows"), + /** + * mode: dungeon + */ + DUNGEON("dungeon"), + /** + * mode: kuudra + */ + KUUDRAS_HOLLOW("kuudra"), + /** + * Unknown Skyblock location + */ + UNKNOWN("unknown"); + + /** + * location id from <a href="https://api.hypixel.net/v2/resources/games">Hypixel API</a> + */ + private final String id; + + /** + * @param id location id from <a href="https://api.hypixel.net/v2/resources/games">Hypixel API</a> + */ + Location(String id) { + this.id = id; + } + + /** + * @return location id + */ + public String id() { + return this.id; + } + + /** + * @param id location id from <a href="https://api.hypixel.net/v2/resources/games">Hypixel API</a> + * @return location object + */ + public static Location from(String id) { + return Arrays.stream(Location.values()).filter(loc -> id.equals(loc.id())).findFirst().orElse(UNKNOWN); + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/Utils.java b/src/main/java/de/hysky/skyblocker/utils/Utils.java index cd739a0c..08d0b167 100644 --- a/src/main/java/de/hysky/skyblocker/utils/Utils.java +++ b/src/main/java/de/hysky/skyblocker/utils/Utils.java @@ -3,10 +3,8 @@ package de.hysky.skyblocker.utils; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import de.hysky.skyblocker.events.SkyblockEvents; -import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra; import de.hysky.skyblocker.skyblock.item.MuseumItemCache; import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; -import de.hysky.skyblocker.skyblock.rift.TheRift; import de.hysky.skyblocker.utils.scheduler.MessageScheduler; import de.hysky.skyblocker.utils.scheduler.Scheduler; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -37,15 +35,17 @@ import java.util.concurrent.CompletableFuture; public class Utils { private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class); private static final String ALTERNATE_HYPIXEL_ADDRESS = System.getProperty("skyblocker.alternateHypixelAddress", ""); - private static final String DUNGEONS_LOCATION = "dungeon"; - private static final String CRYSTAL_HOLLOWS_LOCATION = "crystal_hollows"; - private static final String DWARVEN_MINES_LOCATION = "mining_3"; private static final String PROFILE_PREFIX = "Profile: "; private static boolean isOnHypixel = false; private static boolean isOnSkyblock = false; private static boolean isInjected = false; /** + * Current Skyblock location (from /locraw) + */ + @NotNull + private static Location location = Location.UNKNOWN; + /** * The profile name parsed from the player list. */ @NotNull @@ -88,31 +88,30 @@ public class Utils { } public static boolean isInDungeons() { - return getLocationRaw().equals(DUNGEONS_LOCATION) || FabricLoader.getInstance().isDevelopmentEnvironment(); + return location == Location.DUNGEON || FabricLoader.getInstance().isDevelopmentEnvironment(); } public static boolean isInCrystalHollows() { - return getLocationRaw().equals(CRYSTAL_HOLLOWS_LOCATION) || FabricLoader.getInstance().isDevelopmentEnvironment(); + return location == Location.CRYSTAL_HOLLOWS || FabricLoader.getInstance().isDevelopmentEnvironment(); } public static boolean isInDwarvenMines() { - return getLocationRaw().equals(DWARVEN_MINES_LOCATION) || FabricLoader.getInstance().isDevelopmentEnvironment(); + return location == Location.DWARVEN_MINES || FabricLoader.getInstance().isDevelopmentEnvironment(); } public static boolean isInTheRift() { - return getLocationRaw().equals(TheRift.LOCATION); + return location == Location.THE_RIFT; } /** * @return if the player is in the end island */ public static boolean isInTheEnd() { - // /locraw returns "combat_3" when in The End - return getLocationRaw().equals("combat_3"); + return location == Location.THE_END; } public static boolean isInKuudra() { - return getLocationRaw().equals(Kuudra.LOCATION); + return location == Location.KUUDRAS_HOLLOW; } public static boolean isInjected() { @@ -133,6 +132,14 @@ public class Utils { } /** + * @return the location parsed from /locraw. + */ + @NotNull + public static Location getLocation() { + return location; + } + + /** * @return the server parsed from /locraw. */ @NotNull @@ -376,31 +383,45 @@ public class Utils { } /** + * Parses /locraw chat message and updates {@link #server}, {@link #gameType}, {@link #locationRaw}, {@link #map} + * and {@link #location} + * + * @param message json message from chat + */ + private static void parseLocRaw(String message) { + JsonObject locRaw = JsonParser.parseString(message).getAsJsonObject(); + + if (locRaw.has("server")) { + server = locRaw.get("server").getAsString(); + } + if (locRaw.has("gameType")) { + gameType = locRaw.get("gameType").getAsString(); + } + if (locRaw.has("mode")) { + locationRaw = locRaw.get("mode").getAsString(); + location = Location.from(locationRaw); + } else { + location = Location.UNKNOWN; + } + if (locRaw.has("map")) { + map = locRaw.get("map").getAsString(); + } + } + + /** * Parses the /locraw reply from the server and updates the player's profile id * * @return not display the message in chat if the command is sent by the mod */ public static boolean onChatMessage(Text text, boolean overlay) { String message = text.getString(); - if (message.startsWith("{\"server\":") && message.endsWith("}")) { - JsonObject locRaw = JsonParser.parseString(message).getAsJsonObject(); - if (locRaw.has("server")) { - server = locRaw.get("server").getAsString(); - if (locRaw.has("gameType")) { - gameType = locRaw.get("gameType").getAsString(); - } - if (locRaw.has("mode")) { - locationRaw = locRaw.get("mode").getAsString(); - } - if (locRaw.has("map")) { - map = locRaw.get("map").getAsString(); - } - boolean shouldFilter = !sentLocRaw; - sentLocRaw = false; + if (message.startsWith("{\"server\":") && message.endsWith("}")) { + parseLocRaw(message); + boolean shouldFilter = !sentLocRaw; + sentLocRaw = false; - return shouldFilter; - } + return shouldFilter; } if (isOnSkyblock && message.startsWith("Profile ID: ")) { @@ -419,6 +440,7 @@ public class Utils { gameType = ""; locationRaw = ""; map = ""; + location = Location.UNKNOWN; } private static void tickMayorCache(boolean refresh) { diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index be5921ce..3c6c6349 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -89,7 +89,7 @@ "text.autoconfig.skyblocker.option.general.itemTooltip.enableExoticTooltip": "Enable Exotic Tooltip", "text.autoconfig.skyblocker.option.general.itemTooltip.enableExoticTooltip.@Tooltip": "Displays the type of exotic below the item's name if an armor piece is exotic.", "text.autoconfig.skyblocker.option.general.dungeonQuality": "Dungeon Quality", - "text.autoconfig.skyblocker.option.general.dungeonQuality.@Tooltip": "Displays quality of dungeon drops from mobs", + "text.autoconfig.skyblocker.option.general.dungeonQuality.@Tooltip": "Displays quality and tier of dungeon drops from mobs.\n\n\nReminder:\nTier 1-3 dropped from F1-F3\nTier 4-7 dropped from F4-F7 or M1-M4\nTier 8-10 are dropped only from M5-M7", "text.autoconfig.skyblocker.option.general.itemInfoDisplay": "Item Info Display", "text.autoconfig.skyblocker.option.general.itemInfoDisplay.attributeShardInfo": "Attribute Shard Info", "text.autoconfig.skyblocker.option.general.itemInfoDisplay.attributeShardInfo.@Tooltip": "Displays the attribute's level as the stack count and the initials of the attribute's name.", |