aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/de/hysky/skyblocker/SkyblockerMod.java6
-rw-r--r--src/main/java/de/hysky/skyblocker/SkyblockerScreen.java125
-rw-r--r--src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java283
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java52
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java7
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java2
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java22
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/CommandTreeS2CPacketMixin.java21
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/DyeableItemMixin.java5
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/HandledScreenProviderMixin.java31
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/RenderFishMixin.java26
-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/FishingHelper.java35
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/Tips.java3
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/WarpAutocomplete.java46
-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/dwarven/CrystalsLocationsManager.java46
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dwarven/DwarvenHud.java48
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/end/EnderNodes.java138
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorAnimatedDyes.java181
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/HotbarSlotLock.java5
-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.java52
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/Ico.java1
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/PlayerLocator.java1
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/hud/HudPowderWidget.java21
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/Location.java4
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/Utils.java2
-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
41 files changed, 2379 insertions, 210 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
index 75918fa9..3d96cc50 100644
--- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
+++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
@@ -21,6 +21,7 @@ import de.hysky.skyblocker.skyblock.dwarven.CrystalsHud;
import de.hysky.skyblocker.skyblock.dwarven.CrystalsLocationsManager;
import de.hysky.skyblocker.skyblock.dwarven.DwarvenHud;
import de.hysky.skyblocker.skyblock.end.BeaconHighlighter;
+import de.hysky.skyblocker.skyblock.end.EnderNodes;
import de.hysky.skyblocker.skyblock.end.TheEnd;
import de.hysky.skyblocker.skyblock.garden.FarmingHud;
import de.hysky.skyblocker.skyblock.garden.LowerSensitivity;
@@ -98,6 +99,7 @@ public class SkyblockerMod implements ClientModInitializer {
ClientTickEvents.END_CLIENT_TICK.register(this::tick);
Utils.init();
SkyblockerConfigManager.init();
+ SkyblockerScreen.initClass();
Tips.init();
NEURepoManager.init();
ImageRepoLoader.init();
@@ -110,6 +112,7 @@ public class SkyblockerMod implements ClientModInitializer {
FairySouls.init();
Relics.init();
MythologicalRitual.init();
+ EnderNodes.init();
OrderedWaypoints.init();
BackpackPreview.init();
QuickNav.init();
@@ -148,6 +151,7 @@ public class SkyblockerMod implements ClientModInitializer {
TeleportOverlay.init();
CustomItemNames.init();
CustomArmorDyeColors.init();
+ CustomArmorAnimatedDyes.init();
CustomArmorTrims.init();
TicTacToe.init();
QuiverWarning.init();
@@ -166,6 +170,8 @@ public class SkyblockerMod implements ClientModInitializer {
containerSolverManager.init();
statusBarTracker.init();
BeaconHighlighter.init();
+ WarpAutocomplete.init();
+
Scheduler.INSTANCE.scheduleCyclic(Utils::update, 20);
Scheduler.INSTANCE.scheduleCyclic(DiscordRPCManager::updateDataAndPresence, 200);
Scheduler.INSTANCE.scheduleCyclic(LividColor::update, 10);
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerScreen.java b/src/main/java/de/hysky/skyblocker/SkyblockerScreen.java
new file mode 100644
index 00000000..ba0745ed
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/SkyblockerScreen.java
@@ -0,0 +1,125 @@
+package de.hysky.skyblocker;
+
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.skyblock.Tips;
+import de.hysky.skyblocker.utils.scheduler.Scheduler;
+import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
+import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
+import net.minecraft.client.font.TextRenderer;
+import net.minecraft.client.gui.DrawContext;
+import net.minecraft.client.gui.screen.ConfirmLinkScreen;
+import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.client.gui.widget.ButtonWidget;
+import net.minecraft.client.gui.widget.GridWidget;
+import net.minecraft.client.gui.widget.MultilineTextWidget;
+import net.minecraft.client.gui.widget.TextWidget;
+import net.minecraft.client.gui.widget.ThreePartsLayoutWidget;
+import net.minecraft.screen.ScreenTexts;
+import net.minecraft.text.OrderedText;
+import net.minecraft.text.StringVisitable;
+import net.minecraft.text.Text;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.Language;
+
+public class SkyblockerScreen extends Screen {
+ private static final int SPACING = 8;
+ private static final int BUTTON_WIDTH = 210;
+ private static final int HALF_BUTTON_WIDTH = 101; //Same as (210 - 8) / 2
+ private static final Text TITLE = Text.literal("Skyblocker " + SkyblockerMod.VERSION);
+ private static final Identifier ICON = new Identifier(SkyblockerMod.NAMESPACE, "icon.png");
+ private static final Text CONFIGURATION_TEXT = Text.translatable("text.skyblocker.config");
+ private static final Text SOURCE_TEXT = Text.translatable("text.skyblocker.source");
+ private static final Text REPORT_BUGS_TEXT = Text.translatable("menu.reportBugs");
+ private static final Text WEBSITE_TEXT = Text.translatable("text.skyblocker.website");
+ private static final Text TRANSLATE_TEXT = Text.translatable("text.skyblocker.translate");
+ private static final Text MODRINTH_TEXT = Text.translatable("text.skyblocker.modrinth");
+ private static final Text DISCORD_TEXT = Text.translatable("text.skyblocker.discord");
+ private final ThreePartsLayoutWidget layout = new ThreePartsLayoutWidget(this);
+
+ private SkyblockerScreen() {
+ super(TITLE);
+ }
+
+ public static void initClass() {
+ ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
+ dispatcher.register(ClientCommandManager.literal(SkyblockerMod.NAMESPACE)
+ .executes(Scheduler.queueOpenScreenCommand(SkyblockerScreen::new)));
+ });
+ }
+
+ @Override
+ protected void init() {
+ this.layout.addHeader(new IconTextWidget(this.getTitle(), this.textRenderer, ICON));
+
+ GridWidget gridWidget = this.layout.addBody(new GridWidget()).setSpacing(SPACING);
+ gridWidget.getMainPositioner().alignHorizontalCenter();
+ GridWidget.Adder adder = gridWidget.createAdder(2);
+
+ adder.add(ButtonWidget.builder(CONFIGURATION_TEXT, button -> this.openConfig()).width(BUTTON_WIDTH).build(), 2);
+ adder.add(ButtonWidget.builder(SOURCE_TEXT, ConfirmLinkScreen.opening(this, "https://github.com/SkyblockerMod/Skyblocker")).width(HALF_BUTTON_WIDTH).build());
+ adder.add(ButtonWidget.builder(REPORT_BUGS_TEXT, ConfirmLinkScreen.opening(this, "https://github.com/SkyblockerMod/Skyblocker/issues")).width(HALF_BUTTON_WIDTH).build());
+ adder.add(ButtonWidget.builder(WEBSITE_TEXT, ConfirmLinkScreen.opening(this, "https://hysky.de/")).width(HALF_BUTTON_WIDTH).build());
+ adder.add(ButtonWidget.builder(TRANSLATE_TEXT, ConfirmLinkScreen.opening(this, "https://translate.hysky.de/")).width(HALF_BUTTON_WIDTH).build());
+ adder.add(ButtonWidget.builder(MODRINTH_TEXT, ConfirmLinkScreen.opening(this, "https://modrinth.com/mod/skyblocker-liap")).width(HALF_BUTTON_WIDTH).build());
+ adder.add(ButtonWidget.builder(DISCORD_TEXT, ConfirmLinkScreen.opening(this, "https://discord.gg/aNNJHQykck")).width(HALF_BUTTON_WIDTH).build());
+ adder.add(ButtonWidget.builder(ScreenTexts.DONE, button -> this.close()).width(BUTTON_WIDTH).build(), 2);
+
+ MultilineTextWidget tip = new MultilineTextWidget(Text.translatable("skyblocker.tips.tip", Tips.nextTipInternal()), this.textRenderer)
+ .setCentered(true)
+ .setMaxWidth((int) (this.width * 0.7));
+
+ this.layout.addFooter(tip);
+ this.layout.refreshPositions();
+ this.layout.forEachChild(this::addDrawableChild);
+ }
+
+ @Override
+ protected void initTabNavigation() {
+ this.layout.refreshPositions();
+ }
+
+ private void openConfig() {
+ this.client.setScreen(SkyblockerConfigManager.createGUI(this));
+ }
+
+ @Override
+ public void render(DrawContext context, int mouseX, int mouseY, float delta) {
+ this.renderBackground(context, mouseX, mouseY, delta);
+ super.render(context, mouseX, mouseY, delta);
+ }
+
+ private static class IconTextWidget extends TextWidget {
+ private final Identifier icon;
+
+ IconTextWidget(Text message, TextRenderer textRenderer, Identifier icon) {
+ super(message, textRenderer);
+ this.icon = icon;
+ }
+
+ @Override
+ public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) {
+ Text text = this.getMessage();
+ TextRenderer textRenderer = this.getTextRenderer();
+
+ int width = this.getWidth();
+ int textWidth = textRenderer.getWidth(text);
+ float horizontalAlignment = 0.5f; // default
+ //17 = (32 + 2) / 2 • 32 + 2 is the width of the icon + spacing between icon and text
+ int x = this.getX() + 17 + Math.round(horizontalAlignment * (float) (width - textWidth));
+ int y = this.getY() + (this.getHeight() - textRenderer.fontHeight) / 2;
+ OrderedText orderedText = textWidth > width ? this.trim(text, width) : text.asOrderedText();
+
+ int iconX = x - 34;
+ int iconY = y - 13;
+
+ context.drawTextWithShadow(textRenderer, orderedText, x, y, this.getTextColor());
+ context.drawTexture(this.icon, iconX, iconY, 0, 0, 32, 32, 32, 32);
+ }
+
+ private OrderedText trim(Text text, int width) {
+ TextRenderer textRenderer = this.getTextRenderer();
+ StringVisitable stringVisitable = textRenderer.trimToWidth(text, width - textRenderer.getWidth(ScreenTexts.ELLIPSIS));
+ return Language.getInstance().reorder(StringVisitable.concat(stringVisitable, ScreenTexts.ELLIPSIS));
+ }
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
index bafcd115..e301e8e2 100644
--- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
+++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
@@ -1,6 +1,7 @@
package de.hysky.skyblocker.config;
import de.hysky.skyblocker.SkyblockerMod;
+import de.hysky.skyblocker.skyblock.item.CustomArmorAnimatedDyes;
import de.hysky.skyblocker.skyblock.item.CustomArmorTrims;
import de.hysky.skyblocker.utils.chat.ChatFilterResult;
import de.hysky.skyblocker.utils.waypoint.Waypoint;
@@ -250,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
@@ -263,6 +267,9 @@ public class SkyblockerConfig {
@SerialEntry
public Object2ObjectOpenHashMap<String, CustomArmorTrims.ArmorTrimId> customArmorTrims = new Object2ObjectOpenHashMap<>();
+
+ @SerialEntry
+ public Object2ObjectOpenHashMap<String, CustomArmorAnimatedDyes.AnimatedDye> customAnimatedDyes = new Object2ObjectOpenHashMap<>();
}
public static class TabHudConf {
@@ -349,6 +356,18 @@ public class SkyblockerConfig {
public static class Fishing {
@SerialEntry
public boolean enableFishingHelper = true;
+
+ @SerialEntry
+ public boolean enableFishingTimer = false;
+
+ @SerialEntry
+ public boolean changeTimerColor = true;
+
+ @SerialEntry
+ public float fishingTimerScale = 1f;
+
+ @SerialEntry
+ public boolean hideOtherPlayersRods = false;
}
public static class FairySouls {
@@ -402,138 +421,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;
@@ -566,6 +458,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;
@@ -647,6 +548,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();
@@ -1076,6 +1089,8 @@ public class SkyblockerConfig {
}
public static class TheEnd {
+ @SerialEntry
+ public boolean enableEnderNodeHelper = true;
@SerialEntry
public boolean hudEnabled = true;
@@ -1245,6 +1260,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..dbfbbb10 100644
--- a/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java
+++ b/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java
@@ -226,6 +226,38 @@ public class GeneralCategory {
newValue -> config.general.fishing.enableFishingHelper = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.general.fishing.enableFishingTimer"))
+ .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.general.fishing.enableFishingTimer.@Tooltip")))
+ .binding(defaults.general.fishing.enableFishingTimer,
+ () -> config.general.fishing.enableFishingTimer,
+ newValue -> config.general.fishing.enableFishingTimer = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.general.fishing.changeTimerColor"))
+ .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.general.fishing.changeTimerColor.@Tooltip")))
+ .binding(defaults.general.fishing.changeTimerColor,
+ () -> config.general.fishing.changeTimerColor,
+ newValue -> config.general.fishing.changeTimerColor = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<Float>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.general.fishing.fishingTimerScale"))
+ .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.general.fishing.fishingTimerScale.@Tooltip")))
+ .binding(defaults.general.fishing.fishingTimerScale,
+ () -> config.general.fishing.fishingTimerScale,
+ newValue -> config.general.fishing.fishingTimerScale = newValue)
+ .controller(FloatFieldControllerBuilder::create)
+ .build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.general.fishing.hideOtherPlayers"))
+ .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.general.fishing.hideOtherPlayers.@Tooltip")))
+ .binding(defaults.general.fishing.hideOtherPlayersRods,
+ () -> config.general.fishing.hideOtherPlayersRods,
+ newValue -> config.general.fishing.hideOtherPlayersRods = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
.build())
//Fairy Souls Helper
@@ -739,6 +771,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/config/categories/LocationsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java
index 67512b78..46f3067c 100644
--- a/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java
+++ b/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java
@@ -85,6 +85,13 @@ public class LocationsCategory {
.name(Text.translatable("text.autoconfig.skyblocker.option.locations.end"))
.collapsed(false)
.option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.end.enableEnderNodeHelper"))
+ .binding(defaults.locations.end.enableEnderNodeHelper,
+ () -> config.locations.end.enableEnderNodeHelper,
+ newValue -> config.locations.end.enableEnderNodeHelper = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<Boolean>createBuilder()
.name(Text.translatable("text.autoconfig.skyblocker.option.locations.end.hudEnabled"))
.binding(defaults.locations.end.hudEnabled,
() -> config.locations.end.hudEnabled,
diff --git a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java
index 8397292b..743f949f 100644
--- a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java
@@ -7,6 +7,7 @@ import de.hysky.skyblocker.skyblock.FishingHelper;
import de.hysky.skyblocker.skyblock.dungeon.DungeonScore;
import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager;
import de.hysky.skyblocker.skyblock.end.BeaconHighlighter;
+import de.hysky.skyblocker.skyblock.end.EnderNodes;
import de.hysky.skyblocker.skyblock.end.TheEnd;
import de.hysky.skyblocker.skyblock.waypoint.MythologicalRitual;
import de.hysky.skyblocker.utils.SlayerUtils;
@@ -91,6 +92,7 @@ public abstract class ClientPlayNetworkHandlerMixin {
@Inject(method = "onParticle", at = @At("RETURN"))
private void skyblocker$onParticle(ParticleS2CPacket packet, CallbackInfo ci) {
MythologicalRitual.onParticle(packet);
+ EnderNodes.onParticle(packet);
}
@ModifyExpressionValue(method = "onEntityStatus", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/EntityStatusS2CPacket;getEntity(Lnet/minecraft/world/World;)Lnet/minecraft/entity/Entity;"))
diff --git a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java
index ceda9ed4..8fb2fda4 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;
@@ -25,7 +27,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ClientPlayerEntity.class)
public abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity {
- @Shadow @Final protected MinecraftClient client;
+ @Shadow
+ @Final
+ protected MinecraftClient client;
public ClientPlayerEntityMixin(ClientWorld world, GameProfile profile) {
super(world, profile);
@@ -33,14 +37,9 @@ public abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity
@Inject(method = "dropSelectedItem", at = @At("HEAD"), cancellable = true)
public void skyblocker$dropSelectedItem(CallbackInfoReturnable<Boolean> cir) {
- if (Utils.isOnSkyblock()) {
- if (ItemProtection.isItemProtected(this.getInventory().getMainHandStack())) {
- if (!SkyblockerConfigManager.get().locations.dungeons.allowDroppingProtectedItems
- || (SkyblockerConfigManager.get().locations.dungeons.allowDroppingProtectedItems && !Utils.isInDungeons())) {
- cir.setReturnValue(false);
- }
- }
- HotbarSlotLock.handleDropSelectedItem(this.getInventory().selectedSlot, cir);
+ if (Utils.isOnSkyblock() && (ItemProtection.isItemProtected(this.getInventory().getMainHandStack()) || HotbarSlotLock.isLocked(this.getInventory().selectedSlot))
+ && (!SkyblockerConfigManager.get().locations.dungeons.allowDroppingProtectedItems || !Utils.isInDungeons())) {
+ cir.setReturnValue(false);
}
}
@@ -58,6 +57,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/CommandTreeS2CPacketMixin.java b/src/main/java/de/hysky/skyblocker/mixin/CommandTreeS2CPacketMixin.java
new file mode 100644
index 00000000..1cc1b8de
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/mixin/CommandTreeS2CPacketMixin.java
@@ -0,0 +1,21 @@
+package de.hysky.skyblocker.mixin;
+
+import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
+import com.mojang.brigadier.tree.CommandNode;
+import com.mojang.brigadier.tree.LiteralCommandNode;
+import de.hysky.skyblocker.skyblock.WarpAutocomplete;
+import de.hysky.skyblocker.utils.Utils;
+import net.minecraft.command.CommandSource;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+
+@Mixin(targets = "net.minecraft.network.packet.s2c.play.CommandTreeS2CPacket$CommandTree")
+public class CommandTreeS2CPacketMixin {
+ @ModifyExpressionValue(method = "getNode", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/CommandTreeS2CPacket$CommandTree;getNode(I)Lcom/mojang/brigadier/tree/CommandNode;", ordinal = 1))
+ public CommandNode<? extends CommandSource> modifyCommandSuggestions(CommandNode<CommandSource> original) {
+ if (Utils.isOnHypixel() && WarpAutocomplete.commandNode != null && original instanceof LiteralCommandNode<?> literalCommandNode && literalCommandNode.getLiteral().equals("warp")) {
+ return WarpAutocomplete.commandNode;
+ }
+ return original;
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/mixin/DyeableItemMixin.java b/src/main/java/de/hysky/skyblocker/mixin/DyeableItemMixin.java
index e5697085..64f6a452 100644
--- a/src/main/java/de/hysky/skyblocker/mixin/DyeableItemMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixin/DyeableItemMixin.java
@@ -2,6 +2,7 @@ package de.hysky.skyblocker.mixin;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.skyblock.item.CustomArmorAnimatedDyes;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.Utils;
import net.minecraft.item.DyeableItem;
@@ -16,6 +17,10 @@ public interface DyeableItemMixin {
if (Utils.isOnSkyblock()) {
String itemUuid = ItemUtils.getItemUuid(stack);
+ if (SkyblockerConfigManager.get().general.customAnimatedDyes.containsKey(itemUuid)) {
+ return CustomArmorAnimatedDyes.animateColorTransition(SkyblockerConfigManager.get().general.customAnimatedDyes.get(itemUuid));
+ }
+
return SkyblockerConfigManager.get().general.customDyeColors.getOrDefault(itemUuid, originalColor);
}
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/RenderFishMixin.java b/src/main/java/de/hysky/skyblocker/mixin/RenderFishMixin.java
new file mode 100644
index 00000000..e74bbaea
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/mixin/RenderFishMixin.java
@@ -0,0 +1,26 @@
+package de.hysky.skyblocker.mixin;
+
+
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.utils.Utils;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.render.VertexConsumerProvider;
+import net.minecraft.client.render.entity.FishingBobberEntityRenderer;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.entity.projectile.FishingBobberEntity;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(FishingBobberEntityRenderer.class)
+public abstract class RenderFishMixin {
+
+ @Inject(method = "render", at = @At("HEAD"), cancellable = true)
+ private void skyblocker$render(FishingBobberEntity fishingBobberEntity, float f, float g, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) {
+ //if rendered bobber is not the players and option to hide others is enabled do not render the bobber
+ if (Utils.isOnSkyblock() && fishingBobberEntity.getPlayerOwner() != MinecraftClient.getInstance().player && SkyblockerConfigManager.get().general.fishing.hideOtherPlayersRods) {
+ ci.cancel();
+ }
+ }
+}
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/FishingHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/FishingHelper.java
index 9e7cf541..7676860f 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/FishingHelper.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/FishingHelper.java
@@ -4,6 +4,8 @@ import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.utils.Utils;
import de.hysky.skyblocker.utils.render.RenderHelper;
import de.hysky.skyblocker.utils.render.title.Title;
+import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
+import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
import net.fabricmc.fabric.api.event.player.UseItemCallback;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
@@ -11,6 +13,7 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.FishingRodItem;
import net.minecraft.item.ItemStack;
import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket;
+import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import net.minecraft.util.TypedActionResult;
import net.minecraft.util.math.MathHelper;
@@ -19,6 +22,7 @@ import net.minecraft.util.math.Vec3d;
public class FishingHelper {
private static final Title title = new Title("skyblocker.fishing.reelNow", Formatting.GREEN);
private static long startTime;
+ private static long startTimeFish;
private static Vec3d normalYawVector;
public static void init() {
@@ -36,31 +40,58 @@ public class FishingHelper {
}
return TypedActionResult.pass(stack);
});
+ WorldRenderEvents.AFTER_TRANSLUCENT.register(FishingHelper::render);
}
public static void start(PlayerEntity player) {
startTime = System.currentTimeMillis();
+ startTimeFish = System.currentTimeMillis();
float yawRad = player.getYaw() * 0.017453292F;
normalYawVector = new Vec3d(-MathHelper.sin(yawRad), 0, MathHelper.cos(yawRad));
}
public static void reset() {
startTime = 0;
+ startTimeFish = 0;
+ }
+
+ public static void resetFish() {
+ startTimeFish = 0;
}
public static void onSound(PlaySoundS2CPacket packet) {
String path = packet.getSound().value().getId().getPath();
- if (SkyblockerConfigManager.get().general.fishing.enableFishingHelper && startTime != 0 && System.currentTimeMillis() >= startTime + 2000 && ("entity.generic.splash".equals(path) || "entity.player.splash".equals(path))) {
+ if (SkyblockerConfigManager.get().general.fishing.enableFishingHelper && startTimeFish != 0 && System.currentTimeMillis() >= startTimeFish + 2000 && ("entity.generic.splash".equals(path) || "entity.player.splash".equals(path))) {
ClientPlayerEntity player = MinecraftClient.getInstance().player;
if (player != null && player.fishHook != null) {
Vec3d soundToFishHook = player.fishHook.getPos().subtract(packet.getX(), 0, packet.getZ());
if (Math.abs(normalYawVector.x * soundToFishHook.z - normalYawVector.z * soundToFishHook.x) < 0.2D && Math.abs(normalYawVector.dotProduct(soundToFishHook)) < 4D && player.getPos().squaredDistanceTo(packet.getX(), packet.getY(), packet.getZ()) > 1D) {
RenderHelper.displayInTitleContainerAndPlaySound(title, 10);
- reset();
+ resetFish();
}
} else {
reset();
}
}
}
+
+ public static void render(WorldRenderContext context) {
+ if (SkyblockerConfigManager.get().general.fishing.enableFishingTimer && startTime != 0) {
+ ClientPlayerEntity player = MinecraftClient.getInstance().player;
+ if (player != null && player.fishHook != null) {
+ float time = (int) ((System.currentTimeMillis() - startTime) / 100f) / 10f; //leave 1dp in seconds
+ float scale = SkyblockerConfigManager.get().general.fishing.fishingTimerScale;
+ Vec3d pos = player.fishHook.getPos().add(0, 0.4 + scale / 10, 0);
+
+ Text text;
+ if (time >= 20 && SkyblockerConfigManager.get().general.fishing.changeTimerColor) {
+ text = Text.literal(String.valueOf(time)).formatted(Formatting.GREEN);
+ } else {
+ text = Text.literal(String.valueOf(time));
+ }
+
+ RenderHelper.renderText(context, text, pos, scale, true);
+ }
+ }
+ }
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/Tips.java b/src/main/java/de/hysky/skyblocker/skyblock/Tips.java
index ad345527..513dc4b7 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/Tips.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/Tips.java
@@ -27,6 +27,7 @@ public class Tips {
getTipFactory("skyblocker.tips.customItemNames", ClickEvent.Action.SUGGEST_COMMAND, "/skyblocker custom renameItem"),
getTipFactory("skyblocker.tips.customArmorDyeColors", ClickEvent.Action.SUGGEST_COMMAND, "/skyblocker custom dyeColor"),
getTipFactory("skyblocker.tips.customArmorTrims", ClickEvent.Action.SUGGEST_COMMAND, "/skyblocker custom armorTrim"),
+ getTipFactory("skyblocker.tips.customAnimatedDyes", ClickEvent.Action.SUGGEST_COMMAND, "/skyblocker custom animatedDye"),
getTipFactory("skyblocker.tips.fancyTabExtraInfo"),
getTipFactory("skyblocker.tips.helpCommand", ClickEvent.Action.SUGGEST_COMMAND, "/skyblocker help"),
getTipFactory("skyblocker.tips.discordRichPresence", ClickEvent.Action.SUGGEST_COMMAND, "/skyblocker config"),
@@ -102,7 +103,7 @@ public class Tips {
.append(Text.translatable("skyblocker.tips.clickDisable").styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/skyblocker tips disable"))));
}
- private static Text nextTipInternal() {
+ public static Text nextTipInternal() {
int randomInt = RANDOM.nextInt(TIPS.size());
while (randomInt == previousTipIndex) randomInt = RANDOM.nextInt(TIPS.size());
previousTipIndex = randomInt;
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/WarpAutocomplete.java b/src/main/java/de/hysky/skyblocker/skyblock/WarpAutocomplete.java
new file mode 100644
index 00000000..8862185f
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/WarpAutocomplete.java
@@ -0,0 +1,46 @@
+package de.hysky.skyblocker.skyblock;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import com.mojang.brigadier.tree.LiteralCommandNode;
+import de.hysky.skyblocker.SkyblockerMod;
+import de.hysky.skyblocker.utils.Http;
+import de.hysky.skyblocker.utils.Utils;
+import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
+import net.minecraft.command.CommandSource;
+import org.jetbrains.annotations.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument;
+import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal;
+
+/**
+ * the mixin {@link de.hysky.skyblocker.mixin.CommandTreeS2CPacketMixin}
+ */
+public class WarpAutocomplete {
+ private static final Logger LOGGER = LoggerFactory.getLogger(WarpAutocomplete.class);
+ @Nullable
+ public static LiteralCommandNode<FabricClientCommandSource> commandNode;
+
+ public static void init() {
+ CompletableFuture.supplyAsync(() -> {
+ try {
+ JsonArray jsonElements = SkyblockerMod.GSON.fromJson(Http.sendGetRequest("https://hysky.de/api/locations"), JsonArray.class);
+ return jsonElements.asList().stream().map(JsonElement::getAsString).toList();
+ } catch (Exception e) {
+ LOGGER.error("[Skyblocker] Failed to download warps list", e);
+ }
+ return List.<String>of();
+ }).thenAccept(warps -> commandNode = literal("warp")
+ .requires(fabricClientCommandSource -> Utils.isOnSkyblock())
+ .then(argument("destination", StringArgumentType.string())
+ .suggests((context, builder) -> CommandSource.suggestMatching(warps, builder))
+ ).build()
+ );
+ }
+}
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..c8bc1f13
--- /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 && slot.hasStack() && 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/dwarven/CrystalsLocationsManager.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationsManager.java
index f43574ab..9c37de51 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationsManager.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationsManager.java
@@ -4,11 +4,11 @@ import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.logging.LogUtils;
-
import de.hysky.skyblocker.SkyblockerMod;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.utils.Constants;
import de.hysky.skyblocker.utils.Utils;
+import de.hysky.skyblocker.utils.scheduler.MessageScheduler;
import de.hysky.skyblocker.utils.scheduler.Scheduler;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
@@ -24,7 +24,9 @@ import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.ClickEvent;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
+import net.minecraft.util.Formatting;
import net.minecraft.util.math.BlockPos;
+import org.slf4j.Logger;
import java.awt.*;
import java.util.Arrays;
@@ -35,11 +37,10 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
-import org.slf4j.Logger;
-
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument;
import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal;
+import static net.minecraft.command.CommandSource.suggestMatching;
public class CrystalsLocationsManager {
private static final Logger LOGGER = LogUtils.getLogger();
@@ -101,26 +102,34 @@ public class CrystalsLocationsManager {
LOGGER.error("[Skyblocker Crystals Locations Manager] Encountered an exception while extracing a location from a chat message!", e);
}
}
- protected static Boolean checkInCrystals(BlockPos pos){
+
+ protected static Boolean checkInCrystals(BlockPos pos) {
//checks if a location is inside crystal hollows bounds
return pos.getX() >= 202 && pos.getX() <= 823
&& pos.getZ() >= 202 && pos.getZ() <= 823
- && pos.getY() >= 31 && pos.getY() <= 188;
+ && pos.getY() >= 31 && pos.getY() <= 188;
}
private static void registerWaypointLocationCommands(CommandDispatcher<FabricClientCommandSource> dispatcher, CommandRegistryAccess registryAccess) {
dispatcher.register(literal(SkyblockerMod.NAMESPACE)
- .then(literal("crystalWaypoints")
- .then(argument("pos", BlockPosArgumentType.blockPos())
- .then(argument("place", StringArgumentType.greedyString())
- .executes(context -> addWaypointFromCommand(context.getSource(), getString(context, "place"), context.getArgument("pos", PosArgument.class)))
+ .then(literal("crystalWaypoints")
+ .then(argument("pos", BlockPosArgumentType.blockPos())
+ .then(argument("place", StringArgumentType.greedyString())
+ .suggests((context, builder) -> suggestMatching(WAYPOINT_LOCATIONS.keySet(), builder))
+ .executes(context -> addWaypointFromCommand(context.getSource(), getString(context, "place"), context.getArgument("pos", PosArgument.class)))
+ )
+ )
+ .then(literal("share")
+ .then(argument("place", StringArgumentType.greedyString())
+ .suggests((context, builder) -> suggestMatching(WAYPOINT_LOCATIONS.keySet(), builder))
+ .executes(context -> shareWaypoint(getString(context, "place")))
+ )
)
)
- )
);
}
- protected static Text getSetLocationMessage(String location,BlockPos blockPos) {
+ protected static Text getSetLocationMessage(String location, BlockPos blockPos) {
MutableText text = Constants.PREFIX.get();
text.append(Text.literal("Added waypoint for "));
Color locationColor = WAYPOINT_LOCATIONS.get(location).color;
@@ -159,6 +168,21 @@ public class CrystalsLocationsManager {
return Command.SINGLE_SUCCESS;
}
+ public static int shareWaypoint(String place) {
+ if (activeWaypoints.containsKey(place)) {
+ BlockPos pos = activeWaypoints.get(place).pos;
+ MessageScheduler.INSTANCE.sendMessageAfterCooldown(Constants.PREFIX.get().getString() + " " + place + ": " + pos.getX() + ", " + pos.getY() + ", " + pos.getZ());
+ } else {
+ //send fail message
+ if (CLIENT.player == null || CLIENT.getNetworkHandler() == null) {
+ return 0;
+ }
+ CLIENT.player.sendMessage(Constants.PREFIX.get().append(Text.translatable("text.autoconfig.skyblocker.option.locations.dwarvenMines.crystalsWaypoints.shareFail").formatted(Formatting.RED)), false);
+ }
+
+ return Command.SINGLE_SUCCESS;
+ }
+
private static void addCustomWaypoint(String waypointName, BlockPos pos) {
CrystalsWaypoint.Category category = WAYPOINT_LOCATIONS.get(waypointName);
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/DwarvenHud.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/DwarvenHud.java
index 3297ef5a..4ce92de8 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/DwarvenHud.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/DwarvenHud.java
@@ -24,29 +24,33 @@ import java.util.stream.Stream;
public class DwarvenHud {
- public static final MinecraftClient client = MinecraftClient.getInstance();
- public static List<Commission> commissionList = new ArrayList<>();
+ private static final MinecraftClient CLIENT = MinecraftClient.getInstance();
+ private static List<Commission> commissionList = new ArrayList<>();
public static String mithrilPowder = "0";
public static String gemStonePowder = "0";
+ public static String glacitePowder = "0";
- public static final List<Pattern> COMMISSIONS = Stream.of(
+ private static final List<Pattern> COMMISSIONS = Stream.of(
"(?:Titanium|Mithril|Hard Stone) Miner",
- "(?:Ice Walker|Golden Goblin|(?<!Golden )Goblin|Goblin Raid|Automaton|Sludge|Team Treasurite Member|Yog|Boss Corleone|Thyst) Slayer",
+ "(?:Glacite Walker|Golden Goblin|(?<!Golden )Goblin|Goblin Raid|Treasure Hoarder|Automaton|Sludge|Team Treasurite Member|Yog|Boss Corleone|Thyst) Slayer",
"(?:Lava Springs|Cliffside Veins|Rampart's Quarry|Upper Mines|Royal Mines) Mithril",
"(?:Lava Springs|Cliffside Veins|Rampart's Quarry|Upper Mines|Royal Mines) Titanium",
"Goblin Raid",
- "(?:Powder Ghast|Star Sentry|Treasure Hoarder) Puncher",
+ "(?:Star Sentry|Treasure Hoarder) Puncher",
"(?<!Lucky )Raffle",
"Lucky Raffle",
"2x Mithril Powder Collector",
"First Event",
- "(?:Ruby|Amber|Sapphire|Jade|Amethyst|Topaz) Gemstone Collector",
+ "(?:Ruby|Amber|Sapphire|Jade|Amethyst|Topaz|Onyx|Aquamarine|Citrine|Peridot) Gemstone Collector",
"(?:Amber|Sapphire|Jade|Amethyst|Topaz) Crystal Hunter",
- "Chest Looter").map(s -> Pattern.compile("(" + s + "): (\\d+\\.?\\d*%|DONE)")
+ "(?:Umber|Tungsten|Glacite|Scrap) Collector",
+ "Mineshaft Explorer",
+ "(?:Chest|Corpse) Looter").map(s -> Pattern.compile("(" + s + "): (\\d+\\.?\\d*%|DONE)")
).collect(Collectors.toList());
- public static final Pattern MITHRIL_PATTERN = Pattern.compile("Mithril Powder: [0-9,]+");
- public static final Pattern GEMSTONE_PATTERN = Pattern.compile("Gemstone Powder: [0-9,]+");
+ private static final Pattern MITHRIL_PATTERN = Pattern.compile("Mithril: [0-9,]+");
+ private static final Pattern GEMSTONE_PATTERN = Pattern.compile("Gemstone: [0-9,]+");
+ private static final Pattern GLACITE_PATTERN = Pattern.compile("Glacite: [0-9,]+");
public static void init() {
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(ClientCommandManager.literal("skyblocker")
@@ -59,8 +63,8 @@ public class DwarvenHud {
HudRenderCallback.EVENT.register((context, tickDelta) -> {
if (!SkyblockerConfigManager.get().locations.dwarvenMines.dwarvenHud.enabledCommissions && !SkyblockerConfigManager.get().locations.dwarvenMines.dwarvenHud.enabledPowder
- || client.options.playerListKey.isPressed()
- || client.player == null
+ || CLIENT.options.playerListKey.isPressed()
+ || CLIENT.player == null
|| (!Utils.isInDwarvenMines() && !Utils.isInCrystalHollows())) {
return;
}
@@ -74,7 +78,7 @@ public class DwarvenHud {
});
}
- public static void render(HudCommsWidget hcw, HudPowderWidget hpw, DrawContext context, int comHudX, int comHudY, int powderHudX, int powderHudY, List<Commission> commissions) {
+ protected static void render(HudCommsWidget hcw, HudPowderWidget hpw, DrawContext context, int comHudX, int comHudY, int powderHudX, int powderHudY, List<Commission> commissions) {
switch (SkyblockerConfigManager.get().locations.dwarvenMines.dwarvenHud.style) {
case SIMPLE -> renderSimple(hcw, hpw, context, comHudX, comHudY, powderHudX, powderHudY, commissions);
case FANCY -> renderFancy(hcw, hpw, context, comHudX, comHudY, powderHudX, powderHudY, commissions);
@@ -91,7 +95,7 @@ public class DwarvenHud {
* @param powderHudY Y coordinate of the powder hud
* @param commissions the commissions to render to the commissions hud
*/
- public static void renderClassic(DrawContext context, int comHudX, int comHudY, int powderHudX, int powderHudY, List<Commission> commissions) {
+ private static void renderClassic(DrawContext context, int comHudX, int comHudY, int powderHudX, int powderHudY, List<Commission> commissions) {
if (SkyblockerConfigManager.get().general.tabHud.enableHudBackground) {
context.fill(comHudX, comHudY, comHudX + 200, comHudY + (20 * commissions.size()), 0x64000000);
context.fill(powderHudX, powderHudY, powderHudX + 200, powderHudY + 40, 0x64000000);
@@ -106,7 +110,7 @@ public class DwarvenHud {
percentage = 100f;
}
- context.drawTextWithShadow(client.textRenderer,
+ context.drawTextWithShadow(CLIENT.textRenderer,
Text.literal(commission.commission + ": ").formatted(Formatting.AQUA)
.append(Text.literal(commission.progression).formatted(Colors.hypixelProgressColor(percentage))),
comHudX + 5, comHudY + y + 5, 0xFFFFFFFF);
@@ -115,16 +119,16 @@ public class DwarvenHud {
}
if (SkyblockerConfigManager.get().locations.dwarvenMines.dwarvenHud.enabledPowder) {
//render mithril powder then gemstone
- context.drawTextWithShadow(client.textRenderer,
+ context.drawTextWithShadow(CLIENT.textRenderer,
Text.literal("Mithril: " + mithrilPowder).formatted(Formatting.AQUA),
powderHudX + 5, powderHudY + 5, 0xFFFFFFFF);
- context.drawTextWithShadow(client.textRenderer,
+ context.drawTextWithShadow(CLIENT.textRenderer,
Text.literal("Gemstone: " + gemStonePowder).formatted(Formatting.DARK_PURPLE),
powderHudX + 5, powderHudY + 25, 0xFFFFFFFF);
}
}
- public static void renderSimple(HudCommsWidget hcw, HudPowderWidget hpw, DrawContext context, int comHudX, int comHudY, int powderHudX, int powderHudY, List<Commission> commissions) {
+ private static void renderSimple(HudCommsWidget hcw, HudPowderWidget hpw, DrawContext context, int comHudX, int comHudY, int powderHudX, int powderHudY, List<Commission> commissions) {
if (SkyblockerConfigManager.get().locations.dwarvenMines.dwarvenHud.enabledCommissions) {
hcw.updateData(commissions, false);
hcw.update();
@@ -140,7 +144,7 @@ public class DwarvenHud {
}
}
- public static void renderFancy(HudCommsWidget hcw, HudPowderWidget hpw, DrawContext context, int comHudX, int comHudY, int powderHudX, int powderHudY, List<Commission> commissions) {
+ private static void renderFancy(HudCommsWidget hcw, HudPowderWidget hpw, DrawContext context, int comHudX, int comHudY, int powderHudX, int powderHudY, List<Commission> commissions) {
if (SkyblockerConfigManager.get().locations.dwarvenMines.dwarvenHud.enabledCommissions) {
hcw.updateData(commissions, true);
hcw.update();
@@ -157,7 +161,7 @@ public class DwarvenHud {
}
public static void update() {
- if (client.player == null || client.getNetworkHandler() == null
+ if (CLIENT.player == null || CLIENT.getNetworkHandler() == null
|| !SkyblockerConfigManager.get().locations.dwarvenMines.dwarvenHud.enabledCommissions && !SkyblockerConfigManager.get().locations.dwarvenMines.dwarvenHud.enabledPowder
|| !Utils.isInCrystalHollows() && !Utils.isInDwarvenMines()) {
return;
@@ -165,7 +169,7 @@ public class DwarvenHud {
commissionList = new ArrayList<>();
- for (PlayerListEntry playerListEntry : client.getNetworkHandler().getPlayerList()) {
+ for (PlayerListEntry playerListEntry : CLIENT.getNetworkHandler().getPlayerList()) {
if (playerListEntry.getDisplayName() == null) {
continue;
}
@@ -186,6 +190,10 @@ public class DwarvenHud {
if (gemstoneMatcher.matches()) {
gemStonePowder = gemstoneMatcher.group(0).split(": ")[1];
}
+ Matcher glaciteMatcher = GLACITE_PATTERN.matcher(name);
+ if (glaciteMatcher.matches()) {
+ glacitePowder = glaciteMatcher.group(0).split(": ")[1];
+ }
}
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/end/EnderNodes.java b/src/main/java/de/hysky/skyblocker/skyblock/end/EnderNodes.java
new file mode 100644
index 00000000..b4af7256
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/end/EnderNodes.java
@@ -0,0 +1,138 @@
+package de.hysky.skyblocker.skyblock.end;
+
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.utils.Utils;
+import de.hysky.skyblocker.utils.scheduler.Scheduler;
+import de.hysky.skyblocker.utils.waypoint.Waypoint;
+import it.unimi.dsi.fastutil.ints.IntIntMutablePair;
+import it.unimi.dsi.fastutil.ints.IntIntPair;
+import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
+import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
+import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
+import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.network.packet.s2c.play.ParticleS2CPacket;
+import net.minecraft.particle.ParticleType;
+import net.minecraft.particle.ParticleTypes;
+import net.minecraft.util.ActionResult;
+import net.minecraft.util.DyeColor;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Direction;
+import net.minecraft.util.math.MathHelper;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class EnderNodes {
+ private static final MinecraftClient client = MinecraftClient.getInstance();
+ private static final Map<BlockPos, EnderNode> enderNodes = new HashMap<>();
+
+ public static void init() {
+ Scheduler.INSTANCE.scheduleCyclic(EnderNodes::update, 20);
+ WorldRenderEvents.AFTER_TRANSLUCENT.register(EnderNodes::render);
+ AttackBlockCallback.EVENT.register((player, world, hand, pos, direction) -> {
+ enderNodes.remove(pos);
+ return ActionResult.PASS;
+ });
+ ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> reset());
+ }
+
+ public static void onParticle(ParticleS2CPacket packet) {
+ if (!shouldProcess()) return;
+ ParticleType<?> particleType = packet.getParameters().getType();
+ if (!ParticleTypes.PORTAL.getType().equals(particleType) && !ParticleTypes.WITCH.getType().equals(particleType))
+ return;
+
+ double x = packet.getX();
+ double y = packet.getY();
+ double z = packet.getZ();
+ double xFrac = MathHelper.floorMod(x, 1);
+ double yFrac = MathHelper.floorMod(y, 1);
+ double zFrac = MathHelper.floorMod(z, 1);
+ BlockPos pos;
+ Direction direction;
+ if (yFrac == 0.25) {
+ pos = BlockPos.ofFloored(x, y - 1, z);
+ direction = Direction.UP;
+ } else if (yFrac == 0.75) {
+ pos = BlockPos.ofFloored(x, y + 1, z);
+ direction = Direction.DOWN;
+ } else if (xFrac == 0.25) {
+ pos = BlockPos.ofFloored(x - 1, y, z);
+ direction = Direction.EAST;
+ } else if (xFrac == 0.75) {
+ pos = BlockPos.ofFloored(x + 1, y, z);
+ direction = Direction.WEST;
+ } else if (zFrac == 0.25) {
+ pos = BlockPos.ofFloored(x, y, z - 1);
+ direction = Direction.SOUTH;
+ } else if (zFrac == 0.75) {
+ pos = BlockPos.ofFloored(x, y, z + 1);
+ direction = Direction.NORTH;
+ } else {
+ return;
+ }
+
+ EnderNode enderNode = enderNodes.computeIfAbsent(pos, EnderNode::new);
+ IntIntPair particles = enderNode.particles.get(direction);
+ particles.left(particles.leftInt() + 1);
+ particles.right(particles.rightInt() + 1);
+ }
+
+ private static void update() {
+ if (shouldProcess()) {
+ for (EnderNode enderNode : enderNodes.values()) {
+ enderNode.updateParticles();
+ }
+ }
+ }
+
+ private static void render(WorldRenderContext context) {
+ if (shouldProcess()) {
+ for (EnderNode enderNode : enderNodes.values()) {
+ if (enderNode.shouldRender()) {
+ enderNode.render(context);
+ }
+ }
+ }
+ }
+
+ private static boolean shouldProcess() {
+ return SkyblockerConfigManager.get().locations.end.enableEnderNodeHelper && Utils.isInTheEnd();
+ }
+
+ private static void reset() {
+ enderNodes.clear();
+ }
+
+ public static class EnderNode extends Waypoint {
+ private final Map<Direction, IntIntPair> particles = Map.of(
+ Direction.UP, new IntIntMutablePair(0, 0),
+ Direction.DOWN, new IntIntMutablePair(0, 0),
+ Direction.EAST, new IntIntMutablePair(0, 0),
+ Direction.WEST, new IntIntMutablePair(0, 0),
+ Direction.SOUTH, new IntIntMutablePair(0, 0),
+ Direction.NORTH, new IntIntMutablePair(0, 0)
+ );
+ private long lastConfirmed;
+
+ private EnderNode(BlockPos pos) {
+ super(pos, () -> SkyblockerConfigManager.get().general.waypoints.waypointType, DyeColor.CYAN.getColorComponents(), false);
+ }
+
+ private void updateParticles() {
+ long currentTimeMillis = System.currentTimeMillis();
+ if (lastConfirmed + 2000 > currentTimeMillis || client.world == null || !particles.entrySet().stream().allMatch(entry -> entry.getValue().leftInt() >= 5 && entry.getValue().rightInt() >= 5 || !client.world.getBlockState(pos.offset(entry.getKey())).isAir())) return;
+ lastConfirmed = currentTimeMillis;
+ for (Map.Entry<Direction, IntIntPair> entry : particles.entrySet()) {
+ entry.getValue().left(0);
+ entry.getValue().right(0);
+ }
+ }
+
+ @Override
+ public boolean shouldRender() {
+ return super.shouldRender() && lastConfirmed + 5000 > System.currentTimeMillis();
+ }
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorAnimatedDyes.java b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorAnimatedDyes.java
new file mode 100644
index 00000000..b011b2b0
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/CustomArmorAnimatedDyes.java
@@ -0,0 +1,181 @@
+package de.hysky.skyblocker.skyblock.item;
+
+import static com.mojang.brigadier.arguments.StringArgumentType.getString;
+import static com.mojang.brigadier.arguments.StringArgumentType.word;
+import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument;
+import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.arguments.BoolArgumentType;
+import com.mojang.brigadier.arguments.IntegerArgumentType;
+
+import de.hysky.skyblocker.SkyblockerMod;
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.utils.Constants;
+import de.hysky.skyblocker.utils.ItemUtils;
+import de.hysky.skyblocker.utils.Utils;
+import dev.isxander.yacl3.config.v2.api.SerialEntry;
+import it.unimi.dsi.fastutil.objects.Object2ObjectFunction;
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
+import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
+import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
+import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
+import net.minecraft.command.CommandRegistryAccess;
+import net.minecraft.item.DyeableItem;
+import net.minecraft.item.ItemStack;
+import net.minecraft.text.Text;
+import net.minecraft.util.math.MathHelper;
+
+public class CustomArmorAnimatedDyes {
+ private static final Object2ObjectOpenHashMap<AnimatedDye, AnimatedDyeStateTracker> STATE_TRACKER_MAP = new Object2ObjectOpenHashMap<>();
+ private static final Object2ObjectFunction<AnimatedDye, AnimatedDyeStateTracker> NEW_STATE_TRACKER = _dye -> AnimatedDyeStateTracker.create();
+ private static final int DEFAULT_TICK_DELAY = 4;
+ private static int ticks;
+
+ public static void init() {
+ ClientCommandRegistrationCallback.EVENT.register(CustomArmorAnimatedDyes::registerCommands);
+ ClientTickEvents.END_CLIENT_TICK.register(_client -> ++ticks);
+ }
+
+ private static void registerCommands(CommandDispatcher<FabricClientCommandSource> dispatcher, CommandRegistryAccess registryAccess) {
+ dispatcher.register(literal(SkyblockerMod.NAMESPACE)
+ .then(literal("custom")
+ .then(literal("animatedDye")
+ .executes(context -> customizeAnimatedDye(context.getSource(), null, null, 0, false, 0))
+ .then(argument("hex1", word())
+ .then(argument("hex2", word())
+ .then(argument("samples", IntegerArgumentType.integer(1))
+ .then(argument("cycleBack", BoolArgumentType.bool())
+ .executes(context -> customizeAnimatedDye(context.getSource(), getString(context, "hex1"), getString(context, "hex2"), IntegerArgumentType.getInteger(context, "samples"), BoolArgumentType.getBool(context, "cycleBack"), DEFAULT_TICK_DELAY))
+ .then(argument("tickDelay", IntegerArgumentType.integer(0, 20))
+ .executes(context ->customizeAnimatedDye(context.getSource(), getString(context, "hex1"), getString(context, "hex2"), IntegerArgumentType.getInteger(context, "samples"), BoolArgumentType.getBool(context, "cycleBack"), IntegerArgumentType.getInteger(context, "tickDelay")))))))))));
+ }
+
+ private static int customizeAnimatedDye(FabricClientCommandSource source, String hex1, String hex2, int samples, boolean cycleBack, int tickDelay) {
+ if (hex1 != null && hex2 != null && (!CustomArmorDyeColors.isHexadecimalColor(hex1) || !CustomArmorDyeColors.isHexadecimalColor(hex2))) {
+ source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customAnimatedDyes.invalidHex")));
+
+ return Command.SINGLE_SUCCESS;
+ }
+
+ ItemStack heldItem = source.getPlayer().getMainHandStack();
+
+ if (Utils.isOnSkyblock() && heldItem != null && !heldItem.isEmpty()) {
+ if (heldItem.getItem() instanceof DyeableItem) {
+ String itemUuid = ItemUtils.getItemUuid(heldItem);
+
+ if (!itemUuid.isEmpty()) {
+ Object2ObjectOpenHashMap<String, AnimatedDye> customAnimatedDyes = SkyblockerConfigManager.get().general.customAnimatedDyes;
+
+ if (hex1 == null && hex2 == null) {
+ if (customAnimatedDyes.containsKey(itemUuid)) {
+ customAnimatedDyes.remove(itemUuid);
+ SkyblockerConfigManager.save();
+ source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.customAnimatedDyes.removed")));
+ } else {
+ source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customAnimatedDyes.neverHad")));
+ }
+ } else {
+ AnimatedDye animatedDye = new AnimatedDye(Integer.decode("0x" + hex1.replace("#", "")), Integer.decode("0x" + hex2.replace("#", "")), samples, cycleBack, tickDelay);
+
+ customAnimatedDyes.put(itemUuid, animatedDye);
+ SkyblockerConfigManager.save();
+ source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.customAnimatedDyes.added")));
+ }
+ } else {
+ source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customAnimatedDyes.noItemUuid")));
+ }
+ } else {
+ source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customAnimatedDyes.notDyeable")));
+ }
+ } else {
+ source.sendError(Constants.PREFIX.get().append(Text.translatable("skyblocker.customAnimatedDyes.unableToSetDye")));
+ }
+
+ return Command.SINGLE_SUCCESS;
+ }
+
+ public static int animateColorTransition(AnimatedDye animatedDye) {
+ AnimatedDyeStateTracker trackedState = STATE_TRACKER_MAP.computeIfAbsent(animatedDye, NEW_STATE_TRACKER);
+
+ if (trackedState.lastRecordedTick + animatedDye.tickDelay() > ticks) {
+ return trackedState.lastColor;
+ }
+
+ trackedState.lastRecordedTick = ticks;
+
+ return animatedDye.interpolate(trackedState);
+ }
+
+ //Credit to https://codepen.io/OliverBalfour/post/programmatically-making-gradients
+ private static int interpolate(int firstColor, int secondColor, double percentage) {
+ int r1 = MathHelper.square((firstColor >> 16) & 0xFF);
+ int g1 = MathHelper.square((firstColor >> 8) & 0xFF);
+ int b1 = MathHelper.square(firstColor & 0xFF);
+
+ int r2 = MathHelper.square((secondColor >> 16) & 0xFF);
+ int g2 = MathHelper.square((secondColor >> 8) & 0xFF);
+ int b2 = MathHelper.square(secondColor & 0xFF);
+
+ double inverse = 1d - percentage;
+
+ int r3 = (int) Math.floor(Math.sqrt(r1 * inverse + r2 * percentage));
+ int g3 = (int) Math.floor(Math.sqrt(g1 * inverse + g2 * percentage));
+ int b3 = (int) Math.floor(Math.sqrt(b1 * inverse + b2 * percentage));
+
+ return (r3 << 16) | (g3 << 8 ) | b3;
+ }
+
+ private static class AnimatedDyeStateTracker {
+ private int sampleCounter;
+ private boolean onBackCycle = false;
+ private int lastColor = 0;
+ private int lastRecordedTick = 0;
+
+ boolean shouldCycleBack(int samples, boolean canCycleBack) {
+ return canCycleBack && sampleCounter == samples;
+ }
+
+ int getAndDecrement() {
+ return sampleCounter--;
+ }
+
+ int getAndIncrement() {
+ return sampleCounter++;
+ }
+
+ static AnimatedDyeStateTracker create() {
+ return new AnimatedDyeStateTracker();
+ }
+ }
+
+ public record AnimatedDye(@SerialEntry int color1, @SerialEntry int color2, @SerialEntry int samples, @SerialEntry boolean cycleBack, @SerialEntry int tickDelay) {
+
+ private int interpolate(AnimatedDyeStateTracker stateTracker) {
+ if (stateTracker.shouldCycleBack(samples, cycleBack)) stateTracker.onBackCycle = true;
+
+ if (stateTracker.onBackCycle) {
+ double percent = (1d / (double) samples) * stateTracker.getAndDecrement();
+
+ //Go back to normal cycle once we've cycled all the way back
+ if (stateTracker.sampleCounter == 0) stateTracker.onBackCycle = false;
+
+ int interpolatedColor = CustomArmorAnimatedDyes.interpolate(color1, color2, percent);
+ stateTracker.lastColor = interpolatedColor;
+
+ return interpolatedColor;
+ }
+
+ //This will only happen if cycleBack is false
+ if (stateTracker.sampleCounter == samples) stateTracker.sampleCounter = 0;
+
+ double percent = (1d / (double) samples) * stateTracker.getAndIncrement();
+ int interpolatedColor = CustomArmorAnimatedDyes.interpolate(color1, color2, percent);
+
+ stateTracker.lastColor = interpolatedColor;
+
+ return interpolatedColor;
+ }
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/HotbarSlotLock.java b/src/main/java/de/hysky/skyblocker/skyblock/item/HotbarSlotLock.java
index 069a030d..0fda3ef4 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/HotbarSlotLock.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/HotbarSlotLock.java
@@ -5,7 +5,6 @@ import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.option.KeyBinding;
import org.lwjgl.glfw.GLFW;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
@@ -24,10 +23,6 @@ public class HotbarSlotLock {
return SkyblockerConfigManager.get().general.lockedSlots.contains(slot);
}
- public static void handleDropSelectedItem(int slot, CallbackInfoReturnable<Boolean> cir) {
- if (isLocked(slot)) cir.setReturnValue(false);
- }
-
public static void handleInputEvents(ClientPlayerEntity player) {
while (hotbarSlotLock.wasPressed()) {
List<Integer> lockedSlots = SkyblockerConfigManager.get().general.lockedSlots;
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 637aea22..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;
@@ -218,7 +199,8 @@ public class ItemTooltip {
}
if (TooltipInfoType.COLOR.isTooltipEnabledAndHasOrNullWarning(internalID) && stack.getNbt() != null) {
- boolean hasCustomDye = SkyblockerConfigManager.get().general.customDyeColors.containsKey(ItemUtils.getItemUuid(stack));
+ String uuid = ItemUtils.getItemUuid(stack);
+ boolean hasCustomDye = SkyblockerConfigManager.get().general.customDyeColors.containsKey(uuid) || SkyblockerConfigManager.get().general.customAnimatedDyes.containsKey(uuid);
if (!hasCustomDye && stack.getItem() instanceof DyeableItem item && item.hasColor(stack)) {
String colorHex = String.format("%06X", item.getColor(stack));
@@ -263,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/skyblock/tabhud/util/Ico.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/Ico.java
index 4872435b..818056f0 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/Ico.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/Ico.java
@@ -72,4 +72,5 @@ public class Ico {
public static final ItemStack LIME_DYE = new ItemStack(Items.LIME_DYE);
public static final ItemStack ENCHANTED_BOOK = new ItemStack(Items.ENCHANTED_BOOK);
public static final ItemStack SPIDER_EYE = new ItemStack(Items.SPIDER_EYE);
+ public static final ItemStack BLUE_ICE = new ItemStack(Items.BLUE_ICE);
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/PlayerLocator.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/PlayerLocator.java
index e5f5bfc8..7aec604f 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/PlayerLocator.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/PlayerLocator.java
@@ -27,6 +27,7 @@ public class PlayerLocator {
INSTANCED("kuudra"),
THE_RIFT("rift"),
DARK_AUCTION("dark_auction"),
+ GLACITE_MINESHAFT("mineshaft"),
UNKNOWN("unknown");
public final String internal;
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/hud/HudPowderWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/hud/HudPowderWidget.java
index fe23f19a..50a7880c 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/hud/HudPowderWidget.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/hud/HudPowderWidget.java
@@ -30,6 +30,10 @@ public class HudPowderWidget extends Widget {
*/
private static int gemstonePowder = 0;
/**
+ * current value of Glacite Powder
+ */
+ private static int glacitePowder = 0;
+ /**
* the difference between the previous and current value of Mithril Powder
*/
private static int mithrilPowderDiff = 0;
@@ -38,6 +42,10 @@ public class HudPowderWidget extends Widget {
*/
private static int gemstonePowderDiff = 0;
/**
+ * the difference between the previous and current value of Glacite Powder
+ */
+ private static int glacitePowderDiff = 0;
+ /**
* The initial value of the timer for the difference update delay countdown.
*/
private static long startTime = System.currentTimeMillis();
@@ -77,8 +85,8 @@ public class HudPowderWidget extends Widget {
/**
* Converts Powder and difference values to a string and adds commas to the digits of the numbers.
*
- * @param powder the value of Mithril or Gemstone Powder
- * @param diff the difference between the previous and current value of Mithril or Gemstone Powder
+ * @param powder the value of Mithril, Gemstone Powder, or Glacite Powder
+ * @param diff the difference between the previous and current value of Mithril, Gemstone, or Glacite Powder
* @return formatted string
*/
private static String formatPowderString(int powder, int diff) {
@@ -94,15 +102,18 @@ public class HudPowderWidget extends Widget {
int newMithrilPowder = parsePowder(DwarvenHud.mithrilPowder);
int newGemstonePowder = parsePowder(DwarvenHud.gemStonePowder);
+ int newGlacitePowder = parsePowder(DwarvenHud.glacitePowder);
- if (newMithrilPowder != mithrilPowder || newGemstonePowder != gemstonePowder || elapsedTime > 2000) {
+ if (newMithrilPowder != mithrilPowder || newGemstonePowder != gemstonePowder || newGlacitePowder != glacitePowder || elapsedTime > 2000) {
startTime = System.currentTimeMillis();
mithrilPowderDiff = newMithrilPowder - mithrilPowder;
gemstonePowderDiff = newGemstonePowder - gemstonePowder;
+ glacitePowderDiff = newGlacitePowder - glacitePowder;
mithrilPowder = newMithrilPowder;
gemstonePowder = newGemstonePowder;
+ glacitePowder = newGlacitePowder;
}
}
@@ -111,9 +122,11 @@ public class HudPowderWidget extends Widget {
updatePowders();
String mithrilPowderString = formatPowderString(mithrilPowder, mithrilPowderDiff);
String gemstonePowderString = formatPowderString(gemstonePowder, gemstonePowderDiff);
+ String glacitePowderString = formatPowderString(glacitePowder, glacitePowderDiff);
- this.addSimpleIcoText(Ico.MITHRIL, "Mithril: ", Formatting.AQUA, mithrilPowderString);
+ this.addSimpleIcoText(Ico.MITHRIL, "Mithril: ", Formatting.DARK_GREEN, mithrilPowderString);
this.addSimpleIcoText(Ico.AMETHYST_SHARD, "Gemstone: ", Formatting.DARK_PURPLE, gemstonePowderString);
+ this.addSimpleIcoText(Ico.BLUE_ICE, "Glacite: ", Formatting.AQUA, glacitePowderString);
}
}
diff --git a/src/main/java/de/hysky/skyblocker/utils/Location.java b/src/main/java/de/hysky/skyblocker/utils/Location.java
index bd2773fd..d5214afd 100644
--- a/src/main/java/de/hysky/skyblocker/utils/Location.java
+++ b/src/main/java/de/hysky/skyblocker/utils/Location.java
@@ -83,6 +83,10 @@ public enum Location {
*/
KUUDRAS_HOLLOW("kuudra"),
/**
+ * The freezing cold Glacite Mineshafts! *brr... so cold... :(*
+ */
+ GLACITE_MINESHAFT("mineshaft"),
+ /**
* Unknown Skyblock location
*/
UNKNOWN("unknown");
diff --git a/src/main/java/de/hysky/skyblocker/utils/Utils.java b/src/main/java/de/hysky/skyblocker/utils/Utils.java
index 3e3bc4af..bbee3ce1 100644
--- a/src/main/java/de/hysky/skyblocker/utils/Utils.java
+++ b/src/main/java/de/hysky/skyblocker/utils/Utils.java
@@ -98,7 +98,7 @@ public class Utils {
}
public static boolean isInDwarvenMines() {
- return location == Location.DWARVEN_MINES || FabricLoader.getInstance().isDevelopmentEnvironment();
+ return location == Location.DWARVEN_MINES || location == Location.GLACITE_MINESHAFT || FabricLoader.getInstance().isDevelopmentEnvironment();
}
public static boolean isInTheRift() {
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