aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.gradle6
-rw-r--r--gradle.properties2
-rw-r--r--src/main/java/de/hysky/skyblocker/SkyblockerMod.java4
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java22
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/HelperCategory.java15
-rw-r--r--src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java11
-rw-r--r--src/main/java/de/hysky/skyblocker/config/configs/HelperConfig.java8
-rw-r--r--src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java12
-rw-r--r--src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java11
-rw-r--r--src/main/java/de/hysky/skyblocker/mixins/PlayerSkinTextureMixin.java51
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/bazaar/BazaarHelper.java73
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/bazaar/ReorderHelper.java73
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/crimson/dojo/ControlTestHelper.java2
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/Reparty.java172
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/LightsOn.java46
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/device/SimonSays.java122
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/filters/SimpleChatFilter.java3
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotText.java19
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextManager.java2
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/CollectionAdder.java7
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/SkillLevelAdder.java9
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipAdder.java3
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipManager.java2
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemStackBuilder.java5
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/itemlist/SearchResultsWidget.java2
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/profileviewer/collections/GenericCategory.java2
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/profileviewer/inventory/itemLoaders/ItemLoader.java10
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/ItemUtils.java47
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/TextTransformer.java92
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/Utils.java126
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/chat/ChatPatternListener.java3
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java20
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolver.java3
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolverManager.java5
-rw-r--r--src/main/resources/assets/skyblocker/lang/en_us.json19
-rw-r--r--src/main/resources/fabric.mod.json1
36 files changed, 837 insertions, 173 deletions
diff --git a/build.gradle b/build.gradle
index ea70c4ef..56f281fb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -30,6 +30,9 @@ repositories {
}
maven { url "https://repo.codemc.io/repository/maven-public/" } // For Occlusion Culling library
maven { url "https://repo.nea.moe/releases" } // For neu repoparser
+
+ maven { url "https://maven.azureaaron.net/releases" }
+ maven { url "https://maven.azureaaron.net/snapshots" }
}
dependencies {
@@ -50,6 +53,9 @@ dependencies {
// YACL
include modImplementation("dev.isxander:yet-another-config-lib:${project.yacl_version}-fabric")
+ // HM API (Hypixel Mod API Library)
+ include modImplementation("net.azureaaron:hm-api:${project.hm_api_version}")
+
// Mod Menu
modImplementation "com.terraformersmc:modmenu:${project.mod_menu_version}"
diff --git a/gradle.properties b/gradle.properties
index 614c7a1d..e97585c9 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -14,6 +14,8 @@ fabric_api_version=0.100.1+1.21
# Minecraft Mods
## YACL (https://github.com/isXander/YetAnotherConfigLib)
yacl_version=3.5.0+1.21
+## HM API (https://github.com/AzureAaron/hm-api)
+hm_api_version=1.0.0+1.21
## Mod Menu (https://modrinth.com/mod/modmenu/versions)
mod_menu_version = 11.0.0-beta.1
## REI (https://modrinth.com/mod/rei/versions?l=fabric)
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
index f1eb4321..8dd1419d 100644
--- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
+++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
@@ -14,6 +14,8 @@ import de.hysky.skyblocker.skyblock.chocolatefactory.TimeTowerReminder;
import de.hysky.skyblocker.skyblock.crimson.dojo.DojoManager;
import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra;
import de.hysky.skyblocker.skyblock.dungeon.*;
+import de.hysky.skyblocker.skyblock.dungeon.device.LightsOn;
+import de.hysky.skyblocker.skyblock.dungeon.device.SimonSays;
import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen;
import de.hysky.skyblocker.skyblock.dungeon.puzzle.*;
import de.hysky.skyblocker.skyblock.dungeon.puzzle.boulder.Boulder;
@@ -151,6 +153,8 @@ public class SkyblockerMod implements ClientModInitializer {
Silverfish.init();
IceFill.init();
DungeonScore.init();
+ SimonSays.init();
+ LightsOn.init();
PartyFinderScreen.initClass();
ChestValue.init();
FireFreezeStaffTimer.init();
diff --git a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java
index 28ace441..017e9186 100644
--- a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java
+++ b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java
@@ -269,6 +269,28 @@ public class DungeonsCategory {
.build())
.build())
+ // Devices (F7/M7)
+ .group(OptionGroup.createBuilder()
+ .name(Text.translatable("skyblocker.config.dungeons.devices"))
+ .collapsed(true)
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("skyblocker.config.dungeons.devices.solveSimonSays"))
+ .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.devices.solveSimonSays.@Tooltip")))
+ .binding(defaults.dungeons.devices.solveSimonSays,
+ () -> config.dungeons.devices.solveSimonSays,
+ newValue -> config.dungeons.devices.solveSimonSays = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("skyblocker.config.dungeons.devices.solveLightsOn"))
+ .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.devices.solveLightsOn.@Tooltip")))
+ .binding(defaults.dungeons.devices.solveLightsOn,
+ () -> config.dungeons.devices.solveLightsOn,
+ newValue -> config.dungeons.devices.solveLightsOn = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .build())
+
// Dungeon Secret Waypoints
.group(OptionGroup.createBuilder()
.name(Text.translatable("skyblocker.config.dungeons.secretWaypoints"))
diff --git a/src/main/java/de/hysky/skyblocker/config/categories/HelperCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/HelperCategory.java
index 56dbca94..ec2c561c 100644
--- a/src/main/java/de/hysky/skyblocker/config/categories/HelperCategory.java
+++ b/src/main/java/de/hysky/skyblocker/config/categories/HelperCategory.java
@@ -2,6 +2,7 @@ package de.hysky.skyblocker.config.categories;
import de.hysky.skyblocker.config.ConfigUtils;
import de.hysky.skyblocker.config.SkyblockerConfig;
+import de.hysky.skyblocker.skyblock.bazaar.BazaarHelper;
import de.hysky.skyblocker.utils.waypoint.Waypoint;
import dev.isxander.yacl3.api.ConfigCategory;
import dev.isxander.yacl3.api.Option;
@@ -206,6 +207,20 @@ public class HelperCategory {
.build())
.build())
+ //Bazaar
+ .group(OptionGroup.createBuilder()
+ .name(Text.translatable("skyblocker.config.helpers.bazaar"))
+ .collapsed(true)
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("skyblocker.config.helpers.bazaar.enableBazaarHelper"))
+ .description(OptionDescription.of(Text.translatable("skyblocker.config.helpers.bazaar.enableBazaarHelper.@Tooltip", BazaarHelper.getExpiringIcon(), BazaarHelper.getExpiredIcon(), BazaarHelper.getFilledIcon(69), BazaarHelper.getFilledIcon(100))))
+ .binding(defaults.helpers.bazaar.enableBazaarHelper,
+ () -> config.helpers.bazaar.enableBazaarHelper,
+ newValue -> config.helpers.bazaar.enableBazaarHelper = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .build())
+
.build();
}
}
diff --git a/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java
index 7b394b53..1a0cad9d 100644
--- a/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java
+++ b/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java
@@ -42,6 +42,9 @@ public class DungeonsConfig {
public Terminals terminals = new Terminals();
@SerialEntry
+ public Devices devices = new Devices();
+
+ @SerialEntry
public SecretWaypoints secretWaypoints = new SecretWaypoints();
@SerialEntry
@@ -135,6 +138,14 @@ public class DungeonsConfig {
public boolean blockIncorrectClicks = false;
}
+ public static class Devices {
+ @SerialEntry
+ public boolean solveSimonSays = true;
+
+ @SerialEntry
+ public boolean solveLightsOn = true;
+ }
+
public static class SecretWaypoints {
@SerialEntry
public boolean enableRoomMatching = true;
diff --git a/src/main/java/de/hysky/skyblocker/config/configs/HelperConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/HelperConfig.java
index 636d76da..e009f680 100644
--- a/src/main/java/de/hysky/skyblocker/config/configs/HelperConfig.java
+++ b/src/main/java/de/hysky/skyblocker/config/configs/HelperConfig.java
@@ -26,6 +26,9 @@ public class HelperConfig {
@SerialEntry
public ChocolateFactory chocolateFactory = new ChocolateFactory();
+ @SerialEntry
+ public Bazaar bazaar = new Bazaar();
+
public static class MythologicalRitual {
@SerialEntry
public boolean enableMythologicalRitualHelper = true;
@@ -94,4 +97,9 @@ public class HelperConfig {
@SerialEntry
public boolean straySound = true;
}
+
+ public static class Bazaar {
+ @SerialEntry
+ public boolean enableBazaarHelper = true;
+ }
}
diff --git a/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java
index 6c10e5d2..a2d7887b 100644
--- a/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java
@@ -1,7 +1,7 @@
package de.hysky.skyblocker.mixins;
-
import de.hysky.skyblocker.skyblock.crimson.dojo.DojoManager;
+import de.hysky.skyblocker.skyblock.dungeon.device.SimonSays;
import de.hysky.skyblocker.utils.Utils;
import net.minecraft.block.BlockState;
import net.minecraft.client.world.ClientWorld;
@@ -11,13 +11,21 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import com.llamalad7.mixinextras.sugar.Local;
+
@Mixin(ClientWorld.class)
public class ClientWorldMixin {
+ /**
+ * @implNote The {@code pos} can be mutable when this is called by chunk delta updates, so if you want to copy it into memory
+ * (e.g. store it in a field/list/map) make sure to duplicate it via {@link BlockPos#toImmutable()}.
+ */
@Inject(method = "handleBlockUpdate", at = @At("RETURN"))
- private void skyblocker$handleBlockUpdate(BlockPos pos, BlockState state, int flags, CallbackInfo ci) {
+ private void skyblocker$handleBlockUpdate(CallbackInfo ci, @Local(argsOnly = true) BlockPos pos, @Local(argsOnly = true) BlockState state) {
if (Utils.isInCrimson()) {
DojoManager.onBlockUpdate(pos.toImmutable(), state);
}
+
+ SimonSays.onBlockUpdate(pos, state);
}
}
diff --git a/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java
index f2e3e907..709b8697 100644
--- a/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java
@@ -247,10 +247,21 @@ public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen
return;
}
// Prevent salvaging
+ // TODO in future maybe also block clicking the salvage button if a protected item manages to get into the menu
if (title.equals("Salvage Items") && ItemProtection.isItemProtected(stack)) {
ci.cancel();
return;
}
+ // Prevent Trading
+ if (title.startsWith("You ") && ItemProtection.isItemProtected(stack)) { //Terrible way to detect the trade menu lol
+ ci.cancel();
+ return;
+ }
+ // Prevent Auctioning
+ if ((title.equals("Create BIN Auction") || title.equals("Create Auction")) && ItemProtection.isItemProtected(stack)) {
+ ci.cancel();
+ return;
+ }
switch (this.handler) {
case GenericContainerScreenHandler genericContainerScreenHandler when genericContainerScreenHandler.getRows() == 6 -> {
diff --git a/src/main/java/de/hysky/skyblocker/mixins/PlayerSkinTextureMixin.java b/src/main/java/de/hysky/skyblocker/mixins/PlayerSkinTextureMixin.java
index 828d32e3..9b9691c5 100644
--- a/src/main/java/de/hysky/skyblocker/mixins/PlayerSkinTextureMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixins/PlayerSkinTextureMixin.java
@@ -1,5 +1,8 @@
package de.hysky.skyblocker.mixins;
+import java.awt.Color;
+import java.util.Set;
+
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -9,32 +12,62 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
+import com.llamalad7.mixinextras.sugar.Share;
+import com.llamalad7.mixinextras.sugar.ref.LocalBooleanRef;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.skyblock.item.PlayerHeadHashCache;
import de.hysky.skyblocker.utils.Utils;
import net.minecraft.client.texture.NativeImage;
import net.minecraft.client.texture.PlayerSkinTexture;
+import net.minecraft.util.math.ColorHelper;
@Mixin(PlayerSkinTexture.class)
public class PlayerSkinTextureMixin {
+ @Unique
+ private static final Set<String> STRIP_DE_FACTO_TRANSPARENT_PIXELS = Set.of(
+ "4f3b91b6aa7124f30ed4ad1b2bb012a82985a33640555e18e792f96af8f58ec6", /*Titanium Necklace*/
+ "49821410631186c6f3fbbae5f0ef5b947f475eb32027a8aad0a456512547c209", /*Titanium Cloak*/
+ "4162303bcdd770aebe7fd19fa26371390a7515140358548084361b5056cdc4e6" /*Titanium Belt*/);
+ @Unique
+ private static final float BRIGHTNESS_THRESHOLD = 0.1f;
+
@Shadow
@Final
private String url;
- @Unique
- private boolean isSkyblockSkinTexture;
-
@Inject(method = "remapTexture", at = @At("HEAD"))
- private void skyblocker$determineSkinSource(CallbackInfoReturnable<NativeImage> cir) {
- if (Utils.isOnSkyblock()) {
- int skinHash = PlayerHeadHashCache.getSkinHash(this.url).hashCode();
- this.isSkyblockSkinTexture = PlayerHeadHashCache.contains(skinHash);
+ private void skyblocker$determineSkinSource(NativeImage image, CallbackInfoReturnable<NativeImage> cir, @Share("isSkyblockSkinTexture") LocalBooleanRef isSkyblockSkinTexture) {
+ if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().uiAndVisuals.dontStripSkinAlphaValues) {
+ String skinTextureHash = PlayerHeadHashCache.getSkinHash(this.url);
+ int skinHash = skinTextureHash.hashCode();
+ isSkyblockSkinTexture.set(PlayerHeadHashCache.contains(skinHash));
+
+ //Hypixel had the grand idea of using black pixels in place of actual transparent pixels on the titanium equipment so here we go!
+ if (STRIP_DE_FACTO_TRANSPARENT_PIXELS.contains(skinTextureHash)) {
+ stripDeFactoTransparentPixels(image);
+ }
}
}
@WrapWithCondition(method = "remapTexture", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/texture/PlayerSkinTexture;stripAlpha(Lnet/minecraft/client/texture/NativeImage;IIII)V"))
- private boolean skyblocker$dontStripAlphaValues(NativeImage image, int x1, int y1, int x2, int y2) {
- return !(SkyblockerConfigManager.get().uiAndVisuals.dontStripSkinAlphaValues && this.isSkyblockSkinTexture);
+ private boolean skyblocker$dontStripAlphaValues(NativeImage image, int x1, int y1, int x2, int y2, @Share("isSkyblockSkinTexture") LocalBooleanRef isSkyblockSkinTexture) {
+ return !isSkyblockSkinTexture.get();
+ }
+
+ @Unique
+ private static void stripDeFactoTransparentPixels(NativeImage image) {
+ int height = image.getHeight();
+ int width = image.getWidth();
+
+ for (int x = 0; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ int color = image.getColor(x, y);
+ float[] hsb = Color.RGBtoHSB(ColorHelper.Abgr.getRed(color), ColorHelper.Abgr.getGreen(color), ColorHelper.Abgr.getBlue(color), null);
+
+ //Work around "fake" transparent pixels - Thanks Hypixel I totally appreciate this!
+ if (hsb[2] <= BRIGHTNESS_THRESHOLD) image.setColor(x, y, ColorHelper.Abgr.withAlpha(0x00, color & 0x00FFFFFF));
+ }
+ }
}
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/bazaar/BazaarHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/bazaar/BazaarHelper.java
new file mode 100644
index 00000000..8b83b06b
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/bazaar/BazaarHelper.java
@@ -0,0 +1,73 @@
+package de.hysky.skyblocker.skyblock.bazaar;
+
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
+import de.hysky.skyblocker.skyblock.item.slottext.SlotTextAdder;
+import de.hysky.skyblocker.utils.ItemUtils;
+import net.minecraft.item.ItemStack;
+import net.minecraft.screen.slot.Slot;
+import net.minecraft.text.MutableText;
+import net.minecraft.text.Text;
+import net.minecraft.util.Formatting;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class BazaarHelper extends SlotTextAdder {
+ private static final Pattern FILLED_PATTERN = Pattern.compile("Filled: \\S+ \\(?([\\d.]+)%\\)?!?");
+ private static final int RED = 0xe60b1e;
+ private static final int YELLOW = 0xe6ba0b;
+ private static final int GREEN = 0x1ee60b;
+
+ public BazaarHelper() {
+ super("(?:Co-op|Your) Bazaar Orders");
+ }
+
+ @Override
+ public @NotNull List<SlotText> getText(Slot slot) {
+ if (!SkyblockerConfigManager.get().helpers.bazaar.enableBazaarHelper) return List.of();
+ // Skip the first row as it's always glass panes.
+ if (slot.id < 10) return List.of();
+ // Skip the last 10 items. 11 is subtracted because size is 1-based so the last slot is size - 1.
+ if (slot.id > slot.inventory.size() - 11) return List.of(); //Note that this also skips the slots in player's inventory (anything above 36/45/54 depending on the order count)
+
+ int column = slot.id % 9;
+ if (column == 0 || column == 8) return List.of(); // Skip the first and last column as those are always glass panes as well.
+
+ ItemStack item = slot.getStack();
+ if (item.isEmpty()) return List.of(); //We've skipped all invalid slots, so we can just check if it's not air here.
+
+ Matcher matcher = ItemUtils.getLoreLineIfMatch(item, FILLED_PATTERN);
+ if (matcher != null) {
+ List<Text> lore = ItemUtils.getLore(item);
+ if (!lore.isEmpty() && lore.getLast().getString().equals("Click to claim!")) { //Only show the filled icon when there are items to claim
+ int filled = NumberUtils.toInt(matcher.group(1));
+ return SlotText.topLeftList(getFilledIcon(filled));
+ }
+ }
+
+ if (ItemUtils.getLoreLineIf(item, str -> str.equals("Expired!")) != null) {
+ return SlotText.topLeftList(getExpiredIcon());
+ } else if (ItemUtils.getLoreLineIf(item, str -> str.startsWith("Expires in")) != null) {
+ return SlotText.topLeftList(getExpiringIcon());
+ }
+
+ return List.of();
+ }
+
+ public static @NotNull MutableText getExpiredIcon() {
+ return Text.literal("⏰").withColor(RED).formatted(Formatting.BOLD);
+ }
+
+ public static @NotNull MutableText getExpiringIcon() {
+ return Text.literal("⏰").withColor(YELLOW).formatted(Formatting.BOLD);
+ }
+
+ public static @NotNull MutableText getFilledIcon(int filled) {
+ if (filled < 100) return Text.literal("%").withColor(YELLOW).formatted(Formatting.BOLD);
+ return Text.literal("✅").withColor(GREEN).formatted(Formatting.BOLD);
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/bazaar/ReorderHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/bazaar/ReorderHelper.java
new file mode 100644
index 00000000..c2b11926
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/bazaar/ReorderHelper.java
@@ -0,0 +1,73 @@
+package de.hysky.skyblocker.skyblock.bazaar;
+
+import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
+import de.hysky.skyblocker.utils.ItemUtils;
+import de.hysky.skyblocker.utils.render.gui.ColorHighlight;
+import de.hysky.skyblocker.utils.render.gui.ContainerSolver;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.util.InputUtil;
+import net.minecraft.item.ItemStack;
+import net.minecraft.item.Items;
+import net.minecraft.screen.slot.Slot;
+import net.minecraft.text.Text;
+import net.minecraft.util.Formatting;
+import org.jetbrains.annotations.Nullable;
+import org.lwjgl.glfw.GLFW;
+
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ReorderHelper extends ContainerSolver {
+ private static final Pattern BUY_PATTERN = Pattern.compile("([\\d,]+)x missing items\\.");
+ private static final Pattern SELL_PATTERN = Pattern.compile("([\\d,]+)x items\\.");
+
+ public ReorderHelper() {
+ super("^Order options");
+ }
+
+ @Override
+ protected boolean isEnabled() {
+ return true;
+ }
+
+ @Override
+ protected boolean onClickSlot(int slot, ItemStack stack, int screenId, String[] groups) {
+ // V This part is so that it short-circuits if not necessary
+ if ((slot == 11 || slot == 13) && stack.isOf(Items.GREEN_TERRACOTTA) && InputUtil.isKeyPressed(MinecraftClient.getInstance().getWindow().getHandle(), GLFW.GLFW_KEY_LEFT_CONTROL)) {
+ Matcher matcher;
+ // The terracotta is at slot 13 on sell orders and at slot 11 on buy orders
+ if (slot == 13) matcher = ItemUtils.getLoreLineIfContainsMatch(stack, SELL_PATTERN);
+ else matcher = ItemUtils.getLoreLineIfContainsMatch(stack, BUY_PATTERN);
+ if (matcher != null) {
+ MinecraftClient.getInstance().keyboard.setClipboard(matcher.group(1).replace(",", ""));
+ return false;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) {
+ return List.of();
+ }
+
+ public static class Tooltip extends TooltipAdder {
+ public Tooltip() {
+ super("^Order options", Integer.MIN_VALUE);
+ }
+
+ @Override
+ public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) {
+ if (focusedSlot == null || !stack.isOf(Items.GREEN_TERRACOTTA)) return;
+ switch (focusedSlot.id) {
+ case 11, 13 -> {
+ lines.add(Text.empty());
+ lines.add(Text.empty().append(Text.translatable("skyblocker.reorderHelper.tooltip.line1")).formatted(Formatting.DARK_GRAY, Formatting.ITALIC));
+ lines.add(Text.empty().append(Text.translatable("skyblocker.reorderHelper.tooltip.line2")).formatted(Formatting.DARK_GRAY, Formatting.ITALIC));
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/dojo/ControlTestHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/dojo/ControlTestHelper.java
index 2f616a1e..f63d2fa2 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/crimson/dojo/ControlTestHelper.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/dojo/ControlTestHelper.java
@@ -67,7 +67,7 @@ public class ControlTestHelper {
float tickDelta = context.tickCounter().getTickDelta(false);
//how long until net update
double updatePercent = (double) (System.currentTimeMillis() - lastUpdate) / 150;
- Vec3d aimPos = correctWitherSkeleton.getEyePos().add(pingOffset.multiply(updatePercent)).add(lastPingOffset.multiply(1 - updatePercent));
+ Vec3d aimPos = correctWitherSkeleton.getCameraPosVec(tickDelta).add(pingOffset.multiply(updatePercent)).add(lastPingOffset.multiply(1 - updatePercent));
Box targetBox = new Box(aimPos.add(-0.5, -0.5, -0.5), aimPos.add(0.5, 0.5, 0.5));
boolean playerLookingAtBox = targetBox.raycast(CLIENT.player.getCameraPosVec(tickDelta), CLIENT.player.getCameraPosVec(tickDelta).add(CLIENT.player.getRotationVec(tickDelta).multiply(30))).isPresent();
float[] boxColor = playerLookingAtBox ? Color.GREEN.getColorComponents(new float[]{0, 0, 0}) : Color.LIGHT_GRAY.getColorComponents(new float[]{0, 0, 0});
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/Reparty.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/Reparty.java
index 6165ac6a..80753c1d 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/Reparty.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/Reparty.java
@@ -1,94 +1,112 @@
package de.hysky.skyblocker.skyblock.dungeon;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.utils.Constants;
import de.hysky.skyblocker.utils.Utils;
import de.hysky.skyblocker.utils.chat.ChatFilterResult;
import de.hysky.skyblocker.utils.chat.ChatPatternListener;
import de.hysky.skyblocker.utils.scheduler.MessageScheduler;
import de.hysky.skyblocker.utils.scheduler.Scheduler;
+import net.azureaaron.hmapi.data.party.PartyRole;
+import net.azureaaron.hmapi.events.HypixelPacketEvents;
+import net.azureaaron.hmapi.network.HypixelNetworking;
+import net.azureaaron.hmapi.network.packet.s2c.ErrorS2CPacket;
+import net.azureaaron.hmapi.network.packet.s2c.HypixelS2CPacket;
+import net.azureaaron.hmapi.network.packet.v2.s2c.PartyInfoS2CPacket;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.text.Text;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+
+import org.slf4j.Logger;
+
+import com.mojang.brigadier.Command;
+import com.mojang.logging.LogUtils;
public class Reparty extends ChatPatternListener {
- private static final MinecraftClient client = MinecraftClient.getInstance();
- public static final Pattern PLAYER = Pattern.compile(" ([a-zA-Z0-9_]{2,16}) ●");
- private static final int BASE_DELAY = 10;
-
- private String[] players;
- private int playersSoFar;
- private boolean repartying;
- private String partyLeade