From 7769de8c37ca43da2fed332effddbe284f601b32 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 28 May 2024 19:05:25 +0300 Subject: Tooltip manager initial commit --- .../java/de/hysky/skyblocker/SkyblockerMod.java | 3 +- .../skyblocker/mixins/HandledScreenMixin.java | 506 +++++++++++---------- .../skyblocker/utils/tooltip/TooltipAdder.java | 35 ++ .../skyblocker/utils/tooltip/TooltipManager.java | 56 +++ 4 files changed, 352 insertions(+), 248 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipAdder.java create mode 100644 src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index 19eb395a..5243ff46 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -35,7 +35,6 @@ import de.hysky.skyblocker.skyblock.item.tooltip.AccessoriesHelper; import de.hysky.skyblocker.skyblock.item.tooltip.BackpackPreview; 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.shortcut.Shortcuts; @@ -56,6 +55,7 @@ import de.hysky.skyblocker.utils.render.gui.ContainerSolverManager; import de.hysky.skyblocker.utils.render.title.TitleContainer; import de.hysky.skyblocker.utils.scheduler.MessageScheduler; import de.hysky.skyblocker.utils.scheduler.Scheduler; +import de.hysky.skyblocker.utils.tooltip.TooltipManager; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.loader.api.FabricLoader; @@ -187,6 +187,7 @@ public class SkyblockerMod implements ClientModInitializer { EggFinder.init(); TimeTowerReminder.init(); SkyblockTime.init(); + TooltipManager.init(); Scheduler.INSTANCE.scheduleCyclic(Utils::update, 20); Scheduler.INSTANCE.scheduleCyclic(DiscordRPCManager::updateDataAndPresence, 200); diff --git a/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java index f662be7c..a5f8c5cd 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java @@ -1,5 +1,7 @@ package de.hysky.skyblocker.mixins; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; import com.mojang.blaze3d.systems.RenderSystem; import de.hysky.skyblocker.SkyblockerMod; @@ -19,9 +21,12 @@ import de.hysky.skyblocker.skyblock.quicknav.QuickNavButton; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.render.gui.ContainerSolver; +import de.hysky.skyblocker.utils.tooltip.TooltipManager; +import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.client.item.TooltipData; import net.minecraft.inventory.SimpleInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -45,256 +50,263 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.regex.Matcher; @Mixin(HandledScreen.class) public abstract class HandledScreenMixin extends Screen { - /** - * This is the slot id returned for when a click is outside the screen's bounds - */ - @Unique - private static final int OUT_OF_BOUNDS_SLOT = -999; - - @Unique - private static final Identifier ITEM_PROTECTION = new Identifier(SkyblockerMod.NAMESPACE, "textures/gui/item_protection.png"); - - @Unique - private static final Set FILLER_ITEMS = Set.of( - " ", // Empty menu item - "Locked Page", - "Quick Crafting Slot", - "Locked Backpack Slot 2", //Regular expressions won't be utilized here since the search by contains is based on plain text rather than regex syntax - "Locked Backpack Slot 3", - "Locked Backpack Slot 4", - "Locked Backpack Slot 5", - "Locked Backpack Slot 6", - "Locked Backpack Slot 7", - "Locked Backpack Slot 8", - "Locked Backpack Slot 9", - "Locked Backpack Slot 10", - "Locked Backpack Slot 11", - "Locked Backpack Slot 12", - "Locked Backpack Slot 13", - "Locked Backpack Slot 14", - "Locked Backpack Slot 15", - "Locked Backpack Slot 16", - "Locked Backpack Slot 17", - "Locked Backpack Slot 18", - "Preparing" - ); - - @Shadow - @Nullable - protected Slot focusedSlot; - - @Shadow - @Final - protected T handler; - - @Unique - private List quickNavButtons; - - protected HandledScreenMixin(Text title) { - super(title); - } - - @Inject(method = "init", at = @At("RETURN")) - private void skyblocker$initQuickNav(CallbackInfo ci) { - if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().quickNav.enableQuickNav && client != null && client.player != null && !client.player.isCreative()) { - for (QuickNavButton quickNavButton : quickNavButtons = QuickNav.init(getTitle().getString().trim())) { - addSelectableChild(quickNavButton); - } - } - } - - @Inject(at = @At("HEAD"), method = "keyPressed") - public void skyblocker$keyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable cir) { - if (this.client != null && this.focusedSlot != null && keyCode != 256) { - //wiki lookup - if (!this.client.options.inventoryKey.matchesKey(keyCode, scanCode) && WikiLookup.wikiLookup.matchesKey(keyCode, scanCode) && client.player != null) { - WikiLookup.openWiki(this.focusedSlot, client.player); - } - //item protection - if (!this.client.options.inventoryKey.matchesKey(keyCode, scanCode) && ItemProtection.itemProtection.matchesKey(keyCode, scanCode)) { - ItemProtection.handleKeyPressed(this.focusedSlot.getStack()); - } - } - } - - @Inject(at = @At("HEAD"), method = "mouseClicked") - public void skyblocker$mouseClicked(double mouseX, double mouseY, int button, CallbackInfoReturnable cir) { - if (SkyblockerConfigManager.get().farming.garden.visitorHelper && (Utils.getLocationRaw().equals("garden") && !getTitle().getString().contains("Logbook") || getTitle().getString().startsWith("Bazaar"))) { - VisitorHelper.onMouseClicked(mouseX, mouseY, button, this.textRenderer); - } - } - - /** - * Draws the unselected tabs in front of the background blur, but behind the main inventory, similar to creative inventory tabs - */ - @Inject(method = "renderBackground", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawBackground(Lnet/minecraft/client/gui/DrawContext;FII)V")) - private void skyblocker$drawUnselectedQuickNavButtons(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) { - if (quickNavButtons != null) for (QuickNavButton quickNavButton : quickNavButtons) { - if (!quickNavButton.toggled()) { - quickNavButton.render(context, mouseX, mouseY, delta); - } - } - } - - /** - * Draws the selected tab in front of the background blur and the main inventory, similar to creative inventory tabs - */ - @Inject(method = "renderBackground", at = @At("RETURN")) - private void skyblocker$drawSelectedQuickNavButtons(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) { - if (quickNavButtons != null) for (QuickNavButton quickNavButton : quickNavButtons) { - if (quickNavButton.toggled()) { - quickNavButton.render(context, mouseX, mouseY, delta); - } - } - } - - @SuppressWarnings("DataFlowIssue") - // makes intellij be quiet about this.focusedSlot maybe being null. It's already null checked in mixined method. - @Inject(method = "drawMouseoverTooltip", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawTooltip(Lnet/minecraft/client/font/TextRenderer;Ljava/util/List;Ljava/util/Optional;II)V"), cancellable = true) - public void skyblocker$drawMouseOverTooltip(DrawContext context, int x, int y, CallbackInfo ci, @Local(ordinal = 0) ItemStack stack) { - if (!Utils.isOnSkyblock()) return; - - // Hide Empty Tooltips - if (SkyblockerConfigManager.get().uiAndVisuals.hideEmptyTooltips && stack.getName().getString().equals(" ")) { - ci.cancel(); - } - - // Backpack Preview - boolean shiftDown = SkyblockerConfigManager.get().uiAndVisuals.backpackPreviewWithoutShift ^ Screen.hasShiftDown(); - if (shiftDown && getTitle().getString().equals("Storage") && focusedSlot.inventory != client.player.getInventory() && BackpackPreview.renderPreview(context, this, focusedSlot.getIndex(), x, y)) { - ci.cancel(); - } - - // Compactor Preview - if (SkyblockerConfigManager.get().uiAndVisuals.compactorDeletorPreview) { - Matcher matcher = CompactorDeletorPreview.NAME.matcher(ItemUtils.getItemId(stack)); - if (matcher.matches() && CompactorDeletorPreview.drawPreview(context, stack, matcher.group("type"), matcher.group("size"), x, y)) { - ci.cancel(); - } - } - } - - @ModifyVariable(method = "drawMouseoverTooltip", at = @At(value = "LOAD", ordinal = 0)) - private ItemStack skyblocker$experimentSolvers$replaceTooltipDisplayStack(ItemStack stack) { - return skyblocker$experimentSolvers$getStack(focusedSlot, stack); - } - - @ModifyVariable(method = "drawSlot", at = @At(value = "LOAD", ordinal = 3), ordinal = 0) - private ItemStack skyblocker$experimentSolvers$replaceDisplayStack(ItemStack stack, DrawContext context, Slot slot) { - return skyblocker$experimentSolvers$getStack(slot, stack); - } - - /** - * Redirects getStack calls to account for different stacks in experiment solvers. - */ - @Unique - private ItemStack skyblocker$experimentSolvers$getStack(Slot slot, @NotNull ItemStack stack) { - ContainerSolver currentSolver = SkyblockerMod.getInstance().containerSolverManager.getCurrentSolver(); - if ((currentSolver instanceof SuperpairsSolver || currentSolver instanceof UltrasequencerSolver) && ((ExperimentSolver) currentSolver).getState() == ExperimentSolver.State.SHOW && slot.inventory instanceof SimpleInventory) { - ItemStack itemStack = ((ExperimentSolver) currentSolver).getSlots().get(slot.getIndex()); - return itemStack == null ? stack : itemStack; - } - return stack; - } - - /** - * The naming of this method in yarn is half true, its mostly to handle slot/item interactions (which are mouse or keyboard clicks) - * For example, using the drop key bind while hovering over an item will invoke this method to drop the players item - * - * @implNote This runs before {@link ScreenHandler#onSlotClick(int, int, SlotActionType, net.minecraft.entity.player.PlayerEntity)} - */ - @Inject(method = "onMouseClick(Lnet/minecraft/screen/slot/Slot;IILnet/minecraft/screen/slot/SlotActionType;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;clickSlot(IIILnet/minecraft/screen/slot/SlotActionType;Lnet/minecraft/entity/player/PlayerEntity;)V"), cancellable = true) - private void skyblocker$onSlotClick(Slot slot, int slotId, int button, SlotActionType actionType, CallbackInfo ci) { - if (!Utils.isOnSkyblock()) return; - - // Item Protection - // When you try and drop the item by picking it up then clicking outside the screen - if (slotId == OUT_OF_BOUNDS_SLOT && ItemProtection.isItemProtected(this.handler.getCursorStack())) { - ci.cancel(); - return; - } - - if (slot == null) return; - String title = getTitle().getString(); - ItemStack stack = skyblocker$experimentSolvers$getStack(slot, slot.getStack()); - ContainerSolver currentSolver = SkyblockerMod.getInstance().containerSolverManager.getCurrentSolver(); - - // Prevent clicks on filler items - if (SkyblockerConfigManager.get().uiAndVisuals.hideEmptyTooltips && FILLER_ITEMS.contains(stack.getName().getString()) && - // Allow clicks in Ultrasequencer and Superpairs - (!UltrasequencerSolver.INSTANCE.getName().matcher(title).matches() || SkyblockerConfigManager.get().helpers.experiments.enableUltrasequencerSolver)) { - ci.cancel(); - return; - } - // Item Protection - // When you click your drop key while hovering over an item - if (actionType == SlotActionType.THROW && ItemProtection.isItemProtected(stack)) { - ci.cancel(); - return; - } - // Prevent salvaging - if (title.equals("Salvage Items") && ItemProtection.isItemProtected(stack)) { - ci.cancel(); - return; - } - if (this.handler instanceof GenericContainerScreenHandler genericContainerScreenHandler && genericContainerScreenHandler.getRows() == 6) { - VisitorHelper.onSlotClick(slot, slotId, title, genericContainerScreenHandler.getSlot(13).getStack()); - - // Prevent selling to NPC shops - ItemStack sellStack = this.handler.slots.get(49).getStack(); - if (sellStack.getName().getString().equals("Sell Item") || ItemUtils.getLoreLineIf(sellStack, text -> text.contains("buyback")) != null) { - if (slotId != 49 && ItemProtection.isItemProtected(stack)) { - ci.cancel(); - return; - } - } - } - - if (currentSolver != null) { - boolean disallowed = SkyblockerMod.getInstance().containerSolverManager.onSlotClick(slotId, stack); - - if (disallowed) ci.cancel(); - } - - // Experiment Solvers - if (currentSolver instanceof ExperimentSolver experimentSolver && experimentSolver.getState() == ExperimentSolver.State.SHOW && slot.inventory instanceof SimpleInventory) { - switch (experimentSolver) { - case ChronomatronSolver chronomatronSolver -> { - Item item = chronomatronSolver.getChronomatronSlots().get(chronomatronSolver.getChronomatronCurrentOrdinal()); - if ((stack.isOf(item) || ChronomatronSolver.TERRACOTTA_TO_GLASS.get(stack.getItem()) == item) && chronomatronSolver.incrementChronomatronCurrentOrdinal() >= chronomatronSolver.getChronomatronSlots().size()) { - chronomatronSolver.setState(ExperimentSolver.State.END); - } - } - - case SuperpairsSolver superpairsSolver -> { - superpairsSolver.setSuperpairsPrevClickedSlot(slot.getIndex()); - superpairsSolver.setSuperpairsCurrentSlot(ItemStack.EMPTY); - } - - case UltrasequencerSolver ultrasequencerSolver when slot.getIndex() == ultrasequencerSolver.getUltrasequencerNextSlot() -> { - int count = ultrasequencerSolver.getSlots().get(ultrasequencerSolver.getUltrasequencerNextSlot()).getCount() + 1; - ultrasequencerSolver.getSlots().entrySet().stream().filter(entry -> entry.getValue().getCount() == count).findAny().map(Map.Entry::getKey).ifPresentOrElse(ultrasequencerSolver::setUltrasequencerNextSlot, () -> ultrasequencerSolver.setState(ExperimentSolver.State.END)); - } - - default -> { /*Do Nothing*/ } - } - } - } - - @Inject(method = "drawSlot", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawItem(Lnet/minecraft/item/ItemStack;III)V")) - private void skyblocker$drawItemRarityBackground(DrawContext context, Slot slot, CallbackInfo ci) { - if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().general.itemInfoDisplay.itemRarityBackgrounds) - ItemRarityBackgrounds.tryDraw(slot.getStack(), context, slot.x, slot.y); - // Item protection - if (ItemProtection.isItemProtected(slot.getStack())) { - RenderSystem.enableBlend(); - context.drawTexture(ITEM_PROTECTION, slot.x, slot.y, 0, 0, 16, 16, 16, 16); - RenderSystem.disableBlend(); - } - } + /** + * This is the slot id returned for when a click is outside the screen's bounds + */ + @Unique + private static final int OUT_OF_BOUNDS_SLOT = -999; + + @Unique + private static final Identifier ITEM_PROTECTION = new Identifier(SkyblockerMod.NAMESPACE, "textures/gui/item_protection.png"); + + @Unique + private static final Set FILLER_ITEMS = Set.of( + " ", // Empty menu item + "Locked Page", + "Quick Crafting Slot", + "Locked Backpack Slot 2", //Regular expressions won't be utilized here since the search by contains is based on plain text rather than regex syntax + "Locked Backpack Slot 3", + "Locked Backpack Slot 4", + "Locked Backpack Slot 5", + "Locked Backpack Slot 6", + "Locked Backpack Slot 7", + "Locked Backpack Slot 8", + "Locked Backpack Slot 9", + "Locked Backpack Slot 10", + "Locked Backpack Slot 11", + "Locked Backpack Slot 12", + "Locked Backpack Slot 13", + "Locked Backpack Slot 14", + "Locked Backpack Slot 15", + "Locked Backpack Slot 16", + "Locked Backpack Slot 17", + "Locked Backpack Slot 18", + "Preparing" + ); + + @Shadow + @Nullable + protected Slot focusedSlot; + + @Shadow + @Final + protected T handler; + + @Unique + private List quickNavButtons; + + protected HandledScreenMixin(Text title) { + super(title); + } + + @Inject(method = "init", at = @At("RETURN")) + private void skyblocker$initQuickNav(CallbackInfo ci) { + if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().quickNav.enableQuickNav && client != null && client.player != null && !client.player.isCreative()) { + for (QuickNavButton quickNavButton : quickNavButtons = QuickNav.init(getTitle().getString().trim())) { + addSelectableChild(quickNavButton); + } + } + } + + @Inject(at = @At("HEAD"), method = "keyPressed") + public void skyblocker$keyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable cir) { + if (this.client != null && this.focusedSlot != null && keyCode != 256) { + //wiki lookup + if (!this.client.options.inventoryKey.matchesKey(keyCode, scanCode) && WikiLookup.wikiLookup.matchesKey(keyCode, scanCode) && client.player != null) { + WikiLookup.openWiki(this.focusedSlot, client.player); + } + //item protection + if (!this.client.options.inventoryKey.matchesKey(keyCode, scanCode) && ItemProtection.itemProtection.matchesKey(keyCode, scanCode)) { + ItemProtection.handleKeyPressed(this.focusedSlot.getStack()); + } + } + } + + @Inject(at = @At("HEAD"), method = "mouseClicked") + public void skyblocker$mouseClicked(double mouseX, double mouseY, int button, CallbackInfoReturnable cir) { + if (SkyblockerConfigManager.get().farming.garden.visitorHelper && (Utils.getLocationRaw().equals("garden") && !getTitle().getString().contains("Logbook") || getTitle().getString().startsWith("Bazaar"))) { + VisitorHelper.onMouseClicked(mouseX, mouseY, button, this.textRenderer); + } + } + + /** + * Draws the unselected tabs in front of the background blur, but behind the main inventory, similar to creative inventory tabs + */ + @Inject(method = "renderBackground", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawBackground(Lnet/minecraft/client/gui/DrawContext;FII)V")) + private void skyblocker$drawUnselectedQuickNavButtons(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) { + if (quickNavButtons != null) for (QuickNavButton quickNavButton : quickNavButtons) { + if (!quickNavButton.toggled()) { + quickNavButton.render(context, mouseX, mouseY, delta); + } + } + } + + /** + * Draws the selected tab in front of the background blur and the main inventory, similar to creative inventory tabs + */ + @Inject(method = "renderBackground", at = @At("RETURN")) + private void skyblocker$drawSelectedQuickNavButtons(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) { + if (quickNavButtons != null) for (QuickNavButton quickNavButton : quickNavButtons) { + if (quickNavButton.toggled()) { + quickNavButton.render(context, mouseX, mouseY, delta); + } + } + } + + @SuppressWarnings("DataFlowIssue") + // makes intellij be quiet about this.focusedSlot maybe being null. It's already null checked in mixined method. + @Inject(method = "drawMouseoverTooltip", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawTooltip(Lnet/minecraft/client/font/TextRenderer;Ljava/util/List;Ljava/util/Optional;II)V"), cancellable = true) + public void skyblocker$drawMouseOverTooltip(DrawContext context, int x, int y, CallbackInfo ci, @Local(ordinal = 0) ItemStack stack) { + if (!Utils.isOnSkyblock()) return; + + // Hide Empty Tooltips + if (SkyblockerConfigManager.get().uiAndVisuals.hideEmptyTooltips && stack.getName().getString().equals(" ")) { + ci.cancel(); + } + + // Backpack Preview + boolean shiftDown = SkyblockerConfigManager.get().uiAndVisuals.backpackPreviewWithoutShift ^ Screen.hasShiftDown(); + if (shiftDown && getTitle().getString().equals("Storage") && focusedSlot.inventory != client.player.getInventory() && BackpackPreview.renderPreview(context, this, focusedSlot.getIndex(), x, y)) { + ci.cancel(); + } + + // Compactor Preview + if (SkyblockerConfigManager.get().uiAndVisuals.compactorDeletorPreview) { + Matcher matcher = CompactorDeletorPreview.NAME.matcher(ItemUtils.getItemId(stack)); + if (matcher.matches() && CompactorDeletorPreview.drawPreview(context, stack, matcher.group("type"), matcher.group("size"), x, y)) { + ci.cancel(); + } + } + } + + @ModifyVariable(method = "drawMouseoverTooltip", at = @At(value = "LOAD", ordinal = 0)) + private ItemStack skyblocker$experimentSolvers$replaceTooltipDisplayStack(ItemStack stack) { + return skyblocker$experimentSolvers$getStack(focusedSlot, stack); + } + + @SuppressWarnings("deprecation") + @WrapOperation(method = "drawMouseoverTooltip", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawTooltip(Lnet/minecraft/client/font/TextRenderer;Ljava/util/List;Ljava/util/Optional;II)V")) + private void skyblocker$tooltips$drawMouseoverTooltip(DrawContext context, TextRenderer textRenderer, List text, Optional data, int x, int y, Operation original) { + original.call(context, textRenderer, TooltipManager.addToTooltip(text, focusedSlot), data, x, y); + } + + @ModifyVariable(method = "drawSlot", at = @At(value = "LOAD", ordinal = 3), ordinal = 0) + private ItemStack skyblocker$experimentSolvers$replaceDisplayStack(ItemStack stack, DrawContext context, Slot slot) { + return skyblocker$experimentSolvers$getStack(slot, stack); + } + + /** + * Redirects getStack calls to account for different stacks in experiment solvers. + */ + @Unique + private ItemStack skyblocker$experimentSolvers$getStack(Slot slot, @NotNull ItemStack stack) { + ContainerSolver currentSolver = SkyblockerMod.getInstance().containerSolverManager.getCurrentSolver(); + if ((currentSolver instanceof SuperpairsSolver || currentSolver instanceof UltrasequencerSolver) && ((ExperimentSolver) currentSolver).getState() == ExperimentSolver.State.SHOW && slot.inventory instanceof SimpleInventory) { + ItemStack itemStack = ((ExperimentSolver) currentSolver).getSlots().get(slot.getIndex()); + return itemStack == null ? stack : itemStack; + } + return stack; + } + + /** + * The naming of this method in yarn is half true, its mostly to handle slot/item interactions (which are mouse or keyboard clicks) + * For example, using the drop key bind while hovering over an item will invoke this method to drop the players item + * + * @implNote This runs before {@link ScreenHandler#onSlotClick(int, int, SlotActionType, net.minecraft.entity.player.PlayerEntity)} + */ + @Inject(method = "onMouseClick(Lnet/minecraft/screen/slot/Slot;IILnet/minecraft/screen/slot/SlotActionType;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;clickSlot(IIILnet/minecraft/screen/slot/SlotActionType;Lnet/minecraft/entity/player/PlayerEntity;)V"), cancellable = true) + private void skyblocker$onSlotClick(Slot slot, int slotId, int button, SlotActionType actionType, CallbackInfo ci) { + if (!Utils.isOnSkyblock()) return; + + // Item Protection + // When you try and drop the item by picking it up then clicking outside the screen + if (slotId == OUT_OF_BOUNDS_SLOT && ItemProtection.isItemProtected(this.handler.getCursorStack())) { + ci.cancel(); + return; + } + + if (slot == null) return; + String title = getTitle().getString(); + ItemStack stack = skyblocker$experimentSolvers$getStack(slot, slot.getStack()); + ContainerSolver currentSolver = SkyblockerMod.getInstance().containerSolverManager.getCurrentSolver(); + + // Prevent clicks on filler items + if (SkyblockerConfigManager.get().uiAndVisuals.hideEmptyTooltips && FILLER_ITEMS.contains(stack.getName().getString()) && + // Allow clicks in Ultrasequencer and Superpairs + (!UltrasequencerSolver.INSTANCE.getName().matcher(title).matches() || SkyblockerConfigManager.get().helpers.experiments.enableUltrasequencerSolver)) { + ci.cancel(); + return; + } + // Item Protection + // When you click your drop key while hovering over an item + if (actionType == SlotActionType.THROW && ItemProtection.isItemProtected(stack)) { + ci.cancel(); + return; + } + // Prevent salvaging + if (title.equals("Salvage Items") && ItemProtection.isItemProtected(stack)) { + ci.cancel(); + return; + } + if (this.handler instanceof GenericContainerScreenHandler genericContainerScreenHandler && genericContainerScreenHandler.getRows() == 6) { + VisitorHelper.onSlotClick(slot, slotId, title, genericContainerScreenHandler.getSlot(13).getStack()); + + // Prevent selling to NPC shops + ItemStack sellStack = this.handler.slots.get(49).getStack(); + if (sellStack.getName().getString().equals("Sell Item") || ItemUtils.getLoreLineIf(sellStack, text -> text.contains("buyback")) != null) { + if (slotId != 49 && ItemProtection.isItemProtected(stack)) { + ci.cancel(); + return; + } + } + } + + if (currentSolver != null) { + boolean disallowed = SkyblockerMod.getInstance().containerSolverManager.onSlotClick(slotId, stack); + + if (disallowed) ci.cancel(); + } + + // Experiment Solvers + if (currentSolver instanceof ExperimentSolver experimentSolver && experimentSolver.getState() == ExperimentSolver.State.SHOW && slot.inventory instanceof SimpleInventory) { + switch (experimentSolver) { + case ChronomatronSolver chronomatronSolver -> { + Item item = chronomatronSolver.getChronomatronSlots().get(chronomatronSolver.getChronomatronCurrentOrdinal()); + if ((stack.isOf(item) || ChronomatronSolver.TERRACOTTA_TO_GLASS.get(stack.getItem()) == item) && chronomatronSolver.incrementChronomatronCurrentOrdinal() >= chronomatronSolver.getChronomatronSlots().size()) { + chronomatronSolver.setState(ExperimentSolver.State.END); + } + } + + case SuperpairsSolver superpairsSolver -> { + superpairsSolver.setSuperpairsPrevClickedSlot(slot.getIndex()); + superpairsSolver.setSuperpairsCurrentSlot(ItemStack.EMPTY); + } + + case UltrasequencerSolver ultrasequencerSolver when slot.getIndex() == ultrasequencerSolver.getUltrasequencerNextSlot() -> { + int count = ultrasequencerSolver.getSlots().get(ultrasequencerSolver.getUltrasequencerNextSlot()).getCount() + 1; + ultrasequencerSolver.getSlots().entrySet().stream().filter(entry -> entry.getValue().getCount() == count).findAny().map(Map.Entry::getKey).ifPresentOrElse(ultrasequencerSolver::setUltrasequencerNextSlot, () -> ultrasequencerSolver.setState(ExperimentSolver.State.END)); + } + + default -> { /*Do Nothing*/ } + } + } + } + + @Inject(method = "drawSlot", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawItem(Lnet/minecraft/item/ItemStack;III)V")) + private void skyblocker$drawItemRarityBackground(DrawContext context, Slot slot, CallbackInfo ci) { + if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().general.itemInfoDisplay.itemRarityBackgrounds) + ItemRarityBackgrounds.tryDraw(slot.getStack(), context, slot.x, slot.y); + // Item protection + if (ItemProtection.isItemProtected(slot.getStack())) { + RenderSystem.enableBlend(); + context.drawTexture(ITEM_PROTECTION, slot.x, slot.y, 0, 0, 16, 16, 16, 16); + RenderSystem.disableBlend(); + } + } } diff --git a/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipAdder.java b/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipAdder.java new file mode 100644 index 00000000..1e628e99 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipAdder.java @@ -0,0 +1,35 @@ +package de.hysky.skyblocker.utils.tooltip; + +import net.minecraft.screen.slot.Slot; +import net.minecraft.text.Text; + +import java.util.List; +import java.util.regex.Pattern; + +/** + * Extend this class and add it to {@link TooltipManager#adders} to add additional text to tooltips. + */ +public abstract class TooltipAdder { + public final Pattern titlePattern; + //Lower priority means it will be applied first + public final int priority; + + protected TooltipAdder(String titlePattern, int priority) { + this(Pattern.compile(titlePattern), priority); + } + + protected TooltipAdder(Pattern titlePattern, int priority) { + this.titlePattern = titlePattern; + this.priority = priority; + } + + /** + * Creates a TooltipAdder that will be applied to all screens. + */ + protected TooltipAdder(int priority) { + this.titlePattern = null; + this.priority = priority; + } + + public abstract void addToTooltip(List lore, Slot focusedSlot); +} diff --git a/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java b/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java new file mode 100644 index 00000000..6a744283 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java @@ -0,0 +1,56 @@ +package de.hysky.skyblocker.utils.tooltip; + +import de.hysky.skyblocker.utils.Utils; +import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.screen.slot.Slot; +import net.minecraft.text.Text; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +public class TooltipManager { + private static final TooltipAdder[] adders = new TooltipAdder[]{}; + private static final ArrayList currentScreenAdders = new ArrayList<>(); + + private TooltipManager() { + } + + public static void init() { + ScreenEvents.AFTER_INIT.register((client, screen, width, height) -> { + onScreenChange(screen); + ScreenEvents.remove(screen).register(ignored -> currentScreenAdders.clear()); + }); + } + + private static void onScreenChange(Screen screen) { + final String title = screen.getTitle().getString(); + for (TooltipAdder adder : adders) { + if (adder.titlePattern == null || adder.titlePattern.matcher(title).matches()) { + currentScreenAdders.add(adder); + } + } + currentScreenAdders.sort(Comparator.comparingInt(adder -> adder.priority)); + } + + /** + *

Adds additional text from all adders that are applicable to the current screen. + * This method is run on each tooltip render, so don't do any heavy calculations here.

+ * + *

If you want to add info to the tooltips of multiple items, consider using a switch statement with {@code focusedSlot.getIndex()}

+ * + * @param lore The lore of the focused item. + * @param focusedSlot The slot that is currently focused by the cursor. + * @return The lore itself after all adders have added their text. + * @deprecated This method is public only for the sake of the mixin. Don't call directly, not that there is any point to it. + */ + @Deprecated + public static List addToTooltip(List lore, Slot focusedSlot) { + if (!Utils.isOnSkyblock()) return lore; + for (TooltipAdder adder : currentScreenAdders) { + adder.addToTooltip(lore, focusedSlot); + } + return lore; + } +} -- cgit From a6148c72d4d53c916a73de979519109a378f2451 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 28 May 2024 19:28:52 +0300 Subject: Refactor line smoothener --- .../chocolatefactory/ChocolateFactorySolver.java | 4 +-- .../skyblock/item/tooltip/ItemTooltip.java | 20 -------------- .../skyblocker/utils/tooltip/LineSmoothener.java | 31 ++++++++++++++++++++++ .../skyblocker/utils/tooltip/TooltipManager.java | 4 ++- 4 files changed, 36 insertions(+), 23 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/utils/tooltip/LineSmoothener.java (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java index e04e632a..cd622934 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -1,11 +1,11 @@ package de.hysky.skyblocker.skyblock.chocolatefactory; import de.hysky.skyblocker.config.SkyblockerConfigManager; -import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.RegexUtils; import de.hysky.skyblocker.utils.render.gui.ColorHighlight; import de.hysky.skyblocker.utils.render.gui.ContainerSolver; +import de.hysky.skyblocker.utils.tooltip.LineSmoothener; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback; @@ -182,7 +182,7 @@ public class ChocolateFactorySolver extends ContainerSolver { } //This is an ArrayList, so this operation is probably not very efficient, but logically it's pretty much the only way I can think of - if (shouldAddLine) lines.add(lineIndex, ItemTooltip.createSmoothLine()); + if (shouldAddLine) lines.add(lineIndex, LineSmoothener.createSmoothLine()); } private static boolean addUpgradeTimerToLore(List lines, long cost) { 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 031817ac..505c4c8b 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 @@ -22,7 +22,6 @@ import net.minecraft.nbt.NbtElement; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Formatting; - import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,8 +38,6 @@ public class ItemTooltip { public static void getTooltip(ItemStack stack, Item.TooltipContext tooltipContext, TooltipType tooltipType, List lines) { if (!Utils.isOnSkyblock() || client.player == null) return; - smoothenLines(lines); - String name = getInternalNameFromNBT(stack, false); String internalID = getInternalNameFromNBT(stack, true); String neuName = name; @@ -394,23 +391,6 @@ public class ItemTooltip { return message; } - //This is static to not create a new text object for each line in every item - private static final Text BUMPY_LINE = Text.literal("-----------------").formatted(Formatting.DARK_GRAY, Formatting.STRIKETHROUGH); - - private static void smoothenLines(List lines) { - for (int i = 0; i < lines.size(); i++) { - List lineSiblings = lines.get(i).getSiblings(); - //Compare the first sibling rather than the whole object as the style of the root object can change while visually staying the same - if (lineSiblings.size() == 1 && lineSiblings.getFirst().equals(BUMPY_LINE)) { - lines.set(i, createSmoothLine()); - } - } - } - - public static Text createSmoothLine() { - return Text.literal(" ").formatted(Formatting.DARK_GRAY, Formatting.STRIKETHROUGH, Formatting.BOLD); - } - // 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 = 0; diff --git a/src/main/java/de/hysky/skyblocker/utils/tooltip/LineSmoothener.java b/src/main/java/de/hysky/skyblocker/utils/tooltip/LineSmoothener.java new file mode 100644 index 00000000..1096f7b0 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/tooltip/LineSmoothener.java @@ -0,0 +1,31 @@ +package de.hysky.skyblocker.utils.tooltip; + +import net.minecraft.screen.slot.Slot; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +import java.util.List; + +public class LineSmoothener extends TooltipAdder { + //This is static to not create a new text object for each line in every item + private static final Text BUMPY_LINE = Text.literal("-----------------").formatted(Formatting.DARK_GRAY, Formatting.STRIKETHROUGH); + + public static Text createSmoothLine() { + return Text.literal(" ").formatted(Formatting.DARK_GRAY, Formatting.STRIKETHROUGH, Formatting.BOLD); + } + + protected LineSmoothener() { + super(Integer.MIN_VALUE); + } + + @Override + public void addToTooltip(List lore, Slot focusedSlot) { + for (int i = 0; i < lore.size(); i++) { + List lineSiblings = lore.get(i).getSiblings(); + //Compare the first sibling rather than the whole object as the style of the root object can change while visually staying the same + if (lineSiblings.size() == 1 && lineSiblings.getFirst().equals(BUMPY_LINE)) { + lore.set(i, createSmoothLine()); + } + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java b/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java index 6a744283..7d32e3cd 100644 --- a/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java +++ b/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java @@ -11,7 +11,9 @@ import java.util.Comparator; import java.util.List; public class TooltipManager { - private static final TooltipAdder[] adders = new TooltipAdder[]{}; + private static final TooltipAdder[] adders = new TooltipAdder[]{ + new LineSmoothener() + }; private static final ArrayList currentScreenAdders = new ArrayList<>(); private TooltipManager() { -- cgit From a0bc7dc00f47cf1986120b47ccb23f6116660dda Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 28 May 2024 19:58:47 +0300 Subject: Refactor dungeon quality tooltip --- .../skyblock/item/tooltip/ItemTooltip.java | 41 ++-------------- .../utils/tooltip/DungeonQualityTooltip.java | 55 ++++++++++++++++++++++ .../skyblocker/utils/tooltip/TooltipManager.java | 3 +- 3 files changed, 62 insertions(+), 37 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/utils/tooltip/DungeonQualityTooltip.java (limited to 'src/main/java/de') 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 505c4c8b..5183e901 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 @@ -26,7 +26,10 @@ import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Optional; import java.util.concurrent.CompletableFuture; public class ItemTooltip { @@ -125,40 +128,6 @@ public class ItemTooltip { } } - final Map itemTierFloors = Map.ofEntries( - Map.entry(0, "E"), - Map.entry(1, "F1"), - Map.entry(2, "F2"), - Map.entry(3, "F3"), - Map.entry(4, "F4/M1"), - Map.entry(5, "F5/M2"), - Map.entry(6, "F6/M3"), - Map.entry(7, "F7/M4"), - Map.entry(8, "M5"), - Map.entry(9, "M6"), - Map.entry(10, "M7") - ); - - if (SkyblockerConfigManager.get().general.itemTooltip.dungeonQuality) { - NbtCompound customData = ItemUtils.getCustomData(stack); - if (customData != null && customData.contains("baseStatBoostPercentage")) { - int baseStatBoostPercentage = customData.getInt("baseStatBoostPercentage"); - 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 (customData.contains("item_tier")) { // sometimes it just isn't here? - int itemTier = customData.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)); - } - } - } - } if (TooltipInfoType.MOTES.isTooltipEnabledAndHasOrNullWarning(internalID)) { lines.add(Text.literal(String.format("%-20s", "Motes Price:")) @@ -436,4 +405,4 @@ public class ItemTooltip { }); }, 1200, true); } -} +} \ No newline at end of file diff --git a/src/main/java/de/hysky/skyblocker/utils/tooltip/DungeonQualityTooltip.java b/src/main/java/de/hysky/skyblocker/utils/tooltip/DungeonQualityTooltip.java new file mode 100644 index 00000000..f7be590e --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/tooltip/DungeonQualityTooltip.java @@ -0,0 +1,55 @@ +package de.hysky.skyblocker.utils.tooltip; + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.ItemUtils; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.screen.slot.Slot; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +import java.util.List; + +public class DungeonQualityTooltip extends TooltipAdder { + protected DungeonQualityTooltip(int priority) { + super(priority); + } + + @Override + public void addToTooltip(List lore, Slot focusedSlot) { + if (!SkyblockerConfigManager.get().general.itemTooltip.dungeonQuality) return; + NbtCompound customData = ItemUtils.getCustomData(focusedSlot.getStack()); + if (customData == null || !customData.contains("baseStatBoostPercentage")) return; + int baseStatBoostPercentage = customData.getInt("baseStatBoostPercentage"); + boolean maxQuality = baseStatBoostPercentage == 50; + if (maxQuality) { + lore.add(Text.literal(String.format("%-17s", "Item Quality:") + baseStatBoostPercentage + "/50").formatted(Formatting.RED).formatted(Formatting.BOLD)); + } else { + lore.add(Text.literal(String.format("%-21s", "Item Quality:") + baseStatBoostPercentage + "/50").formatted(Formatting.BLUE)); + } + + if (customData.contains("item_tier")) { // sometimes it just isn't here? + int itemTier = customData.getInt("item_tier"); + if (maxQuality) { + lore.add(Text.literal(String.format("%-17s", "Floor Tier:") + itemTier + " (" + getItemTierFloor(itemTier) + ")").formatted(Formatting.RED).formatted(Formatting.BOLD)); + } else { + lore.add(Text.literal(String.format("%-21s", "Floor Tier:") + itemTier + " (" + getItemTierFloor(itemTier) + ")").formatted(Formatting.BLUE)); + } + } + } + + final String getItemTierFloor(int tier) { + return switch (tier) { + case 1 -> "F1"; + case 2 -> "F2"; + case 3 -> "F3"; + case 4 -> "F4/M1"; + case 5 -> "F5/M2"; + case 6 -> "F6/M3"; + case 7 -> "F7/M4"; + case 8 -> "M5"; + case 9 -> "M6"; + case 10 -> "M7"; + default -> "Unknown"; + }; + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java b/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java index 7d32e3cd..82f02445 100644 --- a/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java +++ b/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java @@ -12,7 +12,8 @@ import java.util.List; public class TooltipManager { private static final TooltipAdder[] adders = new TooltipAdder[]{ - new LineSmoothener() + new LineSmoothener(), + new DungeonQualityTooltip(0) }; private static final ArrayList currentScreenAdders = new ArrayList<>(); -- cgit From 4015ba2f5d79ece643a97c457d2c663f8ef519e7 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 28 May 2024 20:06:50 +0300 Subject: Refactor obtained date tooltip --- .../skyblock/item/tooltip/ItemTooltip.java | 9 --- .../java/de/hysky/skyblocker/utils/ItemUtils.java | 41 ------------- .../skyblocker/utils/tooltip/ObtainedTooltip.java | 71 ++++++++++++++++++++++ .../skyblocker/utils/tooltip/TooltipManager.java | 3 +- 4 files changed, 73 insertions(+), 51 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/utils/tooltip/ObtainedTooltip.java (limited to 'src/main/java/de') 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 5183e901..a008fcf9 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 @@ -135,15 +135,6 @@ public class ItemTooltip { .append(getMotesMessage(TooltipInfoType.MOTES.getData().get(internalID).getAsInt(), count))); } - if (TooltipInfoType.OBTAINED.isTooltipEnabled()) { - String timestamp = ItemUtils.getTimestamp(stack); - - if (!timestamp.isEmpty()) { - lines.add(Text.literal(String.format("%-21s", "Obtained: ")) - .formatted(Formatting.LIGHT_PURPLE) - .append(Text.literal(timestamp).formatted(Formatting.RED))); - } - } if (TooltipInfoType.MUSEUM.isTooltipEnabledAndHasOrNullWarning(internalID) && !bazaarOpened) { String itemCategory = TooltipInfoType.MUSEUM.getData().get(internalID).getAsString(); diff --git a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java index 13b28808..fbc9bddc 100644 --- a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java @@ -20,7 +20,6 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtElement; import net.minecraft.registry.Registries; import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.text.Text; @@ -29,13 +28,7 @@ import net.minecraft.util.dynamic.Codecs; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.time.Instant; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.time.temporal.TemporalAccessor; -import java.util.Iterator; import java.util.List; -import java.util.Locale; import java.util.Optional; import java.util.function.Predicate; import java.util.regex.Matcher; @@ -46,8 +39,6 @@ import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.lit public class ItemUtils { public static final String ID = "id"; public static final String UUID = "uuid"; - private static final DateTimeFormatter OBTAINED_DATE_FORMATTER = DateTimeFormatter.ofPattern("MMMM d, yyyy").withZone(ZoneId.systemDefault()).localizedBy(Locale.ENGLISH); - private static final DateTimeFormatter OLD_OBTAINED_DATE_FORMAT = DateTimeFormatter.ofPattern("M/d/yy h:m a").withZone(ZoneId.of("UTC")).localizedBy(Locale.ENGLISH); public static final Pattern NOT_DURABILITY = Pattern.compile("[^0-9 /]"); public static final Predicate FUEL_PREDICATE = line -> line.contains("Fuel: "); private static final Codec> EMPTY_ALLOWING_ITEM_CODEC = Registries.ITEM.getEntryCodec(); @@ -111,38 +102,6 @@ public class ItemUtils { return getCustomData(stack).getString(UUID); } - /** - * This method converts the "timestamp" variable into the same date format as Hypixel represents it in the museum. - * Currently, there are two types of string timestamps the legacy which is built like this - * "dd/MM/yy hh:mm" ("25/04/20 16:38") and the current which is built like this - * "MM/dd/yy hh:mm aa" ("12/24/20 11:08 PM"). Since Hypixel transforms the two formats into one format without - * taking into account of their formats, we do the same. The final result looks like this - * "MMMM dd, yyyy" (December 24, 2020). - * Since the legacy format has a 25 as "month" SimpleDateFormat converts the 25 into 2 years and 1 month and makes - * "25/04/20 16:38" -> "January 04, 2022" instead of "April 25, 2020". - * This causes the museum rank to be much worse than it should be. - *

- * This also handles the long timestamp format introduced in January 2024 where the timestamp is in epoch milliseconds. - * - * @param stack the item under the pointer - * @return if the item have a "Timestamp" it will be shown formated on the tooltip - */ - public static String getTimestamp(ItemStack stack) { - NbtCompound customData = getCustomData(stack); - - if (customData != null && customData.contains("timestamp", NbtElement.LONG_TYPE)) { - Instant date = Instant.ofEpochMilli(customData.getLong("timestamp")); - return OBTAINED_DATE_FORMATTER.format(date); - } - - if (customData != null && customData.contains("timestamp", NbtElement.STRING_TYPE)) { - TemporalAccessor date = OLD_OBTAINED_DATE_FORMAT.parse(customData.getString("timestamp")); - return OBTAINED_DATE_FORMATTER.format(date); - } - - return ""; - } - public static boolean hasCustomDurability(@NotNull ItemStack stack) { NbtCompound customData = getCustomData(stack); return customData != null && (customData.contains("drill_fuel") || customData.getString(ID).equals("PICKONIMBUS")); diff --git a/src/main/java/de/hysky/skyblocker/utils/tooltip/ObtainedTooltip.java b/src/main/java/de/hysky/skyblocker/utils/tooltip/ObtainedTooltip.java new file mode 100644 index 00000000..f6bcd2f2 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/tooltip/ObtainedTooltip.java @@ -0,0 +1,71 @@ +package de.hysky.skyblocker.utils.tooltip; + +import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; +import de.hysky.skyblocker.utils.ItemUtils; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.screen.slot.Slot; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAccessor; +import java.util.List; +import java.util.Locale; + +public class ObtainedTooltip extends TooltipAdder { + private static final DateTimeFormatter OBTAINED_DATE_FORMATTER = DateTimeFormatter.ofPattern("MMMM d, yyyy").withZone(ZoneId.systemDefault()).localizedBy(Locale.ENGLISH); + private static final DateTimeFormatter OLD_OBTAINED_DATE_FORMAT = DateTimeFormatter.ofPattern("M/d/yy h:m a").withZone(ZoneId.of("UTC")).localizedBy(Locale.ENGLISH); + + protected ObtainedTooltip(int priority) { + super(priority); + } + + @Override + public void addToTooltip(List lore, Slot focusedSlot) { + if (TooltipInfoType.OBTAINED.isTooltipEnabled()) { + String timestamp = getTimestamp(focusedSlot.getStack()); + + if (!timestamp.isEmpty()) { + lore.add(Text.empty() + .append(Text.literal(String.format("%-21s", "Obtained: ")).formatted(Formatting.LIGHT_PURPLE)) + .append(Text.literal(timestamp).formatted(Formatting.RED))); + } + } + } + + /** + * This method converts the "timestamp" variable into the same date format as Hypixel represents it in the museum. + * Currently, there are two types of string timestamps the legacy which is built like this + * "dd/MM/yy hh:mm" ("25/04/20 16:38") and the current which is built like this + * "MM/dd/yy hh:mm aa" ("12/24/20 11:08 PM"). Since Hypixel transforms the two formats into one format without + * taking into account of their formats, we do the same. The final result looks like this + * "MMMM dd, yyyy" (December 24, 2020). + * Since the legacy format has a 25 as "month" SimpleDateFormat converts the 25 into 2 years and 1 month and makes + * "25/04/20 16:38" -> "January 04, 2022" instead of "April 25, 2020". + * This causes the museum rank to be much worse than it should be. + *

+ * This also handles the long timestamp format introduced in January 2024 where the timestamp is in epoch milliseconds. + * + * @param stack the item under the pointer + * @return if the item have a "Timestamp" it will be shown formated on the tooltip + */ + public static String getTimestamp(ItemStack stack) { + NbtCompound customData = ItemUtils.getCustomData(stack); + + if (customData != null && customData.contains("timestamp", NbtElement.LONG_TYPE)) { + Instant date = Instant.ofEpochMilli(customData.getLong("timestamp")); + return OBTAINED_DATE_FORMATTER.format(date); + } + + if (customData != null && customData.contains("timestamp", NbtElement.STRING_TYPE)) { + TemporalAccessor date = OLD_OBTAINED_DATE_FORMAT.parse(customData.getString("timestamp")); + return OBTAINED_DATE_FORMATTER.format(date); + } + + return ""; + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java b/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java index 82f02445..e71ec115 100644 --- a/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java +++ b/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java @@ -13,7 +13,8 @@ import java.util.List; public class TooltipManager { private static final TooltipAdder[] adders = new TooltipAdder[]{ new LineSmoothener(), - new DungeonQualityTooltip(0) + new DungeonQualityTooltip(0), + new ObtainedTooltip(1), }; private static final ArrayList currentScreenAdders = new ArrayList<>(); -- cgit From 6969632aacfefebcffaa676e51b6b0b929d961d7 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 28 May 2024 21:01:39 +0300 Subject: Refactor motes tooltip --- .../skyblock/item/tooltip/ItemTooltip.java | 27 ------------ .../skyblocker/utils/tooltip/MotesTooltip.java | 50 ++++++++++++++++++++++ .../skyblocker/utils/tooltip/TooltipManager.java | 1 + 3 files changed, 51 insertions(+), 27 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/utils/tooltip/MotesTooltip.java (limited to 'src/main/java/de') 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 a008fcf9..04764a79 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 @@ -129,13 +129,6 @@ public class ItemTooltip { } - if (TooltipInfoType.MOTES.isTooltipEnabledAndHasOrNullWarning(internalID)) { - lines.add(Text.literal(String.format("%-20s", "Motes Price:")) - .formatted(Formatting.LIGHT_PURPLE) - .append(getMotesMessage(TooltipInfoType.MOTES.getData().get(internalID).getAsInt(), count))); - } - - if (TooltipInfoType.MUSEUM.isTooltipEnabledAndHasOrNullWarning(internalID) && !bazaarOpened) { String itemCategory = TooltipInfoType.MUSEUM.getData().get(internalID).getAsString(); String format = switch (itemCategory) { @@ -331,26 +324,6 @@ public class ItemTooltip { return message; } - private static Text getMotesMessage(int price, int count) { - float motesMultiplier = SkyblockerConfigManager.get().otherLocations.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) { - return Text.literal(totalPriceString.replace(".0", "") + " Motes").formatted(Formatting.DARK_AQUA); - } - - // 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 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 = 0; diff --git a/src/main/java/de/hysky/skyblocker/utils/tooltip/MotesTooltip.java b/src/main/java/de/hysky/skyblocker/utils/tooltip/MotesTooltip.java new file mode 100644 index 00000000..79a58a62 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/tooltip/MotesTooltip.java @@ -0,0 +1,50 @@ +package de.hysky.skyblocker.utils.tooltip; + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; +import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.slot.Slot; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +import java.util.List; +import java.util.Locale; + +public class MotesTooltip extends TooltipAdder { + protected MotesTooltip(int priority) { + super(priority); + } + + @Override + public void addToTooltip(List lore, Slot focusedSlot) { + final ItemStack itemStack = focusedSlot.getStack(); + final String internalID = ItemTooltip.getInternalNameFromNBT(itemStack, true); + if (internalID != null && TooltipInfoType.MOTES.isTooltipEnabledAndHasOrNullWarning(internalID)) { + lore.add(Text.literal(String.format("%-20s", "Motes Price:")) + .formatted(Formatting.LIGHT_PURPLE) + .append(getMotesMessage(TooltipInfoType.MOTES.getData().get(internalID).getAsInt(), itemStack.getCount()))); + } + } + + private static Text getMotesMessage(int price, int count) { + float motesMultiplier = SkyblockerConfigManager.get().otherLocations.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) { + return Text.literal(totalPriceString.replace(".0", "") + " Motes").formatted(Formatting.DARK_AQUA); + } + + // 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 message; + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java b/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java index e71ec115..4def0a04 100644 --- a/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java +++ b/src/main/java/de/hysky/skyblocker/utils/tooltip/TooltipManager.java @@ -15,6 +15,7 @@ public class TooltipManager { new LineSmoothener(), new DungeonQualityTooltip(0), new ObtainedTooltip(1), + new MotesTooltip(0) }; private static final ArrayList currentScreenAdders = new ArrayList<>(); -- cgit From f559aa2b0a945d27fb5e78076e55f4e3b31e016e Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Wed, 29 May 2024 09:08:08 +0300 Subject: Refactor npc price tooltip --- .../skyblock/item/tooltip/ItemTooltip.java | 20 +++++----------- .../skyblocker/utils/tooltip/NpcPriceTooltip.java | 27 ++++++++++++++++++++++ .../skyblocker/utils/tooltip/TooltipManager.java | 5 ++-- 3 files changed, 36 insertions(+), 16 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/utils/tooltip/NpcPriceTooltip.java (limited to 'src/main/java/de') 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 04764a79..776e301d 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 @@ -56,17 +56,10 @@ public class ItemTooltip { } int count = stack.getCount(); - boolean bazaarOpened = lines.stream().anyMatch(each -> each.getString().contains("Buy price:") || each.getString().contains("Sell price:")); - - if (TooltipInfoType.NPC.isTooltipEnabledAndHasOrNullWarning(internalID)) { - lines.add(Text.literal(String.format("%-21s", "NPC Sell Price:")) - .formatted(Formatting.YELLOW) - .append(getCoinsMessage(TooltipInfoType.NPC.getData().get(internalID).getAsDouble(), count))); - } boolean bazaarExist = false; - if (TooltipInfoType.BAZAAR.isTooltipEnabledAndHasOrNullWarning(name) && !bazaarOpened) { + if (TooltipInfoType.BAZAAR.isTooltipEnabledAndHasOrNullWarning(name)) { JsonObject getItem = TooltipInfoType.BAZAAR.getData().getAsJsonObject(name); lines.add(Text.literal(String.format("%-18s", "Bazaar buy Price:")) .formatted(Formatting.GOLD) @@ -83,7 +76,7 @@ public class ItemTooltip { // bazaarOpened & bazaarExist check for lbin, because Skytils keeps some bazaar item data in lbin api boolean lbinExist = false; - if (TooltipInfoType.LOWEST_BINS.isTooltipEnabledAndHasOrNullWarning(name) && !bazaarOpened && !bazaarExist) { + if (TooltipInfoType.LOWEST_BINS.isTooltipEnabledAndHasOrNullWarni