From 1738f11d88bc90736d08f8a5f994a3afef5143b7 Mon Sep 17 00:00:00 2001 From: Fluboxer Date: Sat, 17 Feb 2024 13:27:28 +0300 Subject: added floor tier to item tooltip as item quality without tier was half useless --- .../hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src/main/java') 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..6ec57359 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 @@ -144,11 +144,20 @@ public class ItemTooltip { NbtCompound ea = ItemUtils.getExtraAttributes(stack); if (ea != null && ea.contains("baseStatBoostPercentage")) { int baseStatBoostPercentage = ea.getInt("baseStatBoostPercentage"); - if (baseStatBoostPercentage == 50) { + boolean max_quality = baseStatBoostPercentage == 50; + if (max_quality) { 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 item_tier = ea.getInt("item_tier"); + if (max_quality) { + lines.add(Text.literal(String.format("%-17s", "Floor Tier:") + item_tier).formatted(Formatting.RED).formatted(Formatting.BOLD)); + } else { + lines.add(Text.literal(String.format("%-21s", "Floor Tier:") + item_tier).formatted(Formatting.BLUE)); + } + } } } -- cgit From 15cb9c5784a9fbe41e3e5235213c2aff5967e9ca Mon Sep 17 00:00:00 2001 From: Fluboxer Date: Sat, 17 Feb 2024 17:48:40 +0300 Subject: Made tooltip also show floor instead of only showing tier number --- .../skyblock/item/tooltip/ItemTooltip.java | 25 ++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'src/main/java') 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 6ec57359..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,22 +140,35 @@ public class ItemTooltip { } } + final Map 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"); - boolean max_quality = baseStatBoostPercentage == 50; - if (max_quality) { + 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 item_tier = ea.getInt("item_tier"); - if (max_quality) { - lines.add(Text.literal(String.format("%-17s", "Floor Tier:") + item_tier).formatted(Formatting.RED).formatted(Formatting.BOLD)); + 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:") + item_tier).formatted(Formatting.BLUE)); + lines.add(Text.literal(String.format("%-21s", "Floor Tier:") + itemTier + " (" + itemTierFloors.get(itemTier) + ")").formatted(Formatting.BLUE)); } } } -- cgit From 6d9aa9f33e91294c5e5733982ffd6c77ebb1a674 Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Sat, 17 Feb 2024 21:17:49 -0500 Subject: Refactor search overlay bazaar data source --- .../skyblocker/skyblock/searchOverlay/SearchOverManager.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/searchOverlay/SearchOverManager.java b/src/main/java/de/hysky/skyblocker/skyblock/searchOverlay/SearchOverManager.java index b2a453a9..68f279c7 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/searchOverlay/SearchOverManager.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/searchOverlay/SearchOverManager.java @@ -96,13 +96,15 @@ public class SearchOverManager { HashMap namesToId = new HashMap<>(); //get bazaar items - try (Http.ApiResponse response = Http.sendHypixelRequest("skyblock/bazaar", "")) { - JsonObject products = JsonParser.parseString(response.content()).getAsJsonObject().get("products").getAsJsonObject(); + try { + if (TooltipInfoType.BAZAAR.getData() == null) TooltipInfoType.BAZAAR.run(); + + JsonObject products = TooltipInfoType.BAZAAR.getData(); for (Map.Entry entry : products.entrySet()) { if (entry.getValue().isJsonObject()) { JsonObject product = entry.getValue().getAsJsonObject(); - String id = product.get("product_id").getAsString(); - int sellVolume = product.get("quick_status").getAsJsonObject().get("sellVolume").getAsInt(); + String id = product.get("id").getAsString(); + int sellVolume = product.get("sellVolume").getAsInt(); if (sellVolume == 0) continue; //do not add items that do not sell e.g. they are not actual in the bazaar Matcher matcher = BAZAAR_ENCHANTMENT_PATTERN.matcher(id); -- cgit From 39cf82e4976f70bf8b8d27216a0284e30d9ae5e4 Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Sat, 17 Feb 2024 21:32:15 -0500 Subject: Rename search overlay package to match Java conventions --- .../java/de/hysky/skyblocker/SkyblockerMod.java | 2 +- .../skyblocker/mixin/ClientPlayerEntityMixin.java | 4 +- .../skyblock/searchOverlay/OverlayScreen.java | 185 ----------- .../skyblock/searchOverlay/SearchOverManager.java | 349 --------------------- .../skyblock/searchoverlay/OverlayScreen.java | 185 +++++++++++ .../skyblock/searchoverlay/SearchOverManager.java | 349 +++++++++++++++++++++ 6 files changed, 537 insertions(+), 537 deletions(-) delete mode 100644 src/main/java/de/hysky/skyblocker/skyblock/searchOverlay/OverlayScreen.java delete mode 100644 src/main/java/de/hysky/skyblocker/skyblock/searchOverlay/SearchOverManager.java create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/searchoverlay/OverlayScreen.java create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/searchoverlay/SearchOverManager.java (limited to 'src/main/java') diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index 1aa97526..b8722fc6 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -26,7 +26,7 @@ import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; import de.hysky.skyblocker.skyblock.quicknav.QuickNav; import de.hysky.skyblocker.skyblock.rift.TheRift; -import de.hysky.skyblocker.skyblock.searchOverlay.SearchOverManager; +import de.hysky.skyblocker.skyblock.searchoverlay.SearchOverManager; import de.hysky.skyblocker.skyblock.shortcut.Shortcuts; import de.hysky.skyblocker.skyblock.special.SpecialEffects; import de.hysky.skyblocker.skyblock.tabhud.TabHud; diff --git a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java index 2a4c38a7..ceda9ed4 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java @@ -6,8 +6,8 @@ import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen; import de.hysky.skyblocker.skyblock.item.HotbarSlotLock; import de.hysky.skyblocker.skyblock.item.ItemProtection; import de.hysky.skyblocker.skyblock.rift.HealingMelonIndicator; -import de.hysky.skyblocker.skyblock.searchOverlay.OverlayScreen; -import de.hysky.skyblocker.skyblock.searchOverlay.SearchOverManager; +import de.hysky.skyblocker.skyblock.searchoverlay.OverlayScreen; +import de.hysky.skyblocker.skyblock.searchoverlay.SearchOverManager; import de.hysky.skyblocker.utils.Utils; import net.minecraft.block.entity.SignBlockEntity; import net.minecraft.client.MinecraftClient; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/searchOverlay/OverlayScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/searchOverlay/OverlayScreen.java deleted file mode 100644 index e1545c6c..00000000 --- a/src/main/java/de/hysky/skyblocker/skyblock/searchOverlay/OverlayScreen.java +++ /dev/null @@ -1,185 +0,0 @@ -package de.hysky.skyblocker.skyblock.searchOverlay; - -import de.hysky.skyblocker.config.SkyblockerConfigManager; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.client.gui.widget.TextFieldWidget; -import net.minecraft.item.ItemStack; -import net.minecraft.text.Style; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; -import net.minecraft.util.Identifier; -import org.lwjgl.glfw.GLFW; - -import static de.hysky.skyblocker.skyblock.itemlist.ItemRepository.getItemStack; - -public class OverlayScreen extends Screen { - - protected static final Identifier SEARCH_ICON_TEXTURE = new Identifier("icon/search"); - private static final int rowHeight = 20; - private TextFieldWidget searchField; - private ButtonWidget finishedButton; - private ButtonWidget[] suggestionButtons; - private ButtonWidget[] historyButtons; - - public OverlayScreen(Text title) { - super(title); - } - - /** - * Creates the layout for the overlay screen. - */ - @Override - protected void init() { - super.init(); - int rowWidth = (int) (this.width * 0.4); - int startX = (int) (this.width * 0.5) - rowWidth / 2; - int startY = (int) ((int) (this.height * 0.5) - (rowHeight * (1 + SkyblockerConfigManager.get().general.searchOverlay.maxSuggestions + 0.75 + SkyblockerConfigManager.get().general.searchOverlay.historyLength)) / 2); - - // Search field - this.searchField = new TextFieldWidget(textRenderer, startX, startY, rowWidth - rowHeight, rowHeight, Text.translatable("gui.recipebook.search_hint")); - searchField.setText(SearchOverManager.search); - searchField.setChangedListener(SearchOverManager::updateSearch); - searchField.setMaxLength(30); - - // finish buttons - finishedButton = ButtonWidget.builder(Text.literal("").setStyle(Style.EMPTY.withColor(Formatting.GREEN)), a -> close()) - .position(startX + rowWidth - rowHeight, startY) - .size(rowHeight, rowHeight).build(); - - // suggested item buttons - int rowOffset = rowHeight; - int totalSuggestions = SkyblockerConfigManager.get().general.searchOverlay.maxSuggestions; - this.suggestionButtons = new ButtonWidget[totalSuggestions]; - for (int i = 0; i < totalSuggestions; i++) { - suggestionButtons[i] = ButtonWidget.builder(Text.literal(SearchOverManager.getSuggestion(i)).setStyle(Style.EMPTY), a -> { - SearchOverManager.updateSearch(a.getMessage().getString()); - close(); - }) - .position(startX, startY + rowOffset) - .size(rowWidth, rowHeight).build(); - suggestionButtons[i].visible = false; - rowOffset += rowHeight; - } - // history item buttons - rowOffset += (int) (rowHeight * 0.75); - int historyLength = SkyblockerConfigManager.get().general.searchOverlay.historyLength; - this.historyButtons = new ButtonWidget[historyLength]; - for (int i = 0; i < historyLength; i++) { - String text = SearchOverManager.getHistory(i); - if (text != null) { - historyButtons[i] = ButtonWidget.builder(Text.literal(text).setStyle(Style.EMPTY), (a) -> { - SearchOverManager.updateSearch(a.getMessage().getString()); - close(); - }) - .position(startX, startY + rowOffset) - .size(rowWidth, rowHeight).build(); - rowOffset += rowHeight; - } else { - break; - } - } - - //add drawables in order to make tab navigation sensible - addDrawableChild(searchField); - for (ButtonWidget suggestion : suggestionButtons) { - addDrawableChild(suggestion); - } - for (ButtonWidget historyOption : historyButtons) { - if (historyOption != null) { - addDrawableChild(historyOption); - } - } - addDrawableChild(finishedButton); - - //focus the search box - this.setInitialFocus(searchField); - } - - /** - * Renders the search icon, label for the history and item Stacks for item names - */ - @Override - public void render(DrawContext context, int mouseX, int mouseY, float delta) { - super.render(context, mouseX, mouseY, delta); - int renderOffset = (rowHeight - 16) / 2; - context.drawGuiTexture(SEARCH_ICON_TEXTURE, finishedButton.getX() + renderOffset, finishedButton.getY() + renderOffset, 16, 16); - if (historyButtons.length > 0 && historyButtons[0] != null) { - context.drawText(textRenderer, Text.translatable("text.autoconfig.skyblocker.option.general.searchOverlay.historyLabel"), historyButtons[0].getX() + renderOffset, historyButtons[0].getY() - rowHeight / 2, 0xFFFFFFFF, true); - } - - //draw item stacks and tooltip to buttons - for (int i = 0; i < suggestionButtons.length; i++) { - drawItemAndTooltip(context, mouseX, mouseY, SearchOverManager.getSuggestionId(i), suggestionButtons[i], renderOffset); - } - for (int i = 0; i < historyButtons.length; i++) { - drawItemAndTooltip(context, mouseX, mouseY, SearchOverManager.getHistoryId(i), historyButtons[i], renderOffset); - } - } - - /** - * Draws the item and tooltip for the given button - */ - private void drawItemAndTooltip(DrawContext context, int mouseX, int mouseY, String id, ButtonWidget button, int renderOffset) { - if (id == null || id.isEmpty()) return; - ItemStack item = getItemStack(id); - if (item == null) return; - context.drawItem(item, button.getX() + renderOffset, button.getY() + renderOffset); - - // Draw tooltip - if (button.isMouseOver(mouseX, mouseY)) { - context.drawItemTooltip(textRenderer, item, mouseX, mouseY); - } - } - - /** - * updates if the suggestions buttons should be visible based on if they have a value - */ - @Override - public final void tick() { - super.tick(); - //update suggestion buttons text - for (int i = 0; i < SkyblockerConfigManager.get().general.searchOverlay.maxSuggestions; i++) { - String text = SearchOverManager.getSuggestion(i); - if (!text.isEmpty()) { - suggestionButtons[i].visible = true; - - boolean isNewText = !text.equals(suggestionButtons[i].getMessage().getString()); - if (!isNewText) continue; - - suggestionButtons[i].setMessage(Text.literal(text).setStyle(Style.EMPTY)); - } else { - suggestionButtons[i].visible = false; - } - } - } - - /** - * When a key is pressed. If enter key pressed and search box selected close - */ - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (keyCode == GLFW.GLFW_KEY_ENTER && searchField.isActive()) { - close(); - return true; - } - return super.keyPressed(keyCode, scanCode, modifiers); - } - - @Override - public boolean shouldPause() { - return false; - } - - /** - * Closes the overlay screen and gets the manager to send a packet update about the sign - */ - @Override - public void close() { - assert this.client != null; - assert this.client.player != null; - SearchOverManager.pushSearch(); - super.close(); - } -} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/searchOverlay/SearchOverManager.java b/src/main/java/de/hysky/skyblocker/skyblock/searchOverlay/SearchOverManager.java deleted file mode 100644 index 68f279c7..00000000 --- a/src/main/java/de/hysky/skyblocker/skyblock/searchOverlay/SearchOverManager.java +++ /dev/null @@ -1,349 +0,0 @@ -package de.hysky.skyblocker.skyblock.searchOverlay; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.mojang.brigadier.Command; -import com.mojang.brigadier.CommandDispatcher; -import de.hysky.skyblocker.config.SkyblockerConfig; -import de.hysky.skyblocker.config.SkyblockerConfigManager; -import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; -import de.hysky.skyblocker.utils.Http; -import de.hysky.skyblocker.utils.NEURepoManager; -import de.hysky.skyblocker.utils.scheduler.MessageScheduler; -import io.github.moulberry.repo.data.NEUItem; -import it.unimi.dsi.fastutil.Pair; -import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import net.minecraft.block.entity.SignBlockEntity; -import net.minecraft.client.MinecraftClient; -import net.minecraft.command.CommandRegistryAccess; -import net.minecraft.network.packet.c2s.play.UpdateSignC2SPacket; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; - -public class SearchOverManager { - - private static final MinecraftClient CLIENT = MinecraftClient.getInstance(); - private static final Logger LOGGER = LoggerFactory.getLogger("Skyblocker Search Overlay"); - - private static final Pattern BAZAAR_ENCHANTMENT_PATTERN = Pattern.compile("ENCHANTMENT_(\\D*)_(\\d+)"); - private static final Pattern AUCTION_PET_AND_RUNE_PATTERN = Pattern.compile("([A-Z0-9_]+);(\\d+)"); - - /** - * converts index (in array) +1 to a roman numeral - */ - private static final String[] ROMAN_NUMERALS = new String[]{ - "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", - "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX" - }; - - private static @Nullable SignBlockEntity sign = null; - private static boolean signFront = true; - private static boolean isAuction; - private static boolean isCommand; - - protected static String search = ""; - - // Use non-final variables and swap them to prevent concurrent modification - private static HashSet bazaarItems; - private static HashSet auctionItems; - private static HashMap namesToId; - - public static String[] suggestionsArray = {}; - - /** - * uses the skyblock api and Moulberry auction to load a list of items in bazaar and auction house - */ - public static void init() { - ClientCommandRegistrationCallback.EVENT.register(SearchOverManager::registerSearchCommands); - NEURepoManager.runAsyncAfterLoad(SearchOverManager::loadItems); - } - - private static void registerSearchCommands(CommandDispatcher dispatcher, CommandRegistryAccess registryAccess) { - if (SkyblockerConfigManager.get().general.searchOverlay.enableCommands) { - dispatcher.register(literal("ahs").executes(context -> startCommand(true))); - dispatcher.register(literal("bzs").executes(context -> startCommand(false))); - } - } - - private static int startCommand(boolean isAuction) { - isCommand = true; - SearchOverManager.isAuction = isAuction; - search = ""; - suggestionsArray = new String[]{}; - CLIENT.send(() -> CLIENT.setScreen(new OverlayScreen(Text.of("")))); - return Command.SINGLE_SUCCESS; - } - - private static void loadItems() { - HashSet bazaarItems = new HashSet<>(); - HashSet auctionItems = new HashSet<>(); - HashMap namesToId = new HashMap<>(); - - //get bazaar items - try { - if (TooltipInfoType.BAZAAR.getData() == null) TooltipInfoType.BAZAAR.run(); - - JsonObject products = TooltipInfoType.BAZAAR.getData(); - for (Map.Entry entry : products.entrySet()) { - if (entry.getValue().isJsonObject()) { - JsonObject product = entry.getValue().getAsJsonObject(); - String id = product.get("id").getAsString(); - int sellVolume = product.get("sellVolume").getAsInt(); - if (sellVolume == 0) - continue; //do not add items that do not sell e.g. they are not actual in the bazaar - Matcher matcher = BAZAAR_ENCHANTMENT_PATTERN.matcher(id); - if (matcher.matches()) {//format enchantments - //remove ultimate if in name - String name = matcher.group(1); - if (!name.contains("WISE")) { //only way found to remove ultimate from everything but ultimate wise - name = name.replace("ULTIMATE_", ""); - } - name = name.replace("_", " "); - name = capitalizeFully(name); - int enchantLevel = Integer.parseInt(matcher.group(2)); - String level = ""; - if (enchantLevel > 0) { - level = ROMAN_NUMERALS[enchantLevel - 1]; - } - bazaarItems.add(name + " " + level); - namesToId.put(name + " " + level, matcher.group(1) + ";" + matcher.group(2)); - continue; - } - //look up id for name - NEUItem neuItem = NEURepoManager.NEU_REPO.getItems().getItemBySkyblockId(id); - if (neuItem != null) { - String name = Formatting.strip(neuItem.getDisplayName()); - bazaarItems.add(name); - namesToId.put(name, id); - continue; - } - } - } - } catch (Exception e) { - LOGGER.error("[Skyblocker] Failed to load bazaar item list! ", e); - } - - //get auction items - try { - if (TooltipInfoType.THREE_DAY_AVERAGE.getData() == null) { - TooltipInfoType.THREE_DAY_AVERAGE.run(); - } - for (Map.Entry entry : TooltipInfoType.THREE_DAY_AVERAGE.getData().entrySet()) { - String id = entry.getKey(); - - Matcher matcher = AUCTION_PET_AND_RUNE_PATTERN.matcher(id); - if (matcher.find()) {//is a pet or rune convert id to name - String name = matcher.group(1).replace("_", " "); - name = capitalizeFully(name); - auctionItems.add(name); - namesToId.put(name, id); - continue; - } - //something else look up in NEU repo. - id = id.split("[+-]")[0]; - NEUItem neuItem = NEURepoManager.NEU_REPO.getItems().getItemBySkyblockId(id); - if (neuItem != null) { - String name = Formatting.strip(neuItem.getDisplayName()); - auctionItems.add(name); - namesToId.put(name, id); - continue; - } - } - } catch (Exception e) { - LOGGER.error("[Skyblocker] Failed to load auction house item list! ", e); - } - - SearchOverManager.bazaarItems = bazaarItems; - SearchOverManager.auctionItems = auctionItems; - SearchOverManager.namesToId = namesToId; - } - - /** - * Capitalizes the first letter off every word in a string - * @param str string to capitalize - */ - private static String capitalizeFully(String str) { - if (str == null || str.isEmpty()) { - return str; - } - - return Arrays.stream(str.split("\\s+")) - .map(t -> t.substring(0, 1).toUpperCase() + t.substring(1).toLowerCase()) - .collect(Collectors.joining(" ")); - } - - /** - * Receives data when a search is started and resets values - * @param sign the sign that is being edited - * @param front if it's the front of the sign - * @param isAuction if the sign is loaded from the auction house menu or bazaar - */ - public static void updateSign(@NotNull SignBlockEntity sign, boolean front, boolean isAuction) { - signFront = front; - SearchOverManager.sign = sign; - isCommand = false; - SearchOverManager.isAuction = isAuction; - if (SkyblockerConfigManager.get().general.searchOverlay.keepPreviousSearches) { - Text[] messages = SearchOverManager.sign.getText(signFront).getMessages(CLIENT.shouldFilterText()); - search = messages[0].getString(); - if (!messages[1].getString().isEmpty()) { - if (!search.endsWith(" ")) { - search += " "; - } - search += messages[1].getString(); - } - } else { - search = ""; - } - suggestionsArray = new String[]{}; - } - - /** - * Updates the search value and the suggestions based on that value. - * @param newValue new search value - */ - protected static void updateSearch(String newValue) { - search = newValue; - //update the suggestion values - int totalSuggestions = SkyblockerConfigManager.get().general.searchOverlay.maxSuggestions; - if (newValue.isBlank() || totalSuggestions == 0) return; //do not search for empty value - suggestionsArray = (isAuction ? auctionItems : bazaarItems).stream().filter(item -> item.toLowerCase().contains(search.toLowerCase())).limit(totalSuggestions).toArray(String[]::new); - } - - /** - * Gets the suggestion in the suggestion array at the index - * @param index index of suggestion - */ - protected static String getSuggestion(int index) { - if (suggestionsArray.length > index && suggestionsArray[index] != null) { - return suggestionsArray[index]; - } else {//there are no suggestions yet - return ""; - } - } - - protected static String getSuggestionId(int index) { - return namesToId.get(getSuggestion(index)); - } - - /** - * Gets the item name in the history array at the index - * @param index index of suggestion - */ - protected static String getHistory(int index) { - if (isAuction) { - if (SkyblockerConfigManager.get().general.searchOverlay.auctionHistory.size() > index) { - return SkyblockerConfigManager.get().general.searchOverlay.auctionHistory.get(index); - } - } else { - if (SkyblockerConfigManager.get().general.searchOverlay.bazaarHistory.size() > index) { - return SkyblockerConfigManager.get().general.searchOverlay.bazaarHistory.get(index); - } - } - return null; - } - - protected static String getHistoryId(int index) { - return namesToId.get(getHistory(index)); - } - - /** - * Add the current search value to the start of the history list and truncate to the max history value and save this to the config - */ - private static void saveHistory() { - //save to history - SkyblockerConfig.SearchOverlay config = SkyblockerConfigManager.get().general.searchOverlay; - if (isAuction) { - if (config.auctionHistory.isEmpty() || !config.auctionHistory.get(0).equals(search)) { - config.auctionHistory.add(0, search); - if (config.auctionHistory.size() > config.historyLength) { - config.auctionHistory = config.auctionHistory.subList(0, config.historyLength); - } - } - } else { - if (config.bazaarHistory.isEmpty() || !config.bazaarHistory.get(0).equals(search)) { - config.bazaarHistory.add(0, search); - if (config.bazaarHistory.size() > config.historyLength) { - config.bazaarHistory = config.bazaarHistory.subList(0, config.historyLength); - } - } - } - SkyblockerConfigManager.save(); - } - - /** - *Saves the current value of ({@link SearchOverManager#search}) then pushes it to a command or sign depending on how the gui was opened - */ - protected static void pushSearch() { - //save to history - if (!search.isEmpty()) { - saveHistory(); - } - if (isCommand) { - pushCommand(); - } else { - pushSign(); - } - } - - /** - * runs the command to search for the value in ({@link SearchOverManager#search}) - */ - private static void pushCommand() { - if (search.isEmpty()) return; - - String command; - if (isAuction) { - command = "/ahSearch " + search; - } else { - command = "/bz " + search; - } - MessageScheduler.INSTANCE.sendMessageAfterCooldown(command); - } - - /** - * pushes the ({@link SearchOverManager#search}) to the sign. It needs to split it over two lines without splitting a word - */ - private static void pushSign() { - //splits text into 2 lines max = 30 chars - Pair split = splitString(search); - - // send packet to update sign - if (CLIENT.player != null && sign != null) { - Text[] messages = sign.getText(signFront).getMessages(CLIENT.shouldFilterText()); - CLIENT.player.networkHandler.sendPacket(new UpdateSignC2SPacket(sign.getPos(), signFront, - split.left(), - split.right(), - messages[2].getString(), - messages[3].getString() - )); - } - } - - static Pair splitString(String s) { - if (s.length() <= 15) { - return Pair.of(s, ""); - } - int index = s.lastIndexOf(' ', 15); - if (index == -1) { - return Pair.of(s.substring(0, 15), ""); - } - return Pair.of(s.substring(0, index), s.substring(index + 1, Math.min(index + 16, s.length())).trim()); - } -} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/searchoverlay/OverlayScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/searchoverlay/OverlayScreen.java new file mode 100644 index 00000000..b8907e27 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/searchoverlay/OverlayScreen.java @@ -0,0 +1,185 @@ +package de.hysky.skyblocker.skyblock.searchoverlay; + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.item.ItemStack; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.Identifier; +import org.lwjgl.glfw.GLFW; + +import static de.hysky.skyblocker.skyblock.itemlist.ItemRepository.getItemStack; + +public class OverlayScreen extends Screen { + + protected static final Identifier SEARCH_ICON_TEXTURE = new Identifier("icon/search"); + private static final int rowHeight = 20; + private TextFieldWidget searchField; + private ButtonWidget finishedButton; + private ButtonWidget[] suggestionButtons; + private ButtonWidget[] historyButtons; + + public OverlayScreen(Text title) { + super(title); + } + + /** + * Creates the layout for the overlay screen. + */ + @Override + protected void init() { + super.init(); + int rowWidth = (int) (this.width * 0.4); + int startX = (int) (this.width * 0.5) - rowWidth / 2; + int startY = (int) ((int) (this.height * 0.5) - (rowHeight * (1 + SkyblockerConfigManager.get().general.searchOverlay.maxSuggestions + 0.75 + SkyblockerConfigManager.get().general.searchOverlay.historyLength)) / 2); + + // Search field + this.searchField = new TextFieldWidget(textRenderer, startX, startY, rowWidth - rowHeight, rowHeight, Text.translatable("gui.recipebook.search_hint")); + searchField.setText(SearchOverManager.search); + searchField.setChangedListener(SearchOverManager::updateSearch); + searchField.setMaxLength(30); + + // finish buttons + finishedButton = ButtonWidget.builder(Text.literal("").setStyle(Style.EMPTY.withColor(Formatting.GREEN)), a -> close()) + .position(startX + rowWidth - rowHeight, startY) + .size(rowHeight, rowHeight).build(); + + // suggested item buttons + int rowOffset = rowHeight; + int totalSuggestions = SkyblockerConfigManager.get().general.searchOverlay.maxSuggestions; + this.suggestionButtons = new ButtonWidget[totalSuggestions]; + for (int i = 0; i < totalSuggestions; i++) { + suggestionButtons[i] = ButtonWidget.builder(Text.literal(SearchOverManager.getSuggestion(i)).setStyle(Style.EMPTY), a -> { + SearchOverManager.updateSearch(a.getMessage().getString()); + close(); + }) + .position(startX, startY + rowOffset) + .size(rowWidth, rowHeight).build(); + suggestionButtons[i].visible = false; + rowOffset += rowHeight; + } + // history item buttons + rowOffset += (int) (rowHeight * 0.75); + int historyLength = SkyblockerConfigManager.get().general.searchOverlay.historyLength; + this.historyButtons = new ButtonWidget[historyLength]; + for (int i = 0; i < historyLength; i++) { + String text = SearchOverManager.getHistory(i); + if (text != null) { + historyButtons[i] = ButtonWidget.builder(Text.literal(text).setStyle(Style.EMPTY), (a) -> { + SearchOverManager.updateSearch(a.getMessage().getString()); + close(); + }) + .position(startX, startY + rowOffset) + .size(rowWidth, rowHeight).build(); + rowOffset += rowHeight; + } else { + break; + } + } + + //add drawables in order to make tab navigation sensible + addDrawableChild(searchField); + for (ButtonWidget suggestion : suggestionButtons) { + addDrawableChild(suggestion); + } + for (ButtonWidget historyOption : historyButtons) { + if (historyOption != null) { + addDrawableChild(historyOption); + } + } + addDrawableChild(finishedButton); + + //focus the search box + this.setInitialFocus(searchField); + } + + /** + * Renders the search icon, label for the history and item Stacks for item names + */ + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + super.render(context, mouseX, mouseY, delta); + int renderOffset = (rowHeight - 16) / 2; + context.drawGuiTexture(SEARCH_ICON_TEXTURE, finishedButton.getX() + renderOffset, finishedButton.getY() + renderOffset, 16, 16); + if (historyButtons.length > 0 && historyButtons[0] != null) { + context.drawText(textRenderer, Text.translatable("text.autoconfig.skyblocker.option.general.searchOverlay.historyLabel"), historyButtons[0].getX() + renderOffset, historyButtons[0].getY() - rowHeight / 2, 0xFFFFFFFF, true); + } + + //draw item stacks and tooltip to buttons + for (int i = 0; i < suggestionButtons.length; i++) { + drawItemAndTooltip(context, mouseX, mouseY, SearchOverManager.getSuggestionId(i), suggestionButtons[i], renderOffset); + } + for (int i = 0; i < historyButtons.length; i++) { + drawItemAndTooltip(context, mouseX, mouseY, SearchOverManager.getHistoryId(i), historyButtons[i], renderOffset); + } + } + + /** + * Draws the item and tooltip for the given button + */ + private void drawItemAndTooltip(DrawContext context, int mouseX, int mouseY, String id, ButtonWidget button, int renderOffset) { + if (id == null || id.isEmpty()) return; + ItemStack item = getItemStack(id); + if (item == null) return; + context.drawItem(item, button.getX() + renderOffset, button.getY() + renderOffset); + + // Draw tooltip + if (button.isMouseOver(mouseX, mouseY)) { + context.drawItemTooltip(textRenderer, item, mouseX, mouseY); + } + } + + /** + * updates if the suggestions buttons should be visible based on if they have a value + */ + @Override + public final void tick() { + super.tick(); + //update suggestion buttons text + for (int i = 0; i < SkyblockerConfigManager.get().general.searchOverlay.maxSuggestions; i++) { + String text = SearchOverManager.getSuggestion(i); + if (!text.isEmpty()) { + suggestionButtons[i].visible = true; + + boolean isNewText = !text.equals(suggestionButtons[i].getMessage().getString()); + if (!isNewText) continue; + + suggestionButtons[i].setMessage(Text.literal(text).setStyle(Style.EMPTY)); + } else { + suggestionButtons[i].visible = false; + } + } + } + + /** + * When a key is pressed. If enter key pressed and search box selected close + */ + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (keyCode == GLFW.GLFW_KEY_ENTER && searchField.isActive()) { + close(); + return true; + } + return super.keyPressed(keyCode, scanCode, modifiers); + } + + @Override + public boolean shouldPause() { + return false; + } + + /** + * Closes the overlay screen and gets the manager to send a packet update about the sign + */ + @Override + public void close() { + assert this.client != null; + assert this.client.player != null; + SearchOverManager.pushSearch(); + super.close(); + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/searchoverlay/SearchOverManager.java b/src/main/java/de/hysky/skyblocker/skyblock/searchoverlay/SearchOverManager.java new file mode 100644 index 00000000..1d740601 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/searchoverlay/SearchOverManager.java @@ -0,0 +1,349 @@ +package de.hysky.skyblocker.skyblock.searchoverlay; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.CommandDispatcher; +import de.hysky.skyblocker.config.SkyblockerConfig; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; +import de.hysky.skyblocker.utils.Http; +import de.hysky.skyblocker.utils.NEURepoManager; +import de.hysky.skyblocker.utils.scheduler.MessageScheduler; +import io.github.moulberry.repo.data.NEUItem; +import it.unimi.dsi.fastutil.Pair; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.block.entity.SignBlockEntity; +import net.minecraft.client.MinecraftClient; +import net.minecraft.command.CommandRegistryAccess; +import net.minecraft.network.packet.c2s.play.UpdateSignC2SPacket; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; + +public class SearchOverManager { + + private static final MinecraftClient CLIENT = MinecraftClient.getInstance(); + private static final Logger LOGGER = LoggerFactory.getLogger("Skyblocker Search Overlay"); + + private static final Pattern BAZAAR_ENCHANTMENT_PATTERN = Pattern.compile("ENCHANTMENT_(\\D*)_(\\d+)"); + private static final Pattern AUCTION_PET_AND_RUNE_PATTERN = Pattern.compile("([A-Z0-9_]+);(\\d+)"); + + /** + * converts index (in array) +1 to a roman numeral + */ + private static final String[] ROMAN_NUMERALS = new String[]{ + "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", + "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX" + }; + + private static @Nullable SignBlockEntity sign = null; + private static boolean signFront = true; + private static boolean isAuction; + private static boolean isCommand; + + protected static String search = ""; + + // Use non-final variables and swap them to prevent concurrent modification + private static HashSet bazaarItems; + private static HashSet auctionItems; + private static HashMap namesToId; + + public static String[] suggestionsArray = {}; + + /** + * uses the skyblock api and Moulberry auction to load a list of items in bazaar and auction house + */ + public static void init() { + ClientCommandRegistrationCallback.EVENT.register(SearchOverManager::registerSearchCommands); + NEURepoManager.runAsyncAfterLoad(SearchOverManager::loadItems); + } + + private static void registerSearchCommands(CommandDispatcher dispatcher, CommandRegistryAccess registryAccess) { + if (SkyblockerConfigManager.get().general.searchOverlay.enableCommands) { + dispatcher.register(literal("ahs").executes(context -> startCommand(true))); + dispatcher.register(literal("bzs").executes(context -> startCommand(false))); + } + } + + private static int startCommand(boolean isAuction) { + isCommand = true; + SearchOverManager.isAuction = isAuction; + search = ""; + suggestionsArray = new String[]{}; + CLIENT.send(() -> CLIENT.setScreen(new OverlayScreen(Text.of("")))); + return Command.SINGLE_SUCCESS; + } + + private static void loadItems() { + HashSet bazaarItems = new HashSet<>(); + HashSet auctionItems = new HashSet<>(); + HashMap namesToId = new HashMap<>(); + + //get bazaar items + try { + if (TooltipInfoType.BAZAAR.getData() == null) TooltipInfoType.BAZAAR.run(); + + JsonObject products = TooltipInfoType.BAZAAR.getData(); + for (Map.Entry entry : products.entrySet()) { + if (entry.getValue().isJsonObject()) { + JsonObject product = entry.getValue().getAsJsonObject(); + String id = product.get("id").getAsString(); + int sellVolume = product.get("sellVolume").getAsInt(); + if (sellVolume == 0) + continue; //do not add items that do not sell e.g. they are not actual in the bazaar + Matcher matcher = BAZAAR_ENCHANTMENT_PATTERN.matcher(id); + if (matcher.matches()) {//format enchantments + //remove ultimate if in name + String name = matcher.group(1); + if (!name.contains("WISE")) { //only way found to remove ultimate from everything but ultimate wise + name = name.replace("ULTIMATE_", ""); + } + name = name.replace("_", " "); + name = capitalizeFully(name); + int enchantLevel = Integer.parseInt(matcher.group(2)); + String level = ""; + if (enchantLevel > 0) { + level = ROMAN_NUMERALS[enchantLevel - 1]; + } + bazaarItems.add(name + " " + level); + namesToId.put(name + " " + level, matcher.group(1) + ";" + matcher.group(2)); + continue; + } + //look up id for name + NEUItem neuItem = NEURepoManager.NEU_REPO.getItems().getItemBySkyblockId(id); + if (neuItem != null) { + String name = Formatting.strip(neuItem.getDisplayName()); + bazaarItems.add(name); + namesToId.put(name, id); + continue; + } + } + } + } catch (Exception e) { + LOGGER.error("[Skyblocker] Failed to load bazaar item list! ", e); + } + + //get auction items + try { + if (TooltipInfoType.THREE_DAY_AVERAGE.getData() == null) { + TooltipInfoType.THREE_DAY_AVERAGE.run(); + } + for (Map.Entry entry : TooltipInfoType.THREE_DAY_AVERAGE.getData().entrySet()) { + String id = entry.getKey(); + + Matcher matcher = AUCTION_PET_AND_RUNE_PATTERN.matcher(id); + if (matcher.find()) {//is a pet or rune convert id to name + String name = matcher.group(1).replace("_", " "); + name = capitalizeFully(name); + auctionItems.add(name); + namesToId.put(name, id); + continue; + } + //something else look up in NEU repo. + id = id.split("[+-]")[0]; + NEUItem neuItem = NEURepoManager.NEU_REPO.getItems().getItemBySkyblockId(id); + if (neuItem != null) { + String name = Formatting.strip(neuItem.getDisplayName()); + auctionItems.add(name); + namesToId.put(name, id); + continue; + } + } + } catch (Exception e) { + LOGGER.error("[Skyblocker] Failed to load auction house item list! ", e); + } + + SearchOverManager.bazaarItems = bazaarItems; + SearchOverManager.auctionItems = auctionItems; + SearchOverManager.namesToId = namesToId; + } + + /** + * Capitalizes the first letter off every word in a string + * @param str string to capitalize + */ + private static String capitalizeFully(String str) { + if (str == null || str.isEmpty()) { + return str; + } + + return Arrays.stream(str.split("\\s+")) + .map(t -> t.substring(0, 1).toUpperCase() + t.substring(1).toLowerCase()) + .collect(Collectors.joining(" ")); + } + + /** + * Receives data when a search is started and resets values + * @param sign the sign that is being edited + * @param front if it's the front of the sign + * @param isAuction if the sign is loaded from the auction house menu or bazaar + */ + public static void updateSign(@NotNull SignBlockEntity sign, boolean front, boolean isAuction) { + signFront = front; + SearchOverManager.sign = sign; + isCommand = false; + SearchOverManager.isAuction = isAuction; + if (SkyblockerConfigManager.get().general.searchOverlay.keepPreviousSearches) { + Text[] messages = SearchOverManager.sign.getText(signFront).getMessages(CLIENT.shouldFilterText()); + search = messages[0].getString(); + if (!messages[1].getString().isEmpty()) { + if (!search.endsWith(" ")) { + search += " "; + } + search += messages[1].getString(); + } + } else { + search = ""; + } + suggestionsArray = new String[]{}; + } + + /** + * Updates the search value and the suggestions based on that value. + * @param newValue new search value + */ + protected static void updateSearch(String newValue) { + search = newValue; + //update the suggestion values + int totalSuggestions = SkyblockerConfigManager.get().general.searchOverlay.maxSuggestions; + if (newValue.isBlank() || totalSuggestions == 0) return; //do not search for empty value + suggestionsArray = (isAuction ? auctionItems : bazaarItems).stream().filter(item -> item.toLowerCase().contains(search.toLowerCase())).limit(totalSuggestions).toArray(String[]::new); + } + + /** + * Gets the suggestion in the suggestion array at the index + * @param index index of suggestion + */ + protected static String getSuggestion(int index) { + if (suggestionsArray.length > index && suggestionsArray[index] != null) { + return suggestionsArray[index]; + } else {//there are no suggestions yet + return ""; + } + } + + protected static String getSuggestionId(int index) { + return namesToId.get(getSuggestion(index)); + } + + /** + * Gets the item name in the history array at the index + * @param index index of suggestion + */ + protected static String getHistory(int index) { + if (isAuction) { + if (SkyblockerConfigManager.get().general.searchOverlay.auctionHistory.size() > index) { + return SkyblockerConfigManager.get().general.searchOverlay.auctionHistory.get(index); + } + } else { + if (SkyblockerConfigManager.get().general.searchOverlay.bazaarHistory.size() > index) { + return SkyblockerConfigManager.get().general.searchOverlay.bazaarHistory.get(index); + } + } + return null; + } + + protected static String getHistoryId(int index) { + return namesToId.get(getHistory(index)); + } + + /** + * Add the current search value to the start of the history list and truncate to the max history value and save this to the config + */ + private static void saveHistory() { + //save to history + SkyblockerConfig.SearchOverlay config = SkyblockerConfigManager.get().general.searchOverlay; + if (isAuction) { + if (config.auctionHistory.isEmpty() || !config.auctionHistory.get(0).equals(search)) { + config.auctionHistory.add(0, search); + if (config.auctionHistory.size() > config.historyLength) { + config.auctionHistory = config.auctionHistory.subList(0, config.historyLength); + } + } + } else { + if (config.bazaarHistory.isEmpty() || !config.bazaarHistory.get(0).equals(search)) { + config.bazaarHistory.add(0, search); + if (config.bazaarHistory.size() > config.historyLength) { + config.bazaarHistory = config.bazaarHistory.subList(0, config.historyLength); + } + } + } + SkyblockerConfigManager.save(); + } + + /** + *Saves the current value of ({@link SearchOverManager#search}) then pushes it to a command or sign depending on how the gui was opened + */ + protected static void pushSearch() { + //save to history + if (!search.isEmpty()) { + saveHistory(); + } + if (isCommand) { + pushCommand(); + } else { + pushSign(); + } + } + + /** + * runs the command to search for the value in ({@link SearchOverManager#search}) + */ + private static void pushCommand() { + if (search.isEmpty()) return; + + String command; + if (isAuction) { + command = "/ahSearch " + search; + } else { + command = "/bz " + search; + } + MessageScheduler.INSTANCE.sendMessageAfterCooldown(command); + } + + /** + * pushes the ({@link SearchOverManager#search}) to the sign. It needs to split it over two lines without splitting a word + */ + private static void pushSign() { + //splits text into 2 lines max = 30 chars + Pair split = splitString(search); + + // send packet to update sign + if (CLIENT.player != null && sign != null) { + Text[] messages = sign.getText(signFront).getMessages(CLIENT.shouldFilterText()); + CLIENT.player.networkHandler.sendPacket(new UpdateSignC2SPacket(sign.getPos(), signFront, + split.left(), + split.right(), + messages[2].getString(), + messages[3].getString() + )); + } + } + + public static Pair splitString(String s) { + if (s.length() <= 15) { + return Pair.of(s, ""); + } + int index = s.lastIndexOf(' ', 15); + if (index == -1) { + return Pair.of(s.substring(0, 15), ""); + } + return Pair.of(s.substring(0, index), s.substring(index + 1, Math.min(index + 16, s.length())).trim()); + } +} -- cgit From c2e4a0513ef19aac52c38478fdd34a8d93990e75 Mon Sep 17 00:00:00 2001 From: Ghost <66458557+Ghost-3@users.noreply.github.com> Date: Sun, 18 Feb 2024 22:12:10 +0300 Subject: Better location management (#547) * Better location management * Location enum rework * Removed unused constants --- .../skyblocker/skyblock/crimson/kuudra/Kuudra.java | 1 - .../de/hysky/skyblocker/skyblock/rift/TheRift.java | 5 - .../java/de/hysky/skyblocker/utils/Location.java | 116 +++++++++++++++++++++ src/main/java/de/hysky/skyblocker/utils/Utils.java | 80 ++++++++------ 4 files changed, 167 insertions(+), 35 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/utils/Location.java (limited to 'src/main/java') 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/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/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 Hypixel API + */ + private final String id; + + /** + * @param id location id from Hypixel API + */ + Location(String id) { + this.id = id; + } + + /** + * @return location id + */ + public String id() { + return this.id; + } + + /** + * @param id location id from Hypixel API + * @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,14 +35,16 @@ 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. */ @@ -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() { @@ -132,6 +131,14 @@ public class Utils { return profileId; } + /** + * @return the location parsed from /locraw. + */ + @NotNull + public static Location getLocation() { + return location; + } + /** * @return the server parsed from /locraw.