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.java2
-rw-r--r--src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java48
-rw-r--r--src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java1
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/CrimsonIsleCategory.java85
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java7
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java13
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/MessageFilterCategory.java8
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/HandledScreenMixin.java21
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/InGameHudMixin.java12
-rw-r--r--src/main/java/de/hysky/skyblocker/mixin/PlayerInventoryMixin.java21
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/ArrowPoisonWarning.java54
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java51
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/KuudraWaypoints.java161
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/filters/DicerFilter.java15
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/garden/VisitorHelper.java162
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/PosUtils.java9
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/Utils.java5
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/chat/ChatMessageListener.java3
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java4
19 files changed, 678 insertions, 4 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
index 6bdf619e..71623ea7 100644
--- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
+++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
@@ -5,6 +5,7 @@ import com.google.gson.GsonBuilder;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.debug.Debug;
import de.hysky.skyblocker.skyblock.*;
+import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra;
import de.hysky.skyblocker.skyblock.dungeon.*;
import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen;
import de.hysky.skyblocker.skyblock.dungeon.puzzle.CreeperBeams;
@@ -139,6 +140,7 @@ public class SkyblockerMod implements ClientModInitializer {
SecretsTracker.init();
ApiUtils.init();
Debug.init();
+ Kuudra.init();
RenderHelper.init();
containerSolverManager.init();
statusBarTracker.init();
diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
index 1bfd1b3c..175c3bdf 100644
--- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
+++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java
@@ -175,6 +175,9 @@ public class SkyblockerConfig {
public boolean dontStripSkinAlphaValues = true;
@SerialEntry
+ public boolean visitorHelper = true;
+
+ @SerialEntry
public TabHudConf tabHud = new TabHudConf();
@SerialEntry
@@ -637,6 +640,9 @@ public class SkyblockerConfig {
public Barn barn = new Barn();
@SerialEntry
+ public CrimsonIsle crimsonIsle = new CrimsonIsle();
+
+ @SerialEntry
public Dungeons dungeons = new Dungeons();
@SerialEntry
@@ -647,6 +653,9 @@ public class SkyblockerConfig {
@SerialEntry
public SpidersDen spidersDen = new SpidersDen();
+
+ @SerialEntry
+ public Garden garden = new Garden();
}
public static class Dungeons {
@@ -985,6 +994,37 @@ public class SkyblockerConfig {
public boolean solveTreasureHunter = true;
}
+ public static class CrimsonIsle {
+ @SerialEntry
+ public Kuudra kuudra = new Kuudra();
+ }
+
+ public static class Kuudra {
+ @SerialEntry
+ public boolean supplyWaypoints = true;
+
+ @SerialEntry
+ public boolean fuelWaypoints = true;
+
+ @SerialEntry
+ public Waypoint.Type suppliesAndFuelWaypointType = Waypoint.Type.WAYPOINT;
+
+ @SerialEntry
+ public boolean ballistaBuildWaypoints = true;
+
+ @SerialEntry
+ public boolean safeSpotWaypoints = true;
+
+ @SerialEntry
+ public boolean pearlWaypoints = true;
+
+ @SerialEntry
+ public boolean noArrowPoisonWarning = true;
+
+ @SerialEntry
+ public int arrowPoisonThreshold = 16;
+ }
+
public static class Rift {
@SerialEntry
public boolean mirrorverseWaypoints = true;
@@ -1015,6 +1055,11 @@ public class SkyblockerConfig {
public boolean highlightFoundRelics = true;
}
+ public static class Garden {
+ @SerialEntry
+ public boolean dicerTitlePrevent = true;
+ }
+
public static class Slayer {
@SerialEntry
public EndermanSlayer endermanSlayer = new EndermanSlayer();
@@ -1111,6 +1156,9 @@ public class SkyblockerConfig {
@SerialEntry
public boolean hideMana = false;
+
+ @SerialEntry
+ public ChatFilterResult hideDicer = ChatFilterResult.PASS;
}
public enum Info {
diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java
index 3a2601ad..70578822 100644
--- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java
+++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java
@@ -73,6 +73,7 @@ public class SkyblockerConfigManager {
.category(GeneralCategory.create(defaults, config))
.category(DungeonsCategory.create(defaults, config))
.category(DwarvenMinesCategory.create(defaults, config))
+ .category(CrimsonIsleCategory.create(defaults, config))
.category(LocationsCategory.create(defaults, config))
.category(SlayersCategory.create(defaults, config))
.category(QuickNavigationCategory.create(defaults, config))
diff --git a/src/main/java/de/hysky/skyblocker/config/categories/CrimsonIsleCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/CrimsonIsleCategory.java
new file mode 100644
index 00000000..3c2dc3b6
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/config/categories/CrimsonIsleCategory.java
@@ -0,0 +1,85 @@
+package de.hysky.skyblocker.config.categories;
+
+import de.hysky.skyblocker.config.ConfigUtils;
+import de.hysky.skyblocker.config.SkyblockerConfig;
+import de.hysky.skyblocker.utils.waypoint.Waypoint;
+import dev.isxander.yacl3.api.ConfigCategory;
+import dev.isxander.yacl3.api.Option;
+import dev.isxander.yacl3.api.OptionDescription;
+import dev.isxander.yacl3.api.OptionGroup;
+import dev.isxander.yacl3.api.controller.IntegerFieldControllerBuilder;
+import net.minecraft.text.Text;
+
+public class CrimsonIsleCategory {
+
+ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig config) {
+ return ConfigCategory.createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.category.crimsonIsle"))
+
+ //Kuudra
+ .group(OptionGroup.createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.crimsonIsle.kuudra"))
+ .collapsed(false)
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.crimsonIsle.kuudra.supplyWaypoints"))
+ .binding(defaults.locations.crimsonIsle.kuudra.supplyWaypoints,
+ () -> config.locations.crimsonIsle.kuudra.supplyWaypoints,
+ newValue -> config.locations.crimsonIsle.kuudra.supplyWaypoints = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.crimsonIsle.kuudra.fuelWaypoints"))
+ .binding(defaults.locations.crimsonIsle.kuudra.fuelWaypoints,
+ () -> config.locations.crimsonIsle.kuudra.fuelWaypoints,
+ newValue -> config.locations.crimsonIsle.kuudra.fuelWaypoints = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<Waypoint.Type>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.crimsonIsle.kuudra.suppliesAndFuelWaypointType"))
+ .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.general.waypoints.waypointType.@Tooltip")))
+ .binding(defaults.locations.crimsonIsle.kuudra.suppliesAndFuelWaypointType,
+ () -> config.locations.crimsonIsle.kuudra.suppliesAndFuelWaypointType,
+ newValue -> config.locations.crimsonIsle.kuudra.suppliesAndFuelWaypointType = newValue)
+ .controller(ConfigUtils::createEnumCyclingListController)
+ .build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.crimsonIsle.kuudra.ballistaBuildWaypoints"))
+ .binding(defaults.locations.crimsonIsle.kuudra.ballistaBuildWaypoints,
+ () -> config.locations.crimsonIsle.kuudra.ballistaBuildWaypoints,
+ newValue -> config.locations.crimsonIsle.kuudra.ballistaBuildWaypoints = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.crimsonIsle.kuudra.safeSpotWaypoints"))
+ .binding(defaults.locations.crimsonIsle.kuudra.safeSpotWaypoints,
+ () -> config.locations.crimsonIsle.kuudra.safeSpotWaypoints,
+ newValue -> config.locations.crimsonIsle.kuudra.safeSpotWaypoints = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.crimsonIsle.kuudra.pearlWaypoints"))
+ .binding(defaults.locations.crimsonIsle.kuudra.pearlWaypoints,
+ () -> config.locations.crimsonIsle.kuudra.pearlWaypoints,
+ newValue -> config.locations.crimsonIsle.kuudra.pearlWaypoints = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.crimsonIsle.kuudra.noArrowPoisonWarning"))
+ .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.crimsonIsle.kuudra.noArrowPoisonWarning.@Tooltip")))
+ .binding(defaults.locations.crimsonIsle.kuudra.noArrowPoisonWarning,
+ () -> config.locations.crimsonIsle.kuudra.noArrowPoisonWarning,
+ newValue -> config.locations.crimsonIsle.kuudra.noArrowPoisonWarning = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<Integer>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.crimsonIsle.kuudra.arrowPoisonThreshold"))
+ .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.locations.crimsonIsle.kuudra.arrowPoisonThreshold.@Tooltip")))
+ .binding(defaults.locations.crimsonIsle.kuudra.arrowPoisonThreshold,
+ () -> config.locations.crimsonIsle.kuudra.arrowPoisonThreshold,
+ newValue -> config.locations.crimsonIsle.kuudra.arrowPoisonThreshold = newValue)
+ .controller(IntegerFieldControllerBuilder::create)
+ .build())
+ .build())
+ .build();
+ }
+}
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 9c3b672f..bb333f79 100644
--- a/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java
+++ b/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java
@@ -78,6 +78,13 @@ public class GeneralCategory {
.controller(ConfigUtils::createBooleanController)
.flag(OptionFlag.ASSET_RELOAD)
.build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.general.visitorHelper"))
+ .binding(defaults.general.visitorHelper,
+ () -> config.general.visitorHelper,
+ newValue -> config.general.visitorHelper = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
//Tab Hud
.group(OptionGroup.createBuilder()
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 0b388d16..9bdcf2e9 100644
--- a/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java
+++ b/src/main/java/de/hysky/skyblocker/config/categories/LocationsCategory.java
@@ -98,6 +98,19 @@ public class LocationsCategory {
.controller(ConfigUtils::createBooleanController)
.build())
.build())
+
+ //Garden
+ .group(OptionGroup.createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.garden"))
+ .collapsed(false)
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.locations.garden.dicerTitlePrevent"))
+ .binding(defaults.locations.garden.dicerTitlePrevent,
+ () -> config.locations.garden.dicerTitlePrevent,
+ newValue -> config.locations.garden.dicerTitlePrevent = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .build())
.build();
}
}
diff --git a/src/main/java/de/hysky/skyblocker/config/categories/MessageFilterCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/MessageFilterCategory.java
index ce349049..acdc8169 100644
--- a/src/main/java/de/hysky/skyblocker/config/categories/MessageFilterCategory.java
+++ b/src/main/java/de/hysky/skyblocker/config/categories/MessageFilterCategory.java
@@ -118,6 +118,14 @@ public class MessageFilterCategory {
newValue -> config.messages.hideDeath = newValue)
.controller(ConfigUtils::createEnumCyclingListController)
.build())
+ .option(Option.<ChatFilterResult>createBuilder()
+ .name(Text.translatable("text.autoconfig.skyblocker.option.messages.hideDicer"))
+ .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.messages.hideDicer.@Tooltip")))
+ .binding(defaults.messages.hideDicer,
+ () -> config.messages.hideDicer,
+ newValue -> config.messages.hideDicer = newValue)
+ .controller(ConfigUtils::createEnumCyclingListController)
+ .build())
.build();
}
}
diff --git a/src/main/java/de/hysky/skyblocker/mixin/HandledScreenMixin.java b/src/main/java/de/hysky/skyblocker/mixin/HandledScreenMixin.java
index 71203381..8a1af570 100644
--- a/src/main/java/de/hysky/skyblocker/mixin/HandledScreenMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixin/HandledScreenMixin.java
@@ -7,6 +7,7 @@ import de.hysky.skyblocker.skyblock.experiment.ChronomatronSolver;
import de.hysky.skyblocker.skyblock.experiment.ExperimentSolver;
import de.hysky.skyblocker.skyblock.experiment.SuperpairsSolver;
import de.hysky.skyblocker.skyblock.experiment.UltrasequencerSolver;
+import de.hysky.skyblocker.skyblock.garden.VisitorHelper;
import de.hysky.skyblocker.skyblock.item.ItemProtection;
import de.hysky.skyblocker.skyblock.item.ItemRarityBackgrounds;
import de.hysky.skyblocker.skyblock.item.WikiLookup;
@@ -37,7 +38,6 @@ import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
-import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@@ -71,6 +71,20 @@ public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen
}
}
+ @Inject(at = @At("RETURN"), method = "render")
+ public void skyblocker$renderScreen(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) {
+ if (!Utils.isOnSkyblock()) return;
+
+ if (SkyblockerConfigManager.get().general.visitorHelper && (Utils.getLocationRaw().equals("garden") && !getTitle().getString().contains("Logbook") || getTitle().getString().startsWith("Bazaar")))
+ VisitorHelper.renderScreen(this.getTitle().getString(), context, textRenderer, handler, mouseX, mouseY);
+ }
+
+ @Inject(at = @At("HEAD"), method = "mouseClicked")
+ public void skyblocker$mouseClicked(double mouseX, double mouseY, int button, CallbackInfoReturnable<Boolean> cir) {
+ if (SkyblockerConfigManager.get().general.visitorHelper && (Utils.getLocationRaw().equals("garden") && !getTitle().getString().contains("Logbook") || getTitle().getString().startsWith("Bazaar")))
+ VisitorHelper.onMouseClicked(mouseX, mouseY, button, this.textRenderer);
+ }
+
@SuppressWarnings("DataFlowIssue")
// makes intellij be quiet about this.focusedSlot maybe being null. It's already null checked in mixined method.
@Inject(method = "drawMouseoverTooltip", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawTooltip(Lnet/minecraft/client/font/TextRenderer;Ljava/util/List;Ljava/util/Optional;II)V"), cancellable = true)
@@ -167,8 +181,11 @@ public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen
if (ItemProtection.isItemProtected(stack)) ci.cancel();
}
- //Prevent selling to NPC shops
+
if (this.client != null && this.handler instanceof GenericContainerScreenHandler genericContainerScreenHandler && genericContainerScreenHandler.getRows() == 6) {
+ VisitorHelper.onSlotClick(slot, slotId, this.getTitle().getString());
+
+ //Prevent selling to NPC shops
ItemStack sellItem = this.handler.slots.get(49).getStack();
if (sellItem.getName().getString().equals("Sell Item") || skyblocker$doesLoreContain(sellItem, this.client, "buyback")) {
diff --git a/src/main/java/de/hysky/skyblocker/mixin/InGameHudMixin.java b/src/main/java/de/hysky/skyblocker/mixin/InGameHudMixin.java
index c8f6f272..88be60cd 100644
--- a/src/main/java/de/hysky/skyblocker/mixin/InGameHudMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixin/InGameHudMixin.java
@@ -19,9 +19,11 @@ import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.hud.InGameHud;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
+import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import java.util.function.Supplier;
+import java.util.regex.Pattern;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
@@ -37,6 +39,9 @@ public abstract class InGameHudMixin {
@Unique
private static final Supplier<Identifier> SLOT_LOCK_ICON = () -> SkyblockerConfigManager.get().general.itemProtection.slotLockStyle.tex;
@Unique
+ private static final Pattern DICER_TITLE_BLACKLIST = Pattern.compile(".+? DROP!");
+
+ @Unique
private final FancyStatusBars statusBars = new FancyStatusBars();
@Shadow
@@ -101,4 +106,11 @@ public abstract class InGameHudMixin {
return cooldownProgress;
}
+
+ @Inject(method = "setTitle", at = @At("HEAD"), cancellable = true)
+ private void skyblocker$dicerTitlePrevent(Text title, CallbackInfo ci) {
+ if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().locations.garden.dicerTitlePrevent && title != null && DICER_TITLE_BLACKLIST.matcher(title.getString()).matches()) {
+ ci.cancel();
+ }
+ }
}
diff --git a/src/main/java/de/hysky/skyblocker/mixin/PlayerInventoryMixin.java b/src/main/java/de/hysky/skyblocker/mixin/PlayerInventoryMixin.java
new file mode 100644
index 00000000..4795a28b
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/mixin/PlayerInventoryMixin.java
@@ -0,0 +1,21 @@
+package de.hysky.skyblocker.mixin;
+
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+import de.hysky.skyblocker.skyblock.crimson.kuudra.ArrowPoisonWarning;
+import net.minecraft.entity.player.PlayerInventory;
+
+@Mixin(PlayerInventory.class)
+public class PlayerInventoryMixin {
+ @Shadow
+ public int selectedSlot;
+
+ @Inject(method = "scrollInHotbar", at = @At("TAIL"))
+ private void skyblocker$onHotbarScroll(CallbackInfo ci) {
+ ArrowPoisonWarning.tryWarn(selectedSlot);
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/ArrowPoisonWarning.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/ArrowPoisonWarning.java
new file mode 100644
index 00000000..7ddbeb99
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/ArrowPoisonWarning.java
@@ -0,0 +1,54 @@
+package de.hysky.skyblocker.skyblock.crimson.kuudra;
+
+import java.util.function.Supplier;
+
+import de.hysky.skyblocker.config.SkyblockerConfig;
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra.KuudraPhase;
+import de.hysky.skyblocker.utils.ItemUtils;
+import de.hysky.skyblocker.utils.Utils;
+import de.hysky.skyblocker.utils.render.RenderHelper;
+import de.hysky.skyblocker.utils.render.title.Title;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.entity.player.PlayerInventory;
+import net.minecraft.item.BowItem;
+import net.minecraft.item.ItemStack;
+import net.minecraft.text.Text;
+import net.minecraft.util.Formatting;
+
+public class ArrowPoisonWarning {
+ private static final Supplier<SkyblockerConfig.Kuudra> CONFIG = () -> SkyblockerConfigManager.get().locations.crimsonIsle.kuudra;
+ private static final int THREE_SECONDS = 20 * 3;
+ private static final Title NONE_TITLE = new Title(Text.translatable("skyblocker.crimson.kuudra.noArrowPoison").formatted(Formatting.GREEN));
+ private static final Title LOW_TITLE = new Title(Text.translatable("skyblocker.crimson.kuudra.lowArrowPoison").formatted(Formatting.GREEN));
+
+ public static void tryWarn(int newSlot) {
+ //Exclude skyblock menu
+ if (Utils.isInKuudra() && CONFIG.get().noArrowPoisonWarning && Kuudra.phase == KuudraPhase.DPS && newSlot != 8) {
+ MinecraftClient client = MinecraftClient.getInstance();
+ PlayerInventory inventory = client.player.getInventory();
+ ItemStack heldItem = inventory.getStack(newSlot);
+
+ if (heldItem.getItem() instanceof BowItem) {
+ boolean hasToxicArrowPoison = false;
+ int arrowPoisonAmount = 0;
+
+ for (int i = 0; i < inventory.size(); ++i) {
+ ItemStack stack = inventory.getStack(i);
+ String itemId = ItemUtils.getItemId(stack);
+
+ if (itemId.equals("TOXIC_ARROW_POISON")) {
+ hasToxicArrowPoison = true;
+ arrowPoisonAmount += stack.getCount();
+ }
+ }
+
+ if (!hasToxicArrowPoison) {
+ RenderHelper.displayInTitleContainerAndPlaySound(NONE_TITLE, THREE_SECONDS);
+ } else if (arrowPoisonAmount < CONFIG.get().arrowPoisonThreshold) {
+ RenderHelper.displayInTitleContainerAndPlaySound(LOW_TITLE, THREE_SECONDS);
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java
new file mode 100644
index 00000000..033a919d
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java
@@ -0,0 +1,51 @@
+package de.hysky.skyblocker.skyblock.crimson.kuudra;
+
+import de.hysky.skyblocker.utils.Utils;
+import de.hysky.skyblocker.utils.scheduler.Scheduler;
+import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
+import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents;
+import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
+import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
+import net.minecraft.text.Text;
+import net.minecraft.util.Formatting;
+
+public class Kuudra {
+ public static final String LOCATION = "kuudra";
+ static KuudraPhase phase = KuudraPhase.OTHER;
+
+ public static void init() {
+ WorldRenderEvents.AFTER_TRANSLUCENT.register(KuudraWaypoints::render);
+ ClientLifecycleEvents.CLIENT_STARTED.register(KuudraWaypoints::load);
+ ClientPlayConnectionEvents.JOIN.register((_handler, _sender, _client) -> reset());
+ ClientReceiveMessageEvents.GAME.register(Kuudra::onMessage);
+ Scheduler.INSTANCE.scheduleCyclic(KuudraWaypoints::tick, 20);
+ }
+
+ private static void onMessage(Text text, boolean overlay) {
+ if (Utils.isInKuudra() && !overlay) {
+ String message = Formatting.strip(text.getString());
+
+ if (message.equals("[NPC] Elle: ARGH! All of the supplies fell into the lava! You need to retrieve them quickly!")) {
+ phase = KuudraPhase.RETRIEVE_SUPPLIES;
+ }
+
+ if (message.equals("[NPC] Elle: Phew! The Ballista is finally ready! It should be strong enough to tank Kuudra's blows now!")) {
+ phase = KuudraPhase.DPS;
+ }
+
+ if (message.equals("[NPC] Elle: POW! SURELY THAT'S IT! I don't think he has any more in him!")) {
+ phase = KuudraPhase.OTHER;
+ }
+ }
+ }
+
+ private static void reset() {
+ phase = KuudraPhase.OTHER;
+ }
+
+ enum KuudraPhase {
+ OTHER,
+ RETRIEVE_SUPPLIES,
+ DPS;
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/KuudraWaypoints.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/KuudraWaypoints.java
new file mode 100644
index 00000000..790d434a
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/KuudraWaypoints.java
@@ -0,0 +1,161 @@
+package de.hysky.skyblocker.skyblock.crimson.kuudra;
+
+import java.io.BufferedReader;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import org.slf4j.Logger;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import com.mojang.logging.LogUtils;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.JsonOps;
+
+import de.hysky.skyblocker.SkyblockerMod;
+import de.hysky.skyblocker.config.SkyblockerConfig;
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.utils.PosUtils;
+import de.hysky.skyblocker.utils.Utils;
+import de.hysky.skyblocker.utils.waypoint.Waypoint;
+import de.hysky.skyblocker.utils.waypoint.Waypoint.Type;
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.entity.decoration.ArmorStandEntity;
+import net.minecraft.entity.mob.GiantEntity;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Box;
+import net.minecraft.util.math.MathHelper;
+
+public class KuudraWaypoints {
+ private static final Logger LOGGER = LogUtils.getLogger();
+ private static final float[] SUPPLIES_COLOR = { 255f / 255f, 0f, 0f };
+ private static final float[] PEARL_COLOR = { 57f / 255f, 117f / 255f, 125f / 255f };
+ private static final float[] SAFE_SPOT_COLOR = { 255f / 255f, 85f / 255f, 255f / 255f };
+ private static final Supplier<Type> SUPPLIES_AND_FUEL_TYPE = () -> SkyblockerConfigManager.get().locations.crimsonIsle.kuudra.suppliesAndFuelWaypointType;
+ private static final ObjectArrayList<Waypoint> SAFE_SPOT_WAYPOINTS = new ObjectArrayList<>();
+ private static final ObjectArrayList<Waypoint> PEARL_WAYPOINTS = new ObjectArrayList<>();
+ private static final Function<float[], Codec<List<Waypoint>>> CODEC = cc -> PosUtils.ALT_BLOCK_POS_CODEC.xmap(
+ pos -> new Waypoint(pos, () -> Waypoint.Type.HIGHLIGHT, cc, false),
+ waypoint -> waypoint.pos)
+ .listOf();
+
+ //Use non final lists and swap them out to avoid ConcurrentModificationExceptions
+ private static ObjectArrayList<Waypoint> supplyWaypoints = ObjectArrayList.of();
+ private static ObjectArrayList<Waypoint> ballistaBuildWaypoints = ObjectArrayList.of();
+ private static ObjectArrayList<Waypoint> fuelWaypoints = ObjectArrayList.of();
+ private static boolean loaded;
+
+ static void load(MinecraftClient client) {
+ CompletableFuture<Void> safeSpots = loadWaypoints(client, new Identifier(SkyblockerMod.NAMESPACE, "crimson/kuudra/safe_spot_waypoints.json"), SAFE_SPOT_WAYPOINTS, SAFE_SPOT_COLOR);
+ CompletableFuture<Void> pearls = loadWaypoints(client, new Identifier(SkyblockerMod.NAMESPACE, "crimson/kuudra/pearl_waypoints.json"), PEARL_WAYPOINTS, PEARL_COLOR);
+
+ CompletableFuture.allOf(safeSpots, pearls).whenComplete((_result, _throwable) -> loaded = true);
+ }
+
+ private static CompletableFuture<Void> loadWaypoints(MinecraftClient client, Identifier file, ObjectArrayList<Waypoint> list, float[] colorComponents) {
+ return CompletableFuture.supplyAsync(() -> {
+ try (BufferedReader reader = client.getResourceManager().openAsReader(file)) {
+ return CODEC.apply(colorComponents).parse(JsonOps.INSTANCE, getWaypoints(reader)).result().orElseThrow();
+ } catch (Exception e) {
+ LOGGER.error("[Skyblocker Kuudra Waypoints] Failed to load kuudra waypoints from: {}", file, e);
+
+ return List.<Waypoint>of();
+ }
+ }).thenAccept(list::addAll);
+ }
+
+ private static JsonElement getWaypoints(BufferedReader reader) {
+ return JsonParser.parseReader(reader).getAsJsonObject().getAsJsonArray("waypoints");
+ }
+
+ static void tick() {
+ MinecraftClient client = MinecraftClient.getInstance();
+ SkyblockerConfig.Kuudra config = SkyblockerConfigManager.get().locations.crimsonIsle.kuudra;
+
+ if (Utils.isInKuudra() && (config.supplyWaypoints || config.fuelWaypoints || config.ballistaBuildWaypoints)) {
+ Box searchBox = client.player.getBoundingBox().expand(500d);
+ ObjectArrayList<Waypoint> supplies = new ObjectArrayList<>();
+ ObjectArrayList<Waypoint> fuelCells = new ObjectArrayList<>();
+
+ if (config.supplyWaypoints || config.fuelWaypoints) {
+ List<GiantEntity> giants = client.world.getEntitiesByClass(GiantEntity.class, searchBox, giant -> giant.getY() < 67);
+
+ for (GiantEntity giant : giants) {
+ double yawOffset = giant.getYaw() + 115;
+
+ double x = giant.getX() + 4.5 * Math.cos((yawOffset) * MathHelper.RADIANS_PER_DEGREE);
+ double y = 75;
+ double z = giant.getZ() + 4.5 * Math.sin((yawOffset) * MathHelper.RADIANS_PER_DEGREE);
+
+ Waypoint waypoint = new Waypoint(BlockPos.ofFloored(x, y, z), SUPPLIES_AND_FUEL_TYPE, SUPPLIES_COLOR, false);
+
+ switch (Kuudra.phase) {
+ case RETRIEVE_SUPPLIES -> supplies.add(waypoint);
+ case DPS -> fuelCells.add(waypoint);
+ default -> supplies.add(waypoint);
+ }
+ }
+ }
+
+ ObjectArrayList<Waypoint> ballistaBuildSpots = new ObjectArrayList<>();
+
+ if (config.ballistaBuildWaypoints) {
+ List<ArmorStandEntity> armorStands = client.world.getEntitiesByClass(ArmorStandEntity.class, searchBox, ArmorStandEntity::hasCustomName);
+
+ for (ArmorStandEntity armorStand : armorStands) {
+ String name = armorStand.getName().getString();
+
+ if (config.ballistaBuildWaypoints && name.contains("SNEAK + PUNCH")) {
+ ballistaBuildSpots.add(new Waypoint(armorStand.getBlockPos(), () -> Waypoint.Type.WAYPOINT, SUPPLIES_COLOR, false));
+ }
+ }
+ }
+
+ supplyWaypoints = supplies;
+ ballistaBuildWaypoints = ballistaBuildSpots;
+ fuelWaypoints = fuelCells;
+ }
+ }
+
+ static void render(WorldRenderContext context) {
+ SkyblockerConfig.Kuudra config = SkyblockerConfigManager.get().locations.crimsonIsle.kuudra;
+
+ if (Utils.isInKuudra() && loaded) {
+ if (config.supplyWaypoints) {
+ for (Waypoint waypoint : supplyWaypoints) {
+ waypoint.render(context);
+ }
+ }
+
+ if (config.ballistaBuildWaypoints) {
+ for (Waypoint waypoint : ballistaBuildWaypoints) {
+ waypoint.render(context);
+ }
+ }
+
+ if (config.fuelWaypoints) {
+ for (Waypoint waypoint : fuelWaypoints) {
+ waypoint.render(context);
+ }
+ }
+
+ if (config.safeSpotWaypoints) {
+ for (Waypoint waypoint : SAFE_SPOT_WAYPOINTS) {
+ waypoint.render(context);
+ }
+ }
+
+ //TODO maybe have "dynamic" waypoints that draw a line to the actual spot
+ if (config.pearlWaypoints) {
+ for (Waypoint waypoint : PEARL_WAYPOINTS) {
+ waypoint.render(context);
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/filters/DicerFilter.java b/src/main/java/de/hysky/skyblocker/skyblock/filters/DicerFilter.java
new file mode 100644
index 00000000..a3f78684
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/filters/DicerFilter.java
@@ -0,0 +1,15 @@
+package de.hysky.skyblocker.skyblock.filters;
+
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.utils.chat.ChatFilterResult;
+
+public class DicerFilter extends SimpleChatFilter {
+ public DicerFilter() {
+ super("[A-Z]+ DROP! .*Dicer dropped [0-9]+x.+!$");
+ }
+
+ @Override
+ public ChatFilterResult state() {
+ return SkyblockerConfigManager.get().messages.hideDicer;
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/garden/VisitorHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/garden/VisitorHelper.java
new file mode 100644
index 00000000..3c049f69
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/garden/VisitorHelper.java
@@ -0,0 +1,162 @@
+package de.hysky.skyblocker.skyblock.garden;
+
+import de.hysky.skyblocker.skyblock.itemlist.ItemRepository;
+import de.hysky.skyblocker.utils.NEURepoManager;
+import de.hysky.skyblocker.utils.scheduler.MessageScheduler;
+import io.github.moulberry.repo.data.NEUItem;
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
+import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
+import net.minecraft.client.font.TextRenderer;
+import net.minecraft.client.gui.DrawContext;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NbtCompound;
+import net.minecraft.nbt.NbtElement;
+import net.minecraft.nbt.NbtList;
+import net.minecraft.screen.ScreenHandler;
+import net.minecraft.screen.slot.Slot;
+import net.minecraft.text.Text;
+import net.minecraft.text.Text.Serialization;
+import net.minecraft.util.Formatting;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.text.NumberFormat;
+import java.util.HashMap;
+import java.util.Map;
+
+//TODO: check inventory items, sum all repeated items into one
+public class VisitorHelper {
+ private static final Logger LOGGER = LoggerFactory.getLogger("Skyblocker Visitor Helper");
+
+ private static final Map<String, Object2IntMap<String>> itemMap = new HashMap<>();
+ private static final Map<String, ItemStack> itemCache = new HashMap<>();
+ private static final int TEXT_START_X = 4;
+ private static final int TEXT_START_Y = 4;
+ private static final int LINE_SPACING = 3;
+
+ public static void renderScreen(String title, DrawContext context, TextRenderer textRenderer, ScreenHandler handler, int mouseX, int mouseY) {
+ if (handler.getCursorStack() == ItemStack.EMPTY)
+ processVisitorItem(title, handler);
+ drawScreenItems(context, textRenderer, mouseX, mouseY);
+ }
+
+ public static void onMouseClicked(double mouseX, double mouseY, int mouseButton, TextRenderer textRenderer) {
+ int yPosition = TEXT_START_Y;
+
+ for (Map.Entry<String, Object2IntMap<String>> visitorEntry : itemMap.entrySet()) {
+ int textWidth;
+ int textHeight = textRenderer.fontHeight;
+
+ yPosition += LINE_SPACING + textHeight;
+
+ for (Object2IntMap.Entry<String> itemEntry : visitorEntry.getValue().object2IntEntrySet()) {
+ String itemText = itemEntry.getKey();
+ textWidth = textRenderer.getWidth(itemText);
+
+ if (isMouseOverText(mouseX, mouseY, TEXT_START_X, yPosition, textWidth, textHeight)) {
+ MessageScheduler.INSTANCE.sendMessageAfterCooldown("/bz " + itemText);
+ return;
+ }
+ yPosition += LINE_SPACING + textHeight;
+ }
+ }
+ }
+
+ public static void onSlotClick(Slot slot, int slotId, String title) {
+ if (slotId == 29 || slotId == 13) {
+ itemMap.remove(title);
+ }
+ }
+
+ private static void processVisitorItem(String visitorName, ScreenHandler handler) {
+ ItemStack visitorItem = handler.getSlot(13).getStack();
+ if (visitorItem == null || !visitorItem.hasNbt() || !visitorItem.getNbt().asString().contains("Times Visited")) return;
+ ItemStack acceptButton = handler.getSlot(29).getStack();
+ if (acceptButton == null) return;
+ NbtCompound acceptButtonNbt = acceptButton.getSubNbt("display");
+ if (acceptButtonNbt == null || !acceptButtonNbt.contains("Lore", NbtElement.LIST_TYPE)) return;
+ processLore(visitorName, acceptButtonNbt.getList("Lore", NbtElement.STRING_TYPE));
+ }
+
+ private static void processLore(String visitorName, NbtList loreList) {
+ boolean saveRequiredItems = false;
+ for (int i = 0; i < loreList.size(); i++) {
+ String lore = loreList.getString(i);
+ if (lore.contains("Items Required"))
+ saveRequiredItems = true;
+ else if (lore.contains("Rewards"))
+ break;
+ else if (saveRequiredItems)
+ updateItemMap(visitorName, lore);
+ }
+ }
+
+ private static void updateItemMap(String visitorName, String lore) {
+ Text itemText = Serialization.fromJson(lore);
+ String[] splitItemText = itemText.getString().split(" x");
+ String itemName = splitItemText[0].trim();
+ if (itemName.isEmpty()) return;
+ try {
+ int amount = splitItemText.length == 2 ? NumberFormat.getInstance().parse(splitItemText[1].trim()).intValue() : 1;
+ Object2IntMap<String> visitorMap = itemMap.getOrDefault(visitorName, new Object2IntOpenHashMap<>());
+ visitorMap.putIfAbsent(itemName, amount);
+ itemMap.putIfAbsent(visitorName, visitorMap);
+ } catch (Exception e) {
+ LOGGER.error("[Skyblocker Visitor Helper] Failed to parse item: " + itemText.getString(), e);
+ }
+ }
+
+ private static void drawScreenItems(DrawContext context, TextRenderer textRenderer, int mouseX, int mouseY) {
+ int index = 0;
+ for (Map.Entry<String, Object2IntMap<String>> visitorEntry : itemMap.entrySet()) {
+ String visitorName = visitorEntry.getKey();
+ drawTextWithOptionalUnderline(context, textRenderer, Text.literal(visitorName), TEXT_START_X, TEXT_START_Y + index * (LINE_SPACING + textRenderer.fontHeight), mouseX, mouseY);
+ index++;
+
+ for (Object2IntMap.Entry<String> itemEntry : visitorEntry.getValue().object2IntEntrySet()) {
+ index = drawItemEntryWithHover(context, textRenderer, itemEntry, index, mouseX, mouseY);
+ }
+ }
+ }
+
+ private static int drawItemEntryWithHover(DrawContext context, TextRenderer textRenderer, Map.Entry<String, Integer> itemEntry, int index, int mouseX, int mouseY) {
+ String itemName = itemEntry.getKey();
+ int amount = itemEntry.getValue();
+ ItemStack stack = getCachedItem(itemName);
+ if (stack != null) {
+ drawItemEntryWithHover(context, textRenderer, stack, amount, index, mouseX, mouseY);
+ }
+ return index + 1;
+ }
+
+ private static ItemStack getCachedItem(String displayName) {
+ String strippedName = Formatting.strip(displayName);
+ ItemStack cachedStack = itemCache.get(strippedName);
+ if (cachedStack != null) return cachedStack;
+ NEUItem neuItem = NEURepoManager.NEU_REPO.getItems().getItems().values().stream()
+ .filter(i -> Formatting.strip(i.getDisplayName()).equals(strippedName))
+ .findFirst()
+ .orElse(null);
+ if (neuItem == null) return null;
+ ItemStack stack = ItemRepository.getItemStack(neuItem.getSkyblockItemId());
+ itemCache.put(strippedName, stack);
+ return stack;
+ }
+
+ private static void drawItemEntryWithHover(DrawContext context, TextRenderer textRenderer, ItemStack stack, int amount, int index, int mouseX, int mousseY) {
+ Text text = Serialization.fromJson(stack.getSubNbt("display").getString("Name")).append(" x" + amount);
+ drawTextWithOptionalUnderline(context, textRenderer, text, TEXT_START_X + 8, TEXT_START_Y + (index * (LINE_SPACING + textRenderer.fontHeight)), mouseX, mousseY);
+ context.drawItem(stack, TEXT_START_X + 10 + textRenderer.getWidth(text), TEXT_START_Y + (index * (LINE_SPACING + textRenderer.fontHeight)) - textRenderer.fontHeight + 5);
+ }
+
+ private static void drawTextWithOptionalUnderline(DrawContext context, TextRenderer textRenderer, Text text, int x, int y, int mouseX, int mouseY) {
+ context.drawText(textRenderer, text, x, y, -1, true);
+ if (isMouseOverText(mouseX, mouseY, x, y, textRenderer.getWidth(text), textRenderer.fontHeight)) {
+ context.drawHorizontalLine(x, x + textRenderer.getWidth(text), y + textRenderer.fontHeight, -1);
+ }
+ }
+
+ private static boolean isMouseOverText(double mouseX, double mouseY, int x, int y, int width, int height) {
+ return mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height;
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/utils/PosUtils.java b/src/main/java/de/hysky/skyblocker/utils/PosUtils.java
index 6a34b060..73ada889 100644
--- a/src/main/java/de/hysky/skyblocker/utils/PosUtils.java
+++ b/src/main/java/de/hysky/skyblocker/utils/PosUtils.java
@@ -1,8 +1,17 @@
package de.hysky.skyblocker.utils;
+import com.mojang.serialization.Codec;
+import com.mojang.serialization.codecs.RecordCodecBuilder;
+
import net.minecraft.util.math.BlockPos;
public final class PosUtils {
+ public static final Codec<BlockPos> ALT_BLOCK_POS_CODEC = RecordCodecBuilder.create(instance -> instance.group(
+ Codec.INT.fieldOf("x").forGetter(BlockPos::getX),
+ Codec.INT.fieldOf("y").forGetter(BlockPos::getY),
+ Codec.INT.fieldOf("z").forGetter(BlockPos::getZ))
+ .apply(instance, BlockPos::new));
+
public static BlockPos parsePosString(String posData) {
String[] posArray = posData.split(",");
return new BlockPos(Integer.parseInt(posArray[0]), Integer.parseInt(posArray[1]), Integer.parseInt(posArray[2]));
diff --git a/src/main/java/de/hysky/skyblocker/utils/Utils.java b/src/main/java/de/hysky/skyblocker/utils/Utils.java
index 0c95985e..cd739a0c 100644
--- a/src/main/java/de/hysky/skyblocker/utils/Utils.java
+++ b/src/main/java/de/hysky/skyblocker/utils/Utils.java
@@ -3,6 +3,7 @@ package de.hysky.skyblocker.utils;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import de.hysky.skyblocker.events.SkyblockEvents;
+import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra;
import de.hysky.skyblocker.skyblock.item.MuseumItemCache;
import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip;
import de.hysky.skyblocker.skyblock.rift.TheRift;
@@ -110,6 +111,10 @@ public class Utils {
return getLocationRaw().equals("combat_3");
}
+ public static boolean isInKuudra() {
+ return getLocationRaw().equals(Kuudra.LOCATION);
+ }
+
public static boolean isInjected() {
return isInjected;
}
diff --git a/src/main/java/de/hysky/skyblocker/utils/chat/ChatMessageListener.java b/src/main/java/de/hysky/skyblocker/utils/chat/ChatMessageListener.java
index ee43bc4c..bdff2d94 100644
--- a/src/main/java/de/hysky/skyblocker/utils/chat/ChatMessageListener.java
+++ b/src/main/java/de/hysky/skyblocker/utils/chat/ChatMessageListener.java
@@ -56,7 +56,8 @@ public interface ChatMessageListener {
new ShowOffFilter(),
new ToggleSkyMallFilter(),
new MimicFilter(),
- new DeathFilter()
+ new DeathFilter(),
+ new DicerFilter()
};
// Register all listeners to EVENT
for (ChatMessageListener listener : listeners) {
diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java
index 2f9c9f63..7f3d4eda 100644
--- a/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java
+++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java
@@ -1,13 +1,14 @@
package de.hysky.skyblocker.utils.waypoint;
import de.hysky.skyblocker.utils.render.RenderHelper;
+import de.hysky.skyblocker.utils.render.Renderable;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import java.util.function.Supplier;
-public class Waypoint {
+public class Waypoint implements Renderable {
protected static final float DEFAULT_HIGHLIGHT_ALPHA = 0.5f;
protected static final float DEFAULT_LINE_WIDTH = 5f;
public final BlockPos pos;
@@ -74,6 +75,7 @@ public class Waypoint {
return colorComponents;
}
+ @Override
public void render(WorldRenderContext context) {
switch (typeSupplier.get()) {
case WAYPOINT -> RenderHelper.renderFilledWithBeaconBeam(context, pos, getColorComponents(), alpha, throughWalls);