diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java index bf98ac1fbd..a1e1dadc52 100644 --- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java @@ -250,6 +250,9 @@ public static class General { @SerialEntry public SearchOverlay searchOverlay = new SearchOverlay(); + @SerialEntry + public FancyAuctionHouse fancyAuctionHouse = new FancyAuctionHouse(); + @SerialEntry public List lockedSlots = new ArrayList<>(); @@ -406,138 +409,11 @@ public static class QuiverWarning { public boolean enableQuiverWarningAfterDungeon = true; } - public static class Hitbox { - @SerialEntry - public boolean oldFarmlandHitbox = false; - - @SerialEntry - public boolean oldLeverHitbox = false; - } - - public static class TitleContainer { - @SerialEntry - public float titleContainerScale = 100; - - @SerialEntry - public int x = 540; - - @SerialEntry - public int y = 10; - - @SerialEntry - public Direction direction = Direction.HORIZONTAL; - - @SerialEntry - public Alignment alignment = Alignment.MIDDLE; - } - - public enum Direction { - HORIZONTAL, VERTICAL; - - @Override - public String toString() { - return switch (this) { - case HORIZONTAL -> "Horizontal"; - case VERTICAL -> "Vertical"; - }; - } - } - - public enum Alignment { - LEFT, RIGHT, MIDDLE; - - @Override - public String toString() { - return switch (this) { - case LEFT -> "Left"; - case RIGHT -> "Right"; - case MIDDLE -> "Middle"; - }; - } - } - - public static class TeleportOverlay { - @SerialEntry - public boolean enableTeleportOverlays = true; - - @SerialEntry - public boolean enableWeirdTransmission = true; - - @SerialEntry - public boolean enableInstantTransmission = true; - - @SerialEntry - public boolean enableEtherTransmission = true; - - @SerialEntry - public boolean enableSinrecallTransmission = true; - - @SerialEntry - public boolean enableWitherImpact = true; - } - - public static class FlameOverlay { - @SerialEntry - public int flameHeight = 100; - - @SerialEntry - public int flameOpacity = 100; - } - - public static class SearchOverlay { - @SerialEntry - public boolean enableBazaar = true; - - @SerialEntry - public boolean enableAuctionHouse = true; - - @SerialEntry - public boolean keepPreviousSearches = false; - - @SerialEntry - public int maxSuggestions = 3; - - @SerialEntry - public int historyLength = 3; - - @SerialEntry - public boolean enableCommands = false; - - @SerialEntry - public List bazaarHistory = new ArrayList<>(); - - @SerialEntry - public List auctionHistory = new ArrayList<>(); - } - - public static class RichPresence { - @SerialEntry - public boolean enableRichPresence = false; - - @SerialEntry - public Info info = Info.LOCATION; - - @SerialEntry - public boolean cycleMode = false; - - @SerialEntry - public String customMessage = "Playing Skyblock"; - } - public static class ItemList { @SerialEntry public boolean enableItemList = true; } - public enum Average { - ONE_DAY, THREE_DAY, BOTH; - - @Override - public String toString() { - return I18n.translate("text.autoconfig.skyblocker.option.general.itemTooltip.avg." + name()); - } - } - public static class ItemTooltip { @SerialEntry public boolean enableNPCPrice = true; @@ -570,6 +446,15 @@ public static class ItemTooltip { public boolean enableAccessoriesHelper = true; } + public enum Average { + ONE_DAY, THREE_DAY, BOTH; + + @Override + public String toString() { + return I18n.translate("text.autoconfig.skyblocker.option.general.itemTooltip.avg." + name()); + } + } + public static class ItemInfoDisplay { @SerialEntry public boolean attributeShardInfo = true; @@ -651,6 +536,118 @@ public static class SpecialEffects { public boolean rareDungeonDropEffects = true; } + public static class Hitbox { + @SerialEntry + public boolean oldFarmlandHitbox = false; + + @SerialEntry + public boolean oldLeverHitbox = false; + } + + public static class TitleContainer { + @SerialEntry + public float titleContainerScale = 100; + + @SerialEntry + public int x = 540; + + @SerialEntry + public int y = 10; + + @SerialEntry + public Direction direction = Direction.HORIZONTAL; + + @SerialEntry + public Alignment alignment = Alignment.MIDDLE; + } + + public enum Direction { + HORIZONTAL, VERTICAL; + + @Override + public String toString() { + return switch (this) { + case HORIZONTAL -> "Horizontal"; + case VERTICAL -> "Vertical"; + }; + } + } + + public enum Alignment { + LEFT, RIGHT, MIDDLE; + + @Override + public String toString() { + return switch (this) { + case LEFT -> "Left"; + case RIGHT -> "Right"; + case MIDDLE -> "Middle"; + }; + } + } + + public static class TeleportOverlay { + @SerialEntry + public boolean enableTeleportOverlays = true; + + @SerialEntry + public boolean enableWeirdTransmission = true; + + @SerialEntry + public boolean enableInstantTransmission = true; + + @SerialEntry + public boolean enableEtherTransmission = true; + + @SerialEntry + public boolean enableSinrecallTransmission = true; + + @SerialEntry + public boolean enableWitherImpact = true; + } + + public static class FlameOverlay { + @SerialEntry + public int flameHeight = 100; + + @SerialEntry + public int flameOpacity = 100; + } + + public static class SearchOverlay { + @SerialEntry + public boolean enableBazaar = true; + + @SerialEntry + public boolean enableAuctionHouse = true; + + @SerialEntry + public boolean keepPreviousSearches = false; + + @SerialEntry + public int maxSuggestions = 3; + + @SerialEntry + public int historyLength = 3; + + @SerialEntry + public boolean enableCommands = false; + + @SerialEntry + public List bazaarHistory = new ArrayList<>(); + + @SerialEntry + public List auctionHistory = new ArrayList<>(); + } + + public static class FancyAuctionHouse { + @SerialEntry + public boolean enabled = true; + + @SerialEntry + public boolean highlightCheapBIN = true; + } + public static class Locations { @SerialEntry public Barn barn = new Barn(); @@ -1242,6 +1239,20 @@ public static class ChatRuleConfig { public int announcementScale = 3; } + public static class RichPresence { + @SerialEntry + public boolean enableRichPresence = false; + + @SerialEntry + public Info info = Info.LOCATION; + + @SerialEntry + public boolean cycleMode = false; + + @SerialEntry + public String customMessage = "Playing Skyblock"; + } + public enum Info { PURSE, BITS, LOCATION; diff --git a/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java index e310cb85c0..a74b9483c4 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java @@ -739,6 +739,26 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig .controller(ConfigUtils::createBooleanController) .build()) .build()) + + // Fancy Auction House + .group(OptionGroup.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.betterAuctionHouse")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.betterAuctionHouse.enabled")) + .binding(defaults.general.fancyAuctionHouse.enabled, + () -> config.general.fancyAuctionHouse.enabled, + newValue -> config.general.fancyAuctionHouse.enabled = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.betterAuctionHouse.highlightUnderAvgPrice")) + .binding(defaults.general.fancyAuctionHouse.highlightCheapBIN, + () -> config.general.fancyAuctionHouse.highlightCheapBIN, + newValue -> config.general.fancyAuctionHouse.highlightCheapBIN = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .build()) .build(); } } diff --git a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java index ceda9ed4db..049443f723 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java @@ -2,6 +2,8 @@ import com.mojang.authlib.GameProfile; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.auction.AuctionViewScreen; +import de.hysky.skyblocker.skyblock.auction.EditBidPopup; import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen; import de.hysky.skyblocker.skyblock.item.HotbarSlotLock; import de.hysky.skyblocker.skyblock.item.ItemProtection; @@ -58,6 +60,11 @@ public ClientPlayerEntityMixin(ClientWorld world, GameProfile profile) { return; } + if (client.currentScreen instanceof AuctionViewScreen auctionViewScreen) { + this.client.setScreen(new EditBidPopup(auctionViewScreen, sign, front, auctionViewScreen.minBid)); + callbackInfo.cancel(); + } + // Search Overlay if (client.currentScreen != null) { if (SkyblockerConfigManager.get().general.searchOverlay.enableAuctionHouse && client.currentScreen.getTitle().getString().toLowerCase().contains("auction")) { diff --git a/src/main/java/de/hysky/skyblocker/mixin/HandledScreenProviderMixin.java b/src/main/java/de/hysky/skyblocker/mixin/HandledScreenProviderMixin.java index 975c9c51ba..bf330d8099 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/HandledScreenProviderMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixin/HandledScreenProviderMixin.java @@ -2,6 +2,9 @@ import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.auction.AuctionBrowserScreen; +import de.hysky.skyblocker.skyblock.auction.AuctionHouseScreenHandler; +import de.hysky.skyblocker.skyblock.auction.AuctionViewScreen; import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen; import de.hysky.skyblocker.skyblock.item.SkyblockCraftingTableScreenHandler; import de.hysky.skyblocker.skyblock.item.SkyblockCraftingTableScreen; @@ -26,7 +29,10 @@ public interface HandledScreenProviderMixin { if (player == null) return; if (!Utils.isOnSkyblock()) return; T screenHandler = type.create(id, player.getInventory()); - if (SkyblockerConfigManager.get().general.betterPartyFinder && screenHandler instanceof GenericContainerScreenHandler containerScreenHandler && PartyFinderScreen.possibleInventoryNames.contains(name.getString().toLowerCase())) { + if (!(screenHandler instanceof GenericContainerScreenHandler containerScreenHandler)) return; + String nameLowercase = name.getString().toLowerCase(); + // Better party finder + if (SkyblockerConfigManager.get().general.betterPartyFinder && PartyFinderScreen.possibleInventoryNames.contains(nameLowercase)) { if (client.currentScreen != null) { String lowerCase = client.currentScreen.getTitle().getString().toLowerCase(); if (lowerCase.contains("group builder")) return; @@ -45,7 +51,28 @@ public interface HandledScreenProviderMixin { } ci.cancel(); - } else if (SkyblockerConfigManager.get().general.fancyCraftingTable && screenHandler instanceof GenericContainerScreenHandler containerScreenHandler && name.getString().toLowerCase().contains("craft item")) { + // Fancy AH + } else if (SkyblockerConfigManager.get().general.fancyAuctionHouse.enabled && (nameLowercase.contains("auctions browser") || nameLowercase.contains("auctions: "))) { + AuctionHouseScreenHandler auctionHouseScreenHandler = AuctionHouseScreenHandler.of(containerScreenHandler, false); + client.player.currentScreenHandler = auctionHouseScreenHandler; + if (client.currentScreen instanceof AuctionBrowserScreen auctionBrowserScreen) { + auctionBrowserScreen.changeHandler(auctionHouseScreenHandler); + } else client.setScreen(new AuctionBrowserScreen(auctionHouseScreenHandler, client.player.getInventory())); + ci.cancel(); + } else if (SkyblockerConfigManager.get().general.fancyAuctionHouse.enabled && nameLowercase.contains("auction view")) { + AuctionHouseScreenHandler auctionHouseScreenHandler = AuctionHouseScreenHandler.of(containerScreenHandler, true); + client.player.currentScreenHandler = auctionHouseScreenHandler; + if (client.currentScreen instanceof AuctionViewScreen auctionViewScreen) { + auctionViewScreen.changeHandler(auctionHouseScreenHandler); + } else + client.setScreen(new AuctionViewScreen(auctionHouseScreenHandler, client.player.getInventory(), name)); + ci.cancel(); + } else if (SkyblockerConfigManager.get().general.fancyAuctionHouse.enabled && (nameLowercase.contains("confirm purchase") || nameLowercase.contains("confirm bid")) && client.currentScreen instanceof AuctionViewScreen auctionViewScreen) { + client.setScreen(auctionViewScreen.getConfirmPurchasePopup(name)); + client.player.currentScreenHandler = containerScreenHandler; + ci.cancel(); + // Fancy crafting table + } else if (SkyblockerConfigManager.get().general.fancyCraftingTable && name.getString().toLowerCase().contains("craft item")) { SkyblockCraftingTableScreenHandler skyblockCraftingTableScreenHandler = new SkyblockCraftingTableScreenHandler(containerScreenHandler, player.getInventory()); client.player.currentScreenHandler = skyblockCraftingTableScreenHandler; client.setScreen(new SkyblockCraftingTableScreen(skyblockCraftingTableScreenHandler, player.getInventory(), Text.literal("Craft Item"))); diff --git a/src/main/java/de/hysky/skyblocker/mixin/accessor/HandledScreenAccessor.java b/src/main/java/de/hysky/skyblocker/mixin/accessor/HandledScreenAccessor.java index d82422cb31..5b84072d18 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/accessor/HandledScreenAccessor.java +++ b/src/main/java/de/hysky/skyblocker/mixin/accessor/HandledScreenAccessor.java @@ -1,7 +1,9 @@ package de.hysky.skyblocker.mixin.accessor; import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.screen.ScreenHandler; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(HandledScreen.class) @@ -17,4 +19,8 @@ public interface HandledScreenAccessor { @Accessor int getBackgroundHeight(); + + @Mutable + @Accessor("handler") + void setHandler(ScreenHandler handler); } diff --git a/src/main/java/de/hysky/skyblocker/mixin/accessor/SlotAccessor.java b/src/main/java/de/hysky/skyblocker/mixin/accessor/SlotAccessor.java new file mode 100644 index 0000000000..ef11006c95 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/mixin/accessor/SlotAccessor.java @@ -0,0 +1,17 @@ +package de.hysky.skyblocker.mixin.accessor; + +import net.minecraft.screen.slot.Slot; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(Slot.class) +public interface SlotAccessor { + @Mutable + @Accessor("x") + void setX(int x); + + @Mutable + @Accessor("y") + void setY(int y); +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionBrowserScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionBrowserScreen.java new file mode 100644 index 0000000000..d47fef058b --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionBrowserScreen.java @@ -0,0 +1,388 @@ +package de.hysky.skyblocker.skyblock.auction; + +import com.google.gson.JsonElement; +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.auction.widgets.AuctionTypeWidget; +import de.hysky.skyblocker.skyblock.auction.widgets.CategoryTabWidget; +import de.hysky.skyblocker.skyblock.auction.widgets.RarityWidget; +import de.hysky.skyblocker.skyblock.auction.widgets.SortWidget; +import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; +import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType; +import de.hysky.skyblocker.utils.ItemUtils; +import de.hysky.skyblocker.utils.render.gui.AbstractCustomHypixelGUI; +import it.unimi.dsi.fastutil.ints.Int2BooleanOpenHashMap; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.screen.slot.Slot; +import net.minecraft.screen.slot.SlotActionType; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.util.Colors; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.MathHelper; +import org.lwjgl.glfw.GLFW; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +public class AuctionBrowserScreen extends AbstractCustomHypixelGUI { + private static final Logger LOGGER = LoggerFactory.getLogger(AuctionBrowserScreen.class); + private static final Identifier TEXTURE = new Identifier(SkyblockerMod.NAMESPACE, "textures/gui/auctions_gui/browser/background.png"); + private static final Identifier SCROLLER_TEXTURE = new Identifier("container/creative_inventory/scroller"); + + private static final Identifier up_arrow_tex = new Identifier(SkyblockerMod.NAMESPACE, "up_arrow_even"); // Put them in their own fields to avoid object allocation on each frame + private static final Identifier down_arrow_tex = new Identifier(SkyblockerMod.NAMESPACE, "down_arrow_even"); + public static final Supplier UP_ARROW = () -> MinecraftClient.getInstance().getGuiAtlasManager().getSprite(up_arrow_tex); + public static final Supplier DOWN_ARROW = () -> MinecraftClient.getInstance().getGuiAtlasManager().getSprite(down_arrow_tex); + + + // SLOTS + public static final int RESET_BUTTON_SLOT = 47; + public static final int SEARCH_BUTTON_SLOT = 48; + public static final int BACK_BUTTON_SLOT = 49; + public static final int SORT_BUTTON_SLOT = 50; + public static final int RARITY_BUTTON_SLOT = 51; + public static final int AUCTION_TYPE_BUTTON_SLOT = 52; + + public static final int PREV_PAGE_BUTTON = 46; + public static final int NEXT_PAGE_BUTTON = 53; + + private final Int2BooleanOpenHashMap isSlotHighlighted = new Int2BooleanOpenHashMap(24); + + + // WIDGETS + private SortWidget sortWidget; + private AuctionTypeWidget auctionTypeWidget; + private RarityWidget rarityWidget; + private ButtonWidget resetFiltersButton; + private final List categoryTabWidgets = new ArrayList<>(6); + private String search = ""; + + public AuctionBrowserScreen(AuctionHouseScreenHandler handler, PlayerInventory inventory) { + super(handler, inventory, Text.literal("Auctions Browser")); + this.backgroundHeight = 187; + this.playerInventoryTitleY = 92; + this.titleX = 999; + } + + @Override + protected void init() { + super.init(); + sortWidget = new SortWidget(x + 25, y + 81, this::clickSlot); + sortWidget.setSlotId(SORT_BUTTON_SLOT); + addDrawableChild(sortWidget); + auctionTypeWidget = new AuctionTypeWidget(x + 134, y + 77, this::clickSlot); + auctionTypeWidget.setSlotId(AUCTION_TYPE_BUTTON_SLOT); + addDrawableChild(auctionTypeWidget); + rarityWidget = new RarityWidget(x + 73, y + 80, this::clickSlot); + rarityWidget.setSlotId(RARITY_BUTTON_SLOT); + addDrawableChild(rarityWidget); + resetFiltersButton = new ScaledTextButtonWidget(x + 10, y + 77, 12, 12, Text.literal("↻"), this::onResetPressed); + addDrawableChild(resetFiltersButton); + resetFiltersButton.setTooltip(Tooltip.of(Text.literal("Reset Filters"))); + resetFiltersButton.setTooltipDelay(500); + + addDrawableChild(new ButtonWidget.Builder(Text.literal("<"), button -> this.clickSlot(BACK_BUTTON_SLOT)) + .position(x + 98, y + 4) + .size(12, 12) + .build()); + + if (categoryTabWidgets.isEmpty()) + for (int i = 0; i < 6; i++) { + CategoryTabWidget categoryTabWidget = new CategoryTabWidget(new ItemStack(Items.SPONGE), this::clickSlot); + categoryTabWidgets.add(categoryTabWidget); + addSelectableChild(categoryTabWidget); // This method only makes it clickable, does not add it to the drawables list + // manually rendered in the render method to have it not render behind the durability bars + categoryTabWidget.setPosition(x - 30, y + 3 + i * 28); + } + else + for (int i = 0; i < categoryTabWidgets.size(); i++) { + CategoryTabWidget categoryTabWidget = categoryTabWidgets.get(i); + categoryTabWidget.setPosition(x - 30, y + 3 + i * 28); + + } + } + + private void onResetPressed(ButtonWidget buttonWidget) { + buttonWidget.setFocused(false); // Annoying. + this.clickSlot(RESET_BUTTON_SLOT, 0); + } + + @Override + protected void drawBackground(DrawContext context, float delta, int mouseX, int mouseY) { + context.drawTexture(TEXTURE, this.x, this.y, 0, 0, this.backgroundWidth, this.backgroundHeight); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + super.render(context, mouseX, mouseY, delta); + for (CategoryTabWidget categoryTabWidget : categoryTabWidgets) { + categoryTabWidget.render(context, mouseX, mouseY, delta); + } + if (isWaitingForServer) { + String waiting = "Waiting for server..."; + context.drawText(textRenderer, waiting, this.width - textRenderer.getWidth(waiting) - 5, this.height - textRenderer.fontHeight - 2, Colors.WHITE, true); + } + + MatrixStack matrices = context.getMatrices(); + matrices.push(); + matrices.translate(x, y, 0); + // Search + context.enableScissor(x + 7, y + 4, x + 97, y + 16); + context.drawText(textRenderer, Text.literal(search).fillStyle(Style.EMPTY.withUnderline(onSearchField(mouseX, mouseY))), 9, 6, Colors.WHITE, true); + context.disableScissor(); + + // Scrollbar + if (prevPageVisible) { + if (onScrollbarTop(mouseX, mouseY)) + context.drawSprite(159, 13, 0, 6, 3, UP_ARROW.get()); + else context.drawSprite(159, 13, 0, 6, 3, UP_ARROW.get(), 0.54f, 0.54f, 0.54f, 1); + } + + if (nextPageVisible) { + if (onScrollbarBottom(mouseX, mouseY)) + context.drawSprite(159, 72, 0, 6, 3, DOWN_ARROW.get()); + else context.drawSprite(159, 72, 0, 6, 3, DOWN_ARROW.get(), 0.54f, 0.54f, 0.54f, 1); + } + context.drawText(textRenderer, String.format("%d/%d", currentPage, totalPages), 111, 6, Colors.GRAY, false); + if (totalPages <= 1) + context.drawGuiTexture(SCROLLER_TEXTURE, 156, 18, 12, 15); + else + context.drawGuiTexture(SCROLLER_TEXTURE, 156, (int) (18 + (float) (Math.min(currentPage, totalPages) - 1) / (totalPages - 1) * 37), 12, 15); + + matrices.pop(); + + this.drawMouseoverTooltip(context, mouseX, mouseY); + } + + @Override + protected void drawSlot(DrawContext context, Slot slot) { + if (SkyblockerConfigManager.get().general.fancyAuctionHouse.highlightCheapBIN && isSlotHighlighted.getOrDefault(slot.id, false)) { + context.drawBorder(slot.x, slot.y, 16, 16, new Color(0, 255, 0, 100).getRGB()); + } + super.drawSlot(context, slot); + } + + @Override + protected void onMouseClick(Slot slot, int slotId, int button, SlotActionType actionType) { + if (slotId >= handler.getRows() * 9) return; + super.onMouseClick(slot, slotId, button, actionType); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (isWaitingForServer) return super.mouseClicked(mouseX, mouseY, button); + if (onScrollbarTop((int) mouseX, (int) mouseY) && prevPageVisible) { + clickSlot(PREV_PAGE_BUTTON); + return true; + } + if (onScrollbarBottom((int) mouseX, (int) mouseY) && nextPageVisible) { + clickSlot(NEXT_PAGE_BUTTON); + return true; + } + + if (onSearchField((int) mouseX, (int) mouseY)) { + clickSlot(SEARCH_BUTTON_SLOT); + return true; + } + return super.mouseClicked(mouseX, mouseY, button); + } + + private boolean onScrollbarTop(int mouseX, int mouseY) { + int localX = mouseX - x; + int localY = mouseY - y; + return localX > 154 && localX < 169 && localY > 6 && localY < 44; + } + + private boolean onScrollbarBottom(int mouseX, int mouseY) { + int localX = mouseX - x; + int localY = mouseY - y; + return localX > 154 && localX < 169 && localY > 43 && localY < 80; + } + + private boolean onSearchField(int mouseX, int mouseY) { + int localX = mouseX - x; + int localY = mouseY - y; + return localX > 6 && localX < 97 && localY > 3 && localY < 16; + } + + @Override + public void onSlotChange(AuctionHouseScreenHandler handler, int slotId, ItemStack stack) { + if (client == null || stack.isEmpty()) return; + isWaitingForServer = false; + + switch (slotId) { + case PREV_PAGE_BUTTON -> { + prevPageVisible = false; + if (stack.isOf(Items.ARROW)) { + prevPageVisible = true; + parsePage(stack); + } + } + case NEXT_PAGE_BUTTON -> { + nextPageVisible = false; + if (stack.isOf(Items.ARROW)) { + nextPageVisible = true; + parsePage(stack); + } + } + case SORT_BUTTON_SLOT -> + sortWidget.setCurrent(SortWidget.Option.get(getOrdinal(ItemUtils.getNbtTooltips(stack)))); + case AUCTION_TYPE_BUTTON_SLOT -> + auctionTypeWidget.setCurrent(AuctionTypeWidget.Option.get(getOrdinal(ItemUtils.getNbtTooltips(stack)))); + case RARITY_BUTTON_SLOT -> { + List tooltip = ItemUtils.getNbtTooltips(stack); + int ordinal = getOrdinal(tooltip); + String split = tooltip.get(ordinal + 1).getString().substring(2); + rarityWidget.setText(tooltip.subList(1, tooltip.size() - 3), split); + } + case RESET_BUTTON_SLOT -> { + if (resetFiltersButton != null) + resetFiltersButton.active = handler.getSlot(slotId).getStack().isOf(Items.ANVIL); + } + case SEARCH_BUTTON_SLOT -> { + List tooltipSearch = ItemUtils.getNbtTooltips(stack); + for (Text text : tooltipSearch) { + String string = text.getString(); + if (string.contains("Filtered:")) { + String[] splitSearch = string.split(":"); + if (splitSearch.length < 2) { + search = ""; + } else search = splitSearch[1].trim(); + break; + } + } + } + default -> { + if (slotId < this.handler.getRows() * 9 && slotId % 9 == 0) { + CategoryTabWidget categoryTabWidget = categoryTabWidgets.get(slotId / 9); + categoryTabWidget.setSlotId(slotId); + categoryTabWidget.setIcon(handler.getSlot(slotId).getStack()); + List tooltipDefault = ItemUtils.getNbtTooltips(handler.getSlot(slotId).getStack()); + for (int j = tooltipDefault.size() - 1; j >= 0; j--) { + String lowerCase = tooltipDefault.get(j).getString().toLowerCase(); + if (lowerCase.contains("currently")) { + categoryTabWidget.setToggled(true); + break; + } else if (lowerCase.contains("click")) { + categoryTabWidget.setToggled(false); + break; + } else categoryTabWidget.setToggled(false); + } + } else if (slotId > 9 && slotId < (handler.getRows() - 1) * 9 && slotId % 9 > 1 && slotId % 9 < 8) { + if (!SkyblockerConfigManager.get().general.fancyAuctionHouse.highlightCheapBIN) return; + List tooltip = ItemUtils.getNbtTooltips(stack); + for (int k = tooltip.size() - 1; k >= 0; k--) { + Text text = tooltip.get(k); + String string = text.getString(); + if (string.toLowerCase().contains("buy it now:")) { + String[] split = string.split(":"); + if (split.length < 2) continue; + String coins = split[1].replace(",", "").replace("coins", "").trim(); + try { + long parsed = Long.parseLong(coins); + String name = ItemTooltip.getInternalNameFromNBT(stack, false); + String internalID = ItemTooltip.getInternalNameFromNBT(stack, true); + String neuName = name; + if (name == null || internalID == null) break; + if (name.startsWith("ISSHINY_")) { + neuName = internalID; + } + JsonElement jsonElement = TooltipInfoType.THREE_DAY_AVERAGE.getData().get(ItemTooltip.getNeuName(internalID, neuName)); + if (jsonElement == null) break; + else { + isSlotHighlighted.put(slotId, jsonElement.getAsDouble() > parsed); + } + } catch (Exception e) { + LOGGER.error("[Skyblocker Fancy Auction House] Failed to parse BIN price", e); + } + } + } + } + } + } + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (keyCode == GLFW.GLFW_KEY_UP && prevPageVisible) { + clickSlot(PREV_PAGE_BUTTON); + return true; + } + if (keyCode == GLFW.GLFW_KEY_DOWN && nextPageVisible) { + clickSlot(NEXT_PAGE_BUTTON); + return true; + } + return super.keyPressed(keyCode, scanCode, modifiers); + } + + private static int getOrdinal(List tooltip) { + int ordinal = 0; + for (int j = 0; j < tooltip.size() - 4; j++) { + if (j + 1 >= tooltip.size()) break; + if (tooltip.get(j + 1).getString().contains("▶")) { + ordinal = j; + break; + } + } + return ordinal; + } + + int currentPage = 0; + int totalPages = 1; + private boolean prevPageVisible = false; + private boolean nextPageVisible = false; + + private void parsePage(ItemStack stack) { + assert client != null; + try { + List tooltip = ItemUtils.getNbtTooltips(stack); + String str = tooltip.get(0).getString().trim(); + str = str.substring(1, str.length() - 1); // remove parentheses + String[] parts = str.split("/"); // split the string + currentPage = Integer.parseInt(parts[0].replace(",", "")); // parse current page + totalPages = Integer.parseInt(parts[1].replace(",", "")); // parse total + } catch (Exception e) { + LOGGER.error("[Skyblocker Fancy Auction House] Failed to parse page arrow", e); + } + } + + @Override + protected boolean isClickOutsideBounds(double mouseX, double mouseY, int left, int top, int button) { + return mouseX < (double) left - 32 || mouseY < (double) top || mouseX >= (double) (left + this.backgroundWidth) || mouseY >= (double) (top + this.backgroundHeight); + } + + private static class ScaledTextButtonWidget extends ButtonWidget { + + protected ScaledTextButtonWidget(int x, int y, int width, int height, Text message, PressAction onPress) { + super(x, y, width, height, message, onPress, Supplier::get); + } + + // Code taken mostly from YACL by isxander. Love you <3 + @Override + public void drawMessage(DrawContext graphics, TextRenderer textRenderer, int color) { + TextRenderer font = MinecraftClient.getInstance().textRenderer; + MatrixStack pose = graphics.getMatrices(); + float textScale = 2.f; + + pose.push(); + pose.translate(((this.getX() + this.width / 2f) - font.getWidth(getMessage()) * textScale / 2) + 1, (float) this.getY() + (this.height - font.fontHeight * textScale) / 2f - 1, 0); + pose.scale(textScale, textScale, 1); + graphics.drawText(font, getMessage(), 0, 0, color | MathHelper.ceil(this.alpha * 255.0F) << 24, true); + pose.pop(); + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionHouseScreenHandler.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionHouseScreenHandler.java new file mode 100644 index 0000000000..28898cdc76 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionHouseScreenHandler.java @@ -0,0 +1,58 @@ +package de.hysky.skyblocker.skyblock.auction; + +import de.hysky.skyblocker.mixin.accessor.SlotAccessor; +import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.GenericContainerScreenHandler; +import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.screen.slot.Slot; + +public class AuctionHouseScreenHandler extends GenericContainerScreenHandler { + public AuctionHouseScreenHandler(ScreenHandlerType type, int syncId, PlayerInventory playerInventory, Inventory inventory, int rows, boolean isView) { + super(type, syncId, playerInventory, inventory, rows); + + int yOffset = (rows - 4) * 18; + // Shift player inventory by 2 pixels and also remove the yOffset + for (int i = rows * 9; i < slots.size(); i++) { + Slot slot = slots.get(i); + SlotAccessor slotAccessor = (SlotAccessor) slot; + slotAccessor.setY(slot.y + 2 - yOffset); + } + // disable ALL THE OTHER SLOTS MWAHAHAHA and also move the good ones around and stuff + for (int i = 0; i < rows * 9; i++) { + int lineI = i % 9; + Slot slot = slots.get(i); + if (!isView && i > 9 && i < (rows - 1) * 9 && lineI > 1 && lineI < 8) { + int miniInventorySlot = lineI - 2 + (i / 9 - 1) * 6; + SlotAccessor slotAccessor = (SlotAccessor) slot; + slotAccessor.setX(8 + miniInventorySlot % 8 * 18); + slotAccessor.setY(18 + miniInventorySlot / 8 * 18); + } else { + slots.set(i, new Slot(slot.inventory, slot.getIndex(), slot.x, slot.y) { + @Override + public boolean isEnabled() { + return false; + } + }); + } + } + } + + public static AuctionHouseScreenHandler of(GenericContainerScreenHandler original, boolean isView) { + assert MinecraftClient.getInstance().player != null; + return new AuctionHouseScreenHandler(original.getType(), + original.syncId, + MinecraftClient.getInstance().player.getInventory(), + original.getInventory(), + original.getRows(), + isView); + } + + @Override + public void setStackInSlot(int slot, int revision, ItemStack stack) { + super.setStackInSlot(slot, revision, stack); + onContentChanged(slots.get(slot).inventory); + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionViewScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionViewScreen.java new file mode 100644 index 0000000000..a8b30a50c1 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionViewScreen.java @@ -0,0 +1,296 @@ +package de.hysky.skyblocker.skyblock.auction; + +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.utils.ItemUtils; +import de.hysky.skyblocker.utils.render.gui.AbstractCustomHypixelGUI; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.PopupScreen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.DirectionalLayoutWidget; +import net.minecraft.client.gui.widget.SimplePositioningWidget; +import net.minecraft.client.gui.widget.TextWidget; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.screen.slot.SlotActionType; +import net.minecraft.text.MutableText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.text.TextColor; +import net.minecraft.util.Colors; +import net.minecraft.util.Formatting; +import net.minecraft.util.Identifier; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; + +public class AuctionViewScreen extends AbstractCustomHypixelGUI { + protected static final Identifier BACKGROUND_TEXTURE = new Identifier(SkyblockerMod.NAMESPACE, "textures/gui/auctions_gui/browser/background_view.png"); + + public static final int BACK_BUTTON_SLOT = 49; + + DirectionalLayoutWidget verticalLayout = DirectionalLayoutWidget.vertical(); + + public final boolean isBinAuction; + private TextWidget priceWidget; + private final Text clickToEditBidText = Text.translatable("skyblocker.fancyAuctionHouse.editBid").setStyle(Style.EMPTY.withUnderline(true)); + + private TextWidget infoTextWidget; + public String minBid = ""; + + private BuyState buyState = null; + private MutableText priceText = Text.literal("?"); + private ButtonWidget buyButton; + private TextWidget priceTextWidget; + + public AuctionViewScreen(AuctionHouseScreenHandler handler, PlayerInventory inventory, Text title) { + super(handler, inventory, title); + backgroundHeight = 187; + isBinAuction = this.getTitle().getString().toLowerCase().contains("bin"); + playerInventoryTitleY = 93; + titleX = 5; + titleY = 4; + } + + @Override + protected void init() { + super.init(); + verticalLayout.spacing(2).getMainPositioner().alignHorizontalCenter(); + priceTextWidget = new TextWidget(isBinAuction ? Text.translatable("skyblocker.fancyAuctionHouse.price") : Text.translatable("skyblocker.fancyAuctionHouse.newBid"), textRenderer).alignCenter(); + verticalLayout.add(priceTextWidget); + + priceWidget = new TextWidget(Text.literal("?"), textRenderer).alignCenter(); + priceWidget.setWidth(textRenderer.getWidth(clickToEditBidText)); + priceWidget.active = true; + verticalLayout.add(priceWidget); + + infoTextWidget = new TextWidget(Text.literal("Can't Afford"), textRenderer).alignCenter(); + verticalLayout.add(infoTextWidget); + + buyButton = ButtonWidget.builder(isBinAuction ? Text.translatable("skyblocker.fancyAuctionHouse.buy") : Text.translatable("skyblocker.fancyAuctionHouse.bid"), button -> { + if (buySlotID == -1) return; + clickSlot(buySlotID); + }).size(60, 15).build(); + verticalLayout.add(buyButton); + verticalLayout.forEachChild(this::addDrawableChild); + updateLayout(); + + addDrawableChild(new ButtonWidget.Builder(Text.literal("<"), button -> this.clickSlot(BACK_BUTTON_SLOT)) + .position(x + backgroundWidth - 16, y + 4) + .size(12, 12) + .build()); + + + } + + private void changeState(BuyState newState) { + if (newState == buyState) return; + buyState = newState; + switch (buyState) { + case CANT_AFFORD -> { + infoTextWidget.setMessage(Text.translatable("skyblocker.fancyAuctionHouse.cantAfford").withColor(Colors.RED)); + buyButton.active = false; + } + case TOP_BID -> + infoTextWidget.setMessage(Text.translatable("skyblocker.fancyAuctionHouse.alreadyTopBid").withColor(Colors.LIGHT_YELLOW)); + case AFFORD -> infoTextWidget.setMessage(Text.empty()); + case COLLECT_AUCTION -> { + infoTextWidget.setMessage(changeProfile ? Text.translatable("skyblocker.fancyAuctionHouse.differentProfile") : wonAuction ? Text.empty() : Text.translatable("skyblocker.fancyAuctionHouse.didntWin")); + //priceWidget.setMessage(Text.empty()); + priceWidget.active = false; + + if (changeProfile) { + buyButton.setMessage(Text.translatable("skyblocker.fancyAuctionHouse.changeProfile").setStyle(Style.EMPTY.withColor(Formatting.AQUA))); + } else if (wonAuction) { + buyButton.setMessage(Text.translatable("skyblocker.fancyAuctionHouse.collectAuction")); + } else { + buyButton.setMessage(Text.translatable("skyblocker.fancyAuctionHouse.collectBid")); + } + buyButton.setWidth(textRenderer.getWidth(buyButton.getMessage()) + 4); + + priceTextWidget.setMessage(Text.translatable("skyblocker.fancyAuctionHouse.auctionEnded")); + priceTextWidget.setWidth(textRenderer.getWidth(priceTextWidget.getMessage())); + } + case CANCELLABLE_AUCTION -> { + buyButton.setMessage(Text.translatable("skyblocker.fancyAuctionHouse.cancelAuction").setStyle(Style.EMPTY.withColor(Formatting.RED))); + buyButton.setWidth(textRenderer.getWidth(buyButton.getMessage()) + 4); + + buyButton.active = true; + buyButton.visible = true; + } + case OWN_AUCTION -> { + buyButton.visible = false; + priceWidget.active = false; + + infoTextWidget.setMessage(Text.translatable("skyblocker.fancyAuctionHouse.yourAuction")); + } + } + infoTextWidget.setWidth(textRenderer.getWidth(infoTextWidget.getMessage())); + updateLayout(); + } + + private void updateLayout() { + verticalLayout.refreshPositions(); + SimplePositioningWidget.setPos(verticalLayout, x, y + 36, backgroundWidth, 60); + } + + @Override + protected void drawBackground(DrawContext context, float delta, int mouseX, int mouseY) { + context.drawTexture(BACKGROUND_TEXTURE, this.x, this.y, 0, 0, this.backgroundWidth, this.backgroundHeight); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + super.render(context, mouseX, mouseY, delta); + + if (isWaitingForServer) context.drawText(textRenderer, "Waiting...", 0, 0, Colors.WHITE, true); + + MatrixStack matrices = context.getMatrices(); + + matrices.push(); + matrices.translate(x + 77, y + 14, 0); + matrices.scale(1.375f, 1.375f, 1.375f); + //matrices.translate(0, 0, 100f); + ItemStack stack = handler.getSlot(13).getStack(); + context.drawItem(stack, 0, 0); + context.drawItemInSlot(textRenderer, stack, 0, 0); + matrices.pop(); + + if (!isBinAuction && buyState != BuyState.COLLECT_AUCTION) { + if (priceWidget.isMouseOver(mouseX, mouseY) && buyState != BuyState.CANT_AFFORD) { + priceWidget.setMessage(clickToEditBidText); + } else { + priceWidget.setMessage(priceText); + } + } + + drawMouseoverTooltip(context, mouseX, mouseY); + } + + @Override + protected void drawMouseoverTooltip(DrawContext context, int x, int y) { + super.drawMouseoverTooltip(context, x, y); + if (x > this.x + 75 && x < this.x + 75 + 26 && y > this.y + 13 && y < this.y + 13 + 26) { + context.drawTooltip(this.textRenderer, this.getTooltipFromItem(handler.getSlot(13).getStack()), x, y); + } + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (!isBinAuction && priceWidget.isMouseOver(mouseX, mouseY)) { + clickSlot(31); + return true; + } + return super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public void onSlotChange(AuctionHouseScreenHandler handler, int slotId, ItemStack stack) { + if (stack.isOf(Items.BLACK_STAINED_GLASS_PANE) || slotId == 13) return; + assert client != null; + if (stack.isOf(Items.RED_TERRACOTTA)) { // Red terracotta shows up when you can cancel it + changeState(BuyState.CANCELLABLE_AUCTION); + buySlotID = slotId; + } + if (priceParsed) return; + if (stack.isOf(Items.POISONOUS_POTATO)) { + changeState(BuyState.CANT_AFFORD); + getPriceFromTooltip(ItemUtils.getNbtTooltips(stack)); + buySlotID = slotId; + } else if (stack.isOf(Items.GOLD_NUGGET)) { + changeState(BuyState.AFFORD); + getPriceFromTooltip(ItemUtils.getNbtTooltips(stack)); + buySlotID = slotId; + } else if (stack.isOf(Items.GOLD_BLOCK)) { + changeState(BuyState.TOP_BID); + getPriceFromTooltip(ItemUtils.getNbtTooltips(stack)); + buySlotID = slotId; + } else if (stack.isOf(Items.NAME_TAG)) { + getPriceFromTooltip(ItemUtils.getNbtTooltips(stack)); + changeProfile = true; + buySlotID = slotId; + } + String lowerCase = stack.getName().getString().toLowerCase(); + if (priceParsed && lowerCase.contains("collect auction")) { + changeState(BuyState.COLLECT_AUCTION); + } + } + + private int buySlotID = -1; + private boolean priceParsed = false; + private boolean wonAuction = true; + private boolean changeProfile = false; + + private void getPriceFromTooltip(List tooltip) { + if (priceParsed) return; + String minBid = null; + String priceString = null; + AtomicReference stringAtomicReference = new AtomicReference<>(""); + + for (Text text : tooltip) { + String string = text.getString(); + String thingToLookFor = (isBinAuction) ? "price:" : "new bid:"; + String lowerCase = string.toLowerCase(); + if (lowerCase.contains(thingToLookFor)) { + String[] split = string.split(":"); + if (split.length < 2) continue; + priceString = split[1].trim(); + } else if (lowerCase.contains("minimum bid:") && !isBinAuction) { + String[] split = string.split(":"); + if (split.length < 2) continue; + minBid = split[1].replace("coins", "").replace(",", "").trim(); + } else if (lowerCase.contains("you pay:")) { + String[] split = string.split(":"); + if (split.length < 2) continue; + if (buyState != BuyState.CANT_AFFORD && !isBinAuction) { + infoTextWidget.setMessage(Text.translatable("skyblocker.fancyAuctionHouse.youPay", split[1].trim())); + infoTextWidget.setWidth(textRenderer.getWidth(infoTextWidget.getMessage())); + } + + } else if (lowerCase.contains("top bid:")) { // Shows up when an auction ended and you lost + wonAuction = false; + } else if (lowerCase.contains("correct profile")) { // When an auction ended but on a different profile + changeProfile = true; + priceWidget.setMessage(Text.empty()); + } else if (lowerCase.contains("own auction")) { // it's yours + changeState(BuyState.OWN_AUCTION); + } + text.visit((style, asString) -> { + // The regex removes [, ] and +. To ignore mvp++ rank and orange + in mvp+ + String res = Objects.equals(style.getColor(), TextColor.fromFormatting(Formatting.GOLD)) && !asString.matches(".*[]\\[+].*") && !asString.contains("Collect") ? asString : null; + return Optional.ofNullable(res); + }, Style.EMPTY).ifPresent(s -> stringAtomicReference.set(stringAtomicReference.get() + s)); + } + + if (priceString == null) priceString = stringAtomicReference.get(); + if (minBid != null) this.minBid = minBid; + else this.minBid = priceString; + priceText = Text.literal(priceString).setStyle(Style.EMPTY.withFormatting(Formatting.BOLD).withColor(Formatting.GOLD)); + priceWidget.setMessage(priceText); + int width = textRenderer.getWidth(priceText); + if (width > priceWidget.getWidth()) priceWidget.setWidth(width); + priceParsed = true; + updateLayout(); + } + + public PopupScreen getConfirmPurchasePopup(Text title) { + // This really shouldn't be possible to be null in its ACTUAL use case. + //noinspection DataFlowIssue + return new PopupScreen.Builder(this, title) + .button(Text.translatable("text.skyblocker.confirm"), popupScreen -> this.client.interactionManager.clickSlot(this.client.player.currentScreenHandler.syncId, 11, 0, SlotActionType.PICKUP, client.player)) + .button(Text.translatable("gui.cancel"), popupScreen -> this.client.interactionManager.clickSlot(this.client.player.currentScreenHandler.syncId, 15, 0, SlotActionType.PICKUP, client.player)) + .message((isBinAuction ? Text.translatable("skyblocker.fancyAuctionHouse.price") : Text.translatable("skyblocker.fancyAuctionHouse.newBid")).append(" ").append(priceText)).build(); + } + + private enum BuyState { + CANT_AFFORD, + AFFORD, + TOP_BID, + COLLECT_AUCTION, + CANCELLABLE_AUCTION, + OWN_AUCTION + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/EditBidPopup.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/EditBidPopup.java new file mode 100644 index 0000000000..6b90b86ce0 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/EditBidPopup.java @@ -0,0 +1,111 @@ +package de.hysky.skyblocker.skyblock.auction; + +import de.hysky.skyblocker.utils.render.gui.AbstractPopupScreen; +import net.minecraft.block.entity.SignBlockEntity; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.widget.*; +import net.minecraft.network.packet.c2s.play.UpdateSignC2SPacket; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import org.jetbrains.annotations.NotNull; +import org.lwjgl.glfw.GLFW; + +public class EditBidPopup extends AbstractPopupScreen { + private DirectionalLayoutWidget layout = DirectionalLayoutWidget.vertical(); + private final String minimumBid; + private final SignBlockEntity signBlockEntity; + + private final boolean signFront; + + private TextFieldWidget textFieldWidget; + + private boolean packetSent = false; + + public EditBidPopup(AuctionViewScreen auctionViewScreen, @NotNull SignBlockEntity signBlockEntity, boolean signFront, String minimumBid) { + super(Text.literal("Edit Bid"), auctionViewScreen); + this.minimumBid = minimumBid; + this.signBlockEntity = signBlockEntity; + this.signFront = signFront; + } + + @Override + protected void init() { + super.init(); + layout = DirectionalLayoutWidget.vertical(); + layout.spacing(8).getMainPositioner().alignHorizontalCenter(); + textFieldWidget = new TextFieldWidget(textRenderer, 120, 15, Text.empty()) { + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (!super.keyPressed(keyCode, scanCode, modifiers)) { + if (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_KP_ENTER) { + done(null); + return true; + } + } else return true; + return false; + } + }; + textFieldWidget.setTextPredicate(this::isStringGood); + layout.add(new TextWidget(Text.literal("- Set Bid -").fillStyle(Style.EMPTY.withBold(true)), textRenderer)); + layout.add(textFieldWidget); + layout.add(new TextWidget(Text.literal("Minimum Bid: " + minimumBid), textRenderer)); + DirectionalLayoutWidget horizontal = DirectionalLayoutWidget.horizontal(); + ButtonWidget buttonWidget = ButtonWidget.builder(Text.literal("Set Minimum Bid"), this::buttonMinimumBid).width(80).build(); + buttonWidget.active = isStringGood(minimumBid); + horizontal.add(buttonWidget); + horizontal.add(ButtonWidget.builder(Text.literal("Done"), this::done).width(80).build()); + layout.add(horizontal); + layout.forEachChild(this::addDrawableChild); + this.layout.refreshPositions(); + SimplePositioningWidget.setPos(layout, this.getNavigationFocus()); + setInitialFocus(textFieldWidget); + } + + @Override + public void renderBackground(DrawContext context, int mouseX, int mouseY, float delta) { + super.renderBackground(context, mouseX, mouseY, delta); + drawPopupBackground(context, layout.getX(), layout.getY(), layout.getWidth(), layout.getHeight()); + } + + private boolean isStringGood(String s) { + assert this.client != null; + return this.client.textRenderer.getWidth(minimumBid) <= this.signBlockEntity.getMaxTextWidth(); + } + + private void buttonMinimumBid(ButtonWidget widget) { + if (!isStringGood(minimumBid)) return; + sendPacket(minimumBid); + this.close(); + } + + private void done(ButtonWidget widget) { + if (!isStringGood(textFieldWidget.getText().trim())) return; + sendPacket(textFieldWidget.getText().trim()); + this.close(); + } + + private void sendPacket(String string) { + assert MinecraftClient.getInstance().player != null; + MinecraftClient.getInstance().player.networkHandler.sendPacket(new UpdateSignC2SPacket(signBlockEntity.getPos(), signFront, + string.replace("coins", ""), + "", + "", + "" + )); + packetSent = true; + } + + @Override + public void close() { + if (!packetSent) sendPacket(""); + assert this.client != null; + this.client.setScreen(null); + } + + @Override + public void removed() { + if (!packetSent) sendPacket(""); + super.removed(); + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/SlotClickHandler.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/SlotClickHandler.java new file mode 100644 index 0000000000..b64a4583e3 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/SlotClickHandler.java @@ -0,0 +1,11 @@ +package de.hysky.skyblocker.skyblock.auction; + +@FunctionalInterface +public interface SlotClickHandler { + + void click(int slot, int button); + + default void click(int slot) { + click(slot, 0); + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/AuctionTypeWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/AuctionTypeWidget.java new file mode 100644 index 0000000000..0caa233a36 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/AuctionTypeWidget.java @@ -0,0 +1,70 @@ +package de.hysky.skyblocker.skyblock.auction.widgets; + +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.skyblock.auction.SlotClickHandler; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.MathHelper; + +public class AuctionTypeWidget extends SliderWidget { + + /** + * @param x x position + * @param y y position + * @param slotClick IDK figure it out + */ + public AuctionTypeWidget(int x, int y, SlotClickHandler slotClick) { + super(x, y, 17, 17, Text.literal("Auction Type Widget"), slotClick, Option.ALL); + } + + public enum Option implements OptionInfo { + ALL("all.png"), + BIN("bin.png"), + AUC("auctions.png"); + + private final Identifier texture; + private static final String prefix = "textures/gui/auctions_gui/auction_type_widget/"; + private static final Identifier HOVER_TEXTURE = new Identifier(SkyblockerMod.NAMESPACE, prefix + "hover.png"); + private static final Identifier BACK_TEXTURE = new Identifier(SkyblockerMod.NAMESPACE, prefix + "back.png"); + + Option(String textureName) { + texture = new Identifier(SkyblockerMod.NAMESPACE, prefix + textureName); + } + + private static final AuctionTypeWidget.Option[] values = values(); + + public static AuctionTypeWidget.Option get(int ordinal) { + return values[MathHelper.clamp(ordinal, 0, values.length - 1)]; + } + + @Override + public boolean isVertical() { + return true; + } + + @Override + public int getOffset() { + return 4 * ordinal(); + } + + @Override + public int[] getOptionSize() { + return new int[]{17, 9}; + } + + @Override + public Identifier getOptionTexture() { + return texture; + } + + @Override + public Identifier getBackTexture() { + return BACK_TEXTURE; + } + + @Override + public Identifier getHoverTexture() { + return HOVER_TEXTURE; + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/CategoryTabWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/CategoryTabWidget.java new file mode 100644 index 0000000000..03d91780b5 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/CategoryTabWidget.java @@ -0,0 +1,58 @@ +package de.hysky.skyblocker.skyblock.auction.widgets; + +import de.hysky.skyblocker.skyblock.auction.SlotClickHandler; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.ButtonTextures; +import net.minecraft.client.gui.widget.ToggleButtonWidget; +import net.minecraft.client.item.TooltipContext; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.NotNull; + +public class CategoryTabWidget extends ToggleButtonWidget { + private static final ButtonTextures TEXTURES = new ButtonTextures(new Identifier("recipe_book/tab"), new Identifier("recipe_book/tab_selected")); + + public void setIcon(@NotNull ItemStack icon) { + this.icon = icon.copy(); + } + + private @NotNull ItemStack icon; + private final SlotClickHandler slotClick; + private int slotId = -1; + + public CategoryTabWidget(@NotNull ItemStack icon, SlotClickHandler slotClick) { + super(0, 0, 35, 27, false); + this.icon = icon.copy(); // copy prevents item disappearing on click + this.slotClick = slotClick; + setTextures(TEXTURES); + } + + @Override + public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) { + if (textures == null) return; + Identifier identifier = textures.get(true, this.toggled); + int x = getX(); + if (toggled) x -= 2; + context.drawGuiTexture(identifier, x, this.getY(), this.width, this.height); + context.drawItem(icon, x + 9, getY() + 5); + + if (isMouseOver(mouseX, mouseY)) { + context.getMatrices().push(); + context.drawTooltip(MinecraftClient.getInstance().textRenderer, icon.getTooltip(MinecraftClient.getInstance().player, TooltipContext.BASIC), mouseX, mouseY); + context.getMatrices().pop(); + } + + } + + public void setSlotId(int slotId) { + this.slotId = slotId; + } + + @Override + public void onClick(double mouseX, double mouseY) { + if (this.toggled || slotId == -1) return; + slotClick.click(slotId); + this.setToggled(true); + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/RarityWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/RarityWidget.java new file mode 100644 index 0000000000..b6bd42a9b0 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/RarityWidget.java @@ -0,0 +1,105 @@ +package de.hysky.skyblocker.skyblock.auction.widgets; + +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.skyblock.auction.SlotClickHandler; +import de.hysky.skyblocker.skyblock.item.ItemRarityBackgrounds; +import de.hysky.skyblocker.skyblock.item.SkyblockItemRarity; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; +import net.minecraft.client.gui.widget.ClickableWidget; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.Identifier; + +import java.util.List; +import java.util.Map; + +public class RarityWidget extends ClickableWidget { + + private static final Identifier HOVER_TEXTURE = new Identifier(SkyblockerMod.NAMESPACE, "textures/gui/auctions_gui/rarity_widget/hover.png"); + private static final Identifier TEXTURE = new Identifier(SkyblockerMod.NAMESPACE, "textures/gui/auctions_gui/rarity_widget/background.png"); + private final SlotClickHandler onClick; + private int slotId = -1; + + public RarityWidget(int x, int y, SlotClickHandler onClick) { + super(x, y, 48, 11, Text.literal("rarity selector thing, hi mom")); + this.onClick = onClick; + } + + @Override + protected void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) { + MatrixStack matrices = context.getMatrices(); + matrices.push(); + matrices.translate(getX(), getY(), 0); + boolean onLeftArrow = isOnLeftArrow(mouseX); + boolean onRightArrow = isOnRightArrow(mouseX); + context.drawTexture(TEXTURE, 0, 0, 0, 0, 48, 11, 48, 11); + if (onLeftArrow) context.drawTexture(HOVER_TEXTURE, 0, 0, 0, 0, 6, 11, 6, 11); + if (onRightArrow) context.drawTexture(HOVER_TEXTURE, 42, 0, 0, 0, 6, 11, 6, 11); + + // Text + TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer; + int textWidth = textRenderer.getWidth(current); + if (textWidth > 34) { + float scale = 34f / textWidth; + matrices.push(); + matrices.translate(0, 5.5, 0); + matrices.scale(scale, scale, 1); + context.drawCenteredTextWithShadow(textRenderer, current, (int) (24 / scale), -textRenderer.fontHeight / 2, color); + matrices.pop(); + } else { + context.drawCenteredTextWithShadow(textRenderer, current, 24, 2, color); + } + + matrices.pop(); + if (!onLeftArrow && !onRightArrow && isHovered()) context.drawTooltip(textRenderer, tooltip, mouseX, mouseY); + + } + + private boolean isOnRightArrow(double mouseX) { + return isHovered() && mouseX - getX() > 40; + } + + private boolean isOnLeftArrow(double mouseX) { + return isHovered() && mouseX - getX() < 7; + } + + @Override + protected void appendClickableNarrations(NarrationMessageBuilder builder) { + + } + + public void setSlotId(int slotId) { + this.slotId = slotId; + } + + private List tooltip = List.of(); + private String current = "?"; + private int color = 0xFFEAEAEA; + + public void setText(List tooltip, String current) { + this.tooltip = tooltip; + this.current = current; + for (Map.Entry rarity : ItemRarityBackgrounds.LORE_RARITIES.entrySet()) { + if (current.toUpperCase().contains(rarity.getKey())) { + this.color = rarity.getValue().color | 0xFF000000; + return; + } + } + //noinspection DataFlowIssue + this.color = Formatting.GRAY.getColorValue() | 0xFF000000; + } + + @Override + public void onClick(double mouseX, double mouseY) { + if (slotId == -1) return; + if (isOnLeftArrow(mouseX)) { + onClick.click(slotId, 1); + } else if (isOnRightArrow(mouseX)) { + onClick.click(slotId, 0); + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/SliderWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/SliderWidget.java new file mode 100644 index 0000000000..22fa1ad8fb --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/SliderWidget.java @@ -0,0 +1,107 @@ +package de.hysky.skyblocker.skyblock.auction.widgets; + +import de.hysky.skyblocker.skyblock.auction.SlotClickHandler; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; +import net.minecraft.client.gui.widget.ClickableWidget; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +// This is kinda excessive, but I thought it was a good idea +public class SliderWidget & SliderWidget.OptionInfo> extends ClickableWidget { + private final SlotClickHandler clickSlot; + private int button = 0; + private int slotId = -1; + + protected E current; + + float posProgress; + + /** + * @param x x position + * @param y y position + * @param width width + * @param height height + * @param message probably useless, just put the widget name + * @param clickSlot the parent AuctionsBrowser + * @param defaultOption the default option should be the one at ordinal 0 + */ + public SliderWidget(int x, int y, int width, int height, Text message, SlotClickHandler clickSlot, E defaultOption) { + super(x, y, width, height, message); + this.clickSlot = clickSlot; + this.current = defaultOption; + posProgress = current.getOffset(); + } + + @Override + protected void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) { + if (posProgress < current.getOffset()) { + posProgress += delta * 5; + if (posProgress > current.getOffset()) posProgress = current.getOffset(); + } else if (posProgress > current.getOffset()) { + posProgress -= delta * 5; + if (posProgress < current.getOffset()) posProgress = current.getOffset(); + } + + + context.getMatrices().push(); + context.getMatrices().translate(getX(), getY(), 0); + + int x = current.isVertical() ? 0 : Math.round(posProgress); + int y = current.isVertical() ? Math.round(posProgress) : 0; + + int optionWidth = current.getOptionSize()[0]; + int optionHeight = current.getOptionSize()[1]; + + context.drawTexture(current.getBackTexture(), 0, 0, 0, 0, getWidth(), getHeight(), getWidth(), getHeight()); + context.drawTexture(current.getOptionTexture(), x, y, 0, 0, optionWidth, optionHeight, optionWidth, optionHeight); + if (isHovered()) { + context.drawTexture(current.getHoverTexture(), x, y, 0, 0, optionWidth, optionHeight, optionWidth, optionHeight); + + } + context.getMatrices().pop(); + } + + @Override + public void onClick(double mouseX, double mouseY) { + if (slotId == -1) return; + clickSlot.click(slotId, button); + super.onClick(mouseX, mouseY); + } + + @Override + protected boolean isValidClickButton(int button) { + this.button = button; + return super.isValidClickButton(button) || button == 1; + } + + public void setSlotId(int slotId) { + this.slotId = slotId; + } + + public void setCurrent(E current) { + this.current = current; + } + + @Override + protected void appendClickableNarrations(NarrationMessageBuilder builder) { + } + + public interface OptionInfo { + boolean isVertical(); + + /** + * @return The current option's position offset from the first option's position + */ + int getOffset(); + + int[] getOptionSize(); + + Identifier getOptionTexture(); + + Identifier getBackTexture(); + + Identifier getHoverTexture(); + + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/SortWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/SortWidget.java new file mode 100644 index 0000000000..dab3c6b4d8 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/SortWidget.java @@ -0,0 +1,70 @@ +package de.hysky.skyblocker.skyblock.auction.widgets; + +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.skyblock.auction.SlotClickHandler; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.MathHelper; + +public class SortWidget extends SliderWidget { + + /** + * @param x x position + * @param y y position + * @param clickSlot the parent AuctionsBrowser + */ + public SortWidget(int x, int y, SlotClickHandler clickSlot) { + super(x, y, 36, 9, Text.literal("Sort Widget"), clickSlot, Option.HIGH); + } + + public enum Option implements OptionInfo { + HIGH("high.png"), + LOW("low.png"), + SOON("soon.png"), + RAND("rand.png"); + + private final Identifier texture; + private static final String prefix = "textures/gui/auctions_gui/sort_widget/"; + private static final Identifier HOVER_TEXTURE = new Identifier(SkyblockerMod.NAMESPACE, prefix + "hover.png"); + private static final Identifier BACK_TEXTURE = new Identifier(SkyblockerMod.NAMESPACE, prefix + "back.png"); + + Option(String textureName) { + texture = new Identifier(SkyblockerMod.NAMESPACE, prefix + textureName); + } + + public Identifier getOptionTexture() { + return texture; + } + + private static final Option[] values = values(); + + public static Option get(int ordinal) { + return values[MathHelper.clamp(ordinal, 0, values.length - 1)]; + } + + @Override + public boolean isVertical() { + return false; + } + + @Override + public int getOffset() { + return 5 * ordinal(); + } + + @Override + public int[] getOptionSize() { + return new int[]{21, 9}; + } + + @Override + public Identifier getBackTexture() { + return BACK_TEXTURE; + } + + @Override + public Identifier getHoverTexture() { + return HOVER_TEXTURE; + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java b/src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java index c9cdb99a58..d4bf3d521c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java @@ -26,7 +26,7 @@ public class ItemRarityBackgrounds { private static final SkyblockerConfig.ItemInfoDisplay CONFIG = SkyblockerConfigManager.get().general.itemInfoDisplay; private static final Supplier SPRITE = () -> MinecraftClient.getInstance().getGuiAtlasManager().getSprite(CONFIG.itemRarityBackgroundStyle.tex); - private static final ImmutableMap LORE_RARITIES = ImmutableMap.ofEntries( + public static final ImmutableMap LORE_RARITIES = ImmutableMap.ofEntries( Map.entry("ADMIN", SkyblockItemRarity.ADMIN), Map.entry("ULTIMATE", SkyblockItemRarity.ULTIMATE), Map.entry("SPECIAL", SkyblockItemRarity.SPECIAL), //Very special is the same color so this will cover it diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/SkyblockItemRarity.java b/src/main/java/de/hysky/skyblocker/skyblock/item/SkyblockItemRarity.java index 4addeac62f..60bda97662 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/SkyblockItemRarity.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/SkyblockItemRarity.java @@ -15,16 +15,17 @@ public enum SkyblockItemRarity { UNCOMMON(Formatting.GREEN), COMMON(Formatting.WHITE); + public final int color; public final float r; public final float g; public final float b; SkyblockItemRarity(Formatting formatting) { - @SuppressWarnings("DataFlowIssue") - int rgb = formatting.getColorValue(); + //noinspection DataFlowIssue + this.color = formatting.getColorValue(); - this.r = ((rgb >> 16) & 0xFF) / 255f; - this.g = ((rgb >> 8) & 0xFF) / 255f; - this.b = (rgb & 0xFF) / 255f; + this.r = ((color >> 16) & 0xFF) / 255f; + this.g = ((color >> 8) & 0xFF) / 255f; + this.b = (color & 0xFF) / 255f; } } 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 62c5073585..7c3be9c96c 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 @@ -20,6 +20,7 @@ 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; @@ -92,27 +93,7 @@ public static void getTooltip(ItemStack stack, TooltipContext context, List { - neuName = neuName.replaceAll("LVL_\\d*_", ""); - String[] parts = neuName.split("_"); - String type = parts[0]; - neuName = neuName.replaceAll(type + "_", ""); - neuName = neuName + "-" + type; - neuName = neuName.replace("UNCOMMON", "1") - .replace("COMMON", "0") - .replace("RARE", "2") - .replace("EPIC", "3") - .replace("LEGENDARY", "4") - .replace("MYTHIC", "5") - .replace("-", ";"); - } - case "RUNE" -> neuName = neuName.replaceAll("_(?!.*_)", ";"); - case "POTION" -> neuName = ""; - case "ATTRIBUTE_SHARD" -> - neuName = internalID + "+" + neuName.replace("SHARD-", "").replaceAll("_(?!.*_)", ";"); - default -> neuName = neuName.replace(":", "-"); - } + neuName = getNeuName(internalID, neuName); if (!neuName.isEmpty() && lbinExist) { SkyblockerConfig.Average type = config.avg; @@ -264,6 +245,32 @@ public static void getTooltip(ItemStack stack, TooltipContext context, List { + neuName = neuName.replaceAll("LVL_\\d*_", ""); + String[] parts = neuName.split("_"); + String type = parts[0]; + neuName = neuName.replaceAll(type + "_", ""); + neuName = neuName + "-" + type; + neuName = neuName.replace("UNCOMMON", "1") + .replace("COMMON", "0") + .replace("RARE", "2") + .replace("EPIC", "3") + .replace("LEGENDARY", "4") + .replace("MYTHIC", "5") + .replace("-", ";"); + } + case "RUNE" -> neuName = neuName.replaceAll("_(?!.*_)", ";"); + case "POTION" -> neuName = ""; + case "ATTRIBUTE_SHARD" -> + neuName = internalID + "+" + neuName.replace("SHARD-", "").replaceAll("_(?!.*_)", ";"); + default -> neuName = neuName.replace(":", "-"); + } + return neuName; + } + private static void addExoticTooltip(List lines, String internalID, NbtCompound nbt, String colorHex, String expectedHex, String existingTooltip) { if (expectedHex != null && !colorHex.equalsIgnoreCase(expectedHex) && !ExoticTooltip.isException(internalID, colorHex) && !ExoticTooltip.intendedDyed(nbt)) { final ExoticTooltip.DyeType type = ExoticTooltip.checkDyeType(colorHex); diff --git a/src/main/java/de/hysky/skyblocker/utils/render/gui/AbstractCustomHypixelGUI.java b/src/main/java/de/hysky/skyblocker/utils/render/gui/AbstractCustomHypixelGUI.java new file mode 100644 index 0000000000..4f648b8c85 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/render/gui/AbstractCustomHypixelGUI.java @@ -0,0 +1,56 @@ +package de.hysky.skyblocker.utils.render.gui; + +import de.hysky.skyblocker.mixin.accessor.HandledScreenAccessor; +import de.hysky.skyblocker.skyblock.auction.AuctionHouseScreenHandler; +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.ScreenHandlerListener; +import net.minecraft.screen.slot.SlotActionType; +import net.minecraft.text.Text; + +public abstract class AbstractCustomHypixelGUI extends HandledScreen implements ScreenHandlerListener { + + public boolean isWaitingForServer = true; + public AbstractCustomHypixelGUI(T handler, PlayerInventory inventory, Text title) { + super(handler, inventory, title); + handler.addListener(this); + } + + protected void clickSlot(int slotID, int button) { + if (isWaitingForServer) return; + if (client == null) return; + assert this.client.interactionManager != null; + this.client.interactionManager.clickSlot(handler.syncId, slotID, button, SlotActionType.PICKUP, client.player); + handler.getCursorStack().setCount(0); + isWaitingForServer = true; + } + + protected void clickSlot(int slotID) { + clickSlot(slotID, 0); + } + + public void changeHandler(AuctionHouseScreenHandler newHandler) { + handler.removeListener(this); + ((HandledScreenAccessor) this).setHandler(newHandler); + handler.addListener(this); + } + + @Override + public void removed() { + super.removed(); + handler.removeListener(this); + } + + @Override + public final void onSlotUpdate(ScreenHandler handler, int slotId, ItemStack stack) { + onSlotChange(this.handler, slotId, stack); + isWaitingForServer = false; + } + + protected abstract void onSlotChange(T handler, int slotID, ItemStack stack); + + @Override + public void onPropertyUpdate(ScreenHandler handler, int property, int value) {} +} diff --git a/src/main/java/de/hysky/skyblocker/utils/render/gui/AbstractPopupScreen.java b/src/main/java/de/hysky/skyblocker/utils/render/gui/AbstractPopupScreen.java new file mode 100644 index 0000000000..2bd1595508 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/render/gui/AbstractPopupScreen.java @@ -0,0 +1,60 @@ +package de.hysky.skyblocker.utils.render.gui; + +import com.mojang.blaze3d.platform.GlConst; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +/** + * A more bare-bones version of Vanilla's Popup Screen. Meant to be extended. + */ +public class AbstractPopupScreen extends Screen { + private static final Identifier BACKGROUND_TEXTURE = new Identifier("popup/background"); + private final Screen backgroundScreen; + + protected AbstractPopupScreen(Text title, Screen backgroundScreen) { + super(title); + this.backgroundScreen = backgroundScreen; + } + + @Override + public void close() { + assert this.client != null; + this.client.setScreen(this.backgroundScreen); + } + + @Override + public void renderBackground(DrawContext context, int mouseX, int mouseY, float delta) { + this.backgroundScreen.render(context, -1, -1, delta); + context.draw(); + RenderSystem.clear(GlConst.GL_DEPTH_BUFFER_BIT, MinecraftClient.IS_SYSTEM_MAC); + this.renderInGameBackground(context); + } + + /** + * These are the inner positions and size of the popup, not outer + */ + public static void drawPopupBackground(DrawContext context, int x, int y, int width, int height) { + context.drawGuiTexture(BACKGROUND_TEXTURE, x - 18, y - 18, width + 36, height + 36); + } + + @Override + protected void init() { + super.init(); + initTabNavigation(); + } + + @Override + protected void initTabNavigation() { + this.backgroundScreen.resize(this.client, this.width, this.height); + } + + @Override + public void onDisplayed() { + super.onDisplayed(); + this.backgroundScreen.blur(); + } +} \ No newline at end of file diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index b1f3df9fe3..bda6a909cc 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -11,6 +11,7 @@ "text.skyblocker.quit_config": "Changes Not Saved", "text.skyblocker.quit_config_sure": "Are you sure you want to quit editing the config? Changes will not be saved!", "text.skyblocker.quit_discard": "Quit & Discard Changes", + "text.skyblocker.confirm": "Confirm", "text.skyblocker.config": "Open Config...", "text.skyblocker.source": "Source", "text.skyblocker.website": "Website", @@ -168,6 +169,9 @@ "text.autoconfig.skyblocker.option.general.searchOverlay.historyLabel": "History:", "text.autoconfig.skyblocker.option.general.betterPartyFinder": "Better Party Finder", "text.autoconfig.skyblocker.option.general.fancyCraftingTable": "Fancy Crafting Table UI", + "text.autoconfig.skyblocker.option.general.betterAuctionHouse": "Better Auction House", + "text.autoconfig.skyblocker.option.general.betterAuctionHouse.enabled": "Enabled", + "text.autoconfig.skyblocker.option.general.betterAuctionHouse.highlightUnderAvgPrice": "Highlight BIN under average price", "skyblocker.itemTooltip.nullMessage": "§cItem price information on tooltip will renew in max 60 seconds. If not, check latest.log", "skyblocker.itemTooltip.noData": "§cNo Data", @@ -619,9 +623,26 @@ "skyblocker.partyFinder.deList": "Click to de-list", "skyblocker.partyFinder.join": "Click to join", + "skyblocker.fancyAuctionHouse.editBid": "Click to edit bid!", + "skyblocker.fancyAuctionHouse.price": "Price:", + "skyblocker.fancyAuctionHouse.newBid": "New Bid:", + "skyblocker.fancyAuctionHouse.buy": "Buy!", + "skyblocker.fancyAuctionHouse.bid": "Bid!", + "skyblocker.fancyAuctionHouse.cantAfford": "Can't Afford!", + "skyblocker.fancyAuctionHouse.alreadyTopBid": "Already Top Bid!", + "skyblocker.fancyAuctionHouse.differentProfile": "On a different profile", + "skyblocker.fancyAuctionHouse.didntWin": "Didn't win :(", + "skyblocker.fancyAuctionHouse.changeProfile": "Change Profile", + "skyblocker.fancyAuctionHouse.collectAuction": "Collect Auction", + "skyblocker.fancyAuctionHouse.collectBid": "Collect Bid", + "skyblocker.fancyAuctionHouse.auctionEnded": "Auction Ended!", + "skyblocker.fancyAuctionHouse.cancelAuction": "Cancel Auction", + "skyblocker.fancyAuctionHouse.yourAuction": "This is your auction!", + "skyblocker.fancyAuctionHouse.youPay": "You pay: %s", + "skyblocker.crimson.kuudra.noArrowPoison": "No Arrow Poison!", "skyblocker.crimson.kuudra.lowArrowPoison": "Low on Arrow Poison!", - + "skyblocker.waypoints.ordered.groupNonExistent": "§cThe waypoint group %s doesn't exist.", "skyblocker.waypoints.ordered.add.invalidHexColor": "§cInvalid HEX color code!", "skyblocker.waypoints.ordered.addAt.success": "Added a waypoint in group %s at index %d.", diff --git a/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/auction_type_widget/all.png b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/auction_type_widget/all.png new file mode 100644 index 0000000000..8842041de9 Binary files /dev/null and b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/auction_type_widget/all.png differ diff --git a/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/auction_type_widget/auctions.png b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/auction_type_widget/auctions.png new file mode 100644 index 0000000000..1de6b9aaae Binary files /dev/null and b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/auction_type_widget/auctions.png differ diff --git a/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/auction_type_widget/back.png b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/auction_type_widget/back.png new file mode 100644 index 0000000000..58e84c3401 Binary files /dev/null and b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/auction_type_widget/back.png differ diff --git a/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/auction_type_widget/bin.png b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/auction_type_widget/bin.png new file mode 100644 index 0000000000..b816a9fb51 Binary files /dev/null and b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/auction_type_widget/bin.png differ diff --git a/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/auction_type_widget/hover.png b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/auction_type_widget/hover.png new file mode 100644 index 0000000000..cb55b1f038 Binary files /dev/null and b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/auction_type_widget/hover.png differ diff --git a/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/browser/background.png b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/browser/background.png new file mode 100644 index 0000000000..ca52a9e859 Binary files /dev/null and b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/browser/background.png differ diff --git a/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/browser/background_view.png b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/browser/background_view.png new file mode 100644 index 0000000000..34bf95c436 Binary files /dev/null and b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/browser/background_view.png differ diff --git a/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/rarity_widget/background.png b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/rarity_widget/background.png new file mode 100644 index 0000000000..d55e197364 Binary files /dev/null and b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/rarity_widget/background.png differ diff --git a/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/rarity_widget/hover.png b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/rarity_widget/hover.png new file mode 100644 index 0000000000..81ca8ef0c8 Binary files /dev/null and b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/rarity_widget/hover.png differ diff --git a/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/sort_widget/back.png b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/sort_widget/back.png new file mode 100644 index 0000000000..890b98d7f4 Binary files /dev/null and b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/sort_widget/back.png differ diff --git a/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/sort_widget/high.png b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/sort_widget/high.png new file mode 100644 index 0000000000..4e8a455a76 Binary files /dev/null and b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/sort_widget/high.png differ diff --git a/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/sort_widget/hover.png b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/sort_widget/hover.png new file mode 100644 index 0000000000..eeb6b1c680 Binary files /dev/null and b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/sort_widget/hover.png differ diff --git a/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/sort_widget/low.png b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/sort_widget/low.png new file mode 100644 index 0000000000..c53864fc4d Binary files /dev/null and b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/sort_widget/low.png differ diff --git a/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/sort_widget/rand.png b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/sort_widget/rand.png new file mode 100644 index 0000000000..d7dea84734 Binary files /dev/null and b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/sort_widget/rand.png differ diff --git a/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/sort_widget/soon.png b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/sort_widget/soon.png new file mode 100644 index 0000000000..d72acf59d7 Binary files /dev/null and b/src/main/resources/assets/skyblocker/textures/gui/auctions_gui/sort_widget/soon.png differ diff --git a/src/main/resources/assets/skyblocker/textures/gui/sprites/down_arrow_even.png b/src/main/resources/assets/skyblocker/textures/gui/sprites/down_arrow_even.png new file mode 100644 index 0000000000..94243d0af2 Binary files /dev/null and b/src/main/resources/assets/skyblocker/textures/gui/sprites/down_arrow_even.png differ diff --git a/src/main/resources/assets/skyblocker/textures/gui/sprites/up_arrow_even.png b/src/main/resources/assets/skyblocker/textures/gui/sprites/up_arrow_even.png new file mode 100644 index 0000000000..2243bb9503 Binary files /dev/null and b/src/main/resources/assets/skyblocker/textures/gui/sprites/up_arrow_even.png differ diff --git a/src/main/resources/skyblocker.mixins.json b/src/main/resources/skyblocker.mixins.json index 9f5f824032..1466d8f2a2 100644 --- a/src/main/resources/skyblocker.mixins.json +++ b/src/main/resources/skyblocker.mixins.json @@ -47,6 +47,7 @@ "accessor.RecipeBookWidgetAccessor", "accessor.ScreenAccessor", "accessor.SkullBlockEntityAccessor", + "accessor.SlotAccessor", "accessor.WorldRendererAccessor", "discordipc.ConnectionMixin" ],