aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/de/hysky
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/de/hysky')
-rw-r--r--src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java265
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java20
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java7
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/HandledScreenProviderMixin.java31
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/accessor/HandledScreenAccessor.java6
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/accessor/SlotAccessor.java17
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionBrowserScreen.java388
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionHouseScreenHandler.java58
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/auction/AuctionViewScreen.java296
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/auction/EditBidPopup.java111
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/auction/SlotClickHandler.java11
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/AuctionTypeWidget.java70
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/CategoryTabWidget.java58
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/RarityWidget.java105
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/SliderWidget.java107
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/SortWidget.java70
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/ItemRarityBackgrounds.java2
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/SkyblockItemRarity.java11
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java49
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/render/gui/AbstractCustomHypixelGUI.java56
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/render/gui/AbstractPopupScreen.java60
21 files changed, 1642 insertions, 156 deletions
diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
index bf98ac1f..a1e1dadc 100644
--- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
+++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
@@ -251,6 +251,9 @@ public class SkyblockerConfig {
public SearchOverlay searchOverlay = new SearchOverlay();
@SerialEntry
+ public FancyAuctionHouse fancyAuctionHouse = new FancyAuctionHouse();
+
+ @SerialEntry
public List<Integer> lockedSlots = new ArrayList<>();
@SerialEntry
@@ -406,138 +409,11 @@ public class SkyblockerConfig {
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<String> bazaarHistory = new ArrayList<>();
-
- @SerialEntry
- public List<String> 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 class SkyblockerConfig {
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 class SkyblockerConfig {
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<String> bazaarHistory = new ArrayList<>();
+
+ @SerialEntry
+ public List<String> 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 class SkyblockerConfig {
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 e310cb85..a74b9483 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 class GeneralCategory {
.controller(ConfigUtils::createBooleanController)
.build())
.build())
+
+ // Fancy Auction House
+ .group(OptionGroup.createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.general.betterAuctionHouse"))
+ .collapsed(true)
+ .option(Option.<Boolean>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.<Boolean>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 ceda9ed4..049443f7 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 @@ package de.hysky.skyblocker.mixin;
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 abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity
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 975c9c51..bf330d80 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 @@ package de.hysky.skyblocker.mixin;
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<T extends ScreenHandler> {
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<T extends ScreenHandler> {
}
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 d82422cb..5b84072d 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 00000000..ef11006c
--- /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 00000000..d47fef05
--- /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<AuctionHouseScreenHandler> {
+ 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<Sprite> UP_ARROW = () -> MinecraftClient.getInstance().getGuiAtlasManager().getSprite(up_arrow_tex);
+ public static final Supplier<Sprite> 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<CategoryTabWidget> 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<Text> 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<Text> 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<Text> 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<Text> 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<Text> 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<Text> 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 00000000..28898cdc
--- /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 00000000..a8b30a50
--- /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<AuctionHouseScreenHandler> {
+ 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<Text> tooltip) {
+ if (priceParsed) return;
+ String minBid = null;
+ String priceString = null;
+ AtomicReference<String> 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 00000000..6b90b86c
--- /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 00000000..b64a4583
--- /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 00000000..0caa233a
--- /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<AuctionTypeWidget.Option> {
+
+ /**
+ * @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 00000000..03d91780
--- /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 00000000..b6bd42a9
--- /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<Text> tooltip = List.of();
+ private String current = "?";
+ private int color = 0xFFEAEAEA;
+
+ public void setText(List<Text> tooltip, String current) {
+ this.tooltip = tooltip;
+ this.current = current;
+ for (Map.Entry<String, SkyblockItemRarity> 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 00000000..22fa1ad8
--- /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<E extends Enum<E> & 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 <strong>should be the one at ordinal 0</strong>
+ */
+ 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 00000000..dab3c6b4
--- /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<SortWidget.Option> {
+
+ /**
+ * @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 c9cdb99a..d4bf3d52 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 @@ import net.minecraft.text.Text;
public class ItemRarityBackgrounds {
private static final SkyblockerConfig.ItemInfoDisplay CONFIG = SkyblockerConfigManager.get().general.itemInfoDisplay;
private static final Supplier<Sprite> SPRITE = () -> MinecraftClient.getInstance().getGuiAtlasManager().getSprite(CONFIG.itemRarityBackgroundStyle.tex);
- private static final ImmutableMap<String, SkyblockItemRarity> LORE_RARITIES = ImmutableMap.ofEntries(
+ public static final ImmutableMap<String, SkyblockItemRarity> 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 4addeac6..60bda976 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 62c50735..7c3be9c9 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.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;
@@ -92,27 +93,7 @@ public class ItemTooltip {
We are skipping check average prices for potions, runes
and enchanted books because there is no data for their in API.
*/
- switch (internalID) {
- case "PET" -> {
- 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 class ItemTooltip {
}
}
+ @NotNull
+ public static String getNeuName(String internalID, String neuName) {
+ switch (internalID) {
+ case "PET" -> {
+ 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<Text> 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 00000000..4f648b8c
--- /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<T extends ScreenHandler> extends HandledScreen<T> 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 00000000..2bd15955
--- /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