aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/de/hysky/skyblocker/SkyblockerMod.java3
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java22
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java32
-rw-r--r--src/main/java/de/hysky/skyblocker/config/configs/GeneralConfig.java8
-rw-r--r--src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java10
-rw-r--r--src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java2
-rw-r--r--src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java33
-rw-r--r--src/main/java/de/hysky/skyblocker/mixins/PlayerListHudMixin.java8
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/accessories/newyearcakes/NewYearCakeBagHelper.java8
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/accessories/newyearcakes/NewYearCakesHelper.java10
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/bazaar/BazaarHelper.java20
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/bazaar/ReorderHelper.java39
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java306
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusHelper.java9
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusProfit.java15
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/ColorTerminal.java15
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/LightsOnTerminal.java14
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/OrderTerminal.java18
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/StartsWithTerminal.java15
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/TerminalSolver.java1
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dwarven/CommissionHighlight.java9
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHud.java22
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationsManager.java252
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsWaypoint.java98
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dwarven/MetalDetector.java9
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dwarven/MiningLocationLabel.java53
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dwarven/WishingCompassSolver.java389
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/experiment/ChronomatronSolver.java5
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/experiment/ExperimentSolver.java16
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/experiment/SuperpairsSolver.java8
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/experiment/UltrasequencerSolver.java5
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SimpleSlotTextAdder.java39
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextAdder.java58
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextManager.java83
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextMode.java23
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/TextPosition.java3
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/AttributeShardAdder.java9
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/CatacombsLevelAdder.java27
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/CollectionAdder.java8
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/CommunityShopAdder.java41
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/EnchantmentLevelAdder.java15
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/EssenceShopAdder.java9
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/MinionLevelAdder.java13
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PetLevelAdder.java14
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PotionLevelAdder.java10
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PowerStonesGuideAdder.java18
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PrehistoricEggAdder.java19
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/RancherBootsSpeedAdder.java13
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/SkillLevelAdder.java12
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/SkyblockLevelAdder.java12
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/StatsTuningAdder.java9
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/YourEssenceAdder.java8
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/BackpackPreview.java7
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/SimpleTooltipAdder.java57
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipAdder.java46
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java10
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipManager.java11
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/AccessoryTooltip.java11
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/AvgBinTooltip.java63
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/BazaarPriceTooltip.java11
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ColorTooltip.java11
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/CraftPriceTooltip.java12
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/DungeonQualityTooltip.java12
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/EssenceShopPrice.java11
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/LBinTooltip.java11
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/LineSmoothener.java9
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MotesTooltip.java11
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MuseumTooltip.java11
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/NpcPriceTooltip.java11
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java22
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/SupercraftReminder.java9
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/PlayerListMgr.java71
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/Utils.java11
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/container/ContainerMatcher.java20
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/container/ContainerSolver.java38
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/container/ContainerSolverManager.java154
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/container/RegexContainerMatcher.java68
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/container/SimpleContainerSolver.java38
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/container/SlotTextAdder.java30
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/container/TooltipAdder.java18
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/render/gui/AbstractContainerMatcher.java29
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolver.java52
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolverManager.java157
-rw-r--r--src/main/resources/assets/skyblocker/lang/en_us.json27
-rw-r--r--src/test/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationManagerTest.java31
-rw-r--r--src/test/java/de/hysky/skyblocker/skyblock/dwarven/WishingCompassSolverTest.java43
86 files changed, 1951 insertions, 1079 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
index 08b0915a..9d5f2b0f 100644
--- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
+++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
@@ -54,7 +54,7 @@ import de.hysky.skyblocker.utils.chat.ChatMessageListener;
import de.hysky.skyblocker.utils.discord.DiscordRPCManager;
import de.hysky.skyblocker.utils.render.RenderHelper;
import de.hysky.skyblocker.utils.render.culling.OcclusionCulling;
-import de.hysky.skyblocker.utils.render.gui.ContainerSolverManager;
+import de.hysky.skyblocker.utils.container.ContainerSolverManager;
import de.hysky.skyblocker.utils.render.title.TitleContainer;
import de.hysky.skyblocker.utils.scheduler.MessageScheduler;
import de.hysky.skyblocker.utils.scheduler.Scheduler;
@@ -132,6 +132,7 @@ public class SkyblockerMod implements ClientModInitializer {
FarmingHud.init();
LowerSensitivity.init();
CrystalsLocationsManager.init();
+ WishingCompassSolver.init();
MetalDetector.init();
ChatMessageListener.init();
Shortcuts.init();
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 ab674b18..7669359e 100644
--- a/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java
+++ b/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java
@@ -5,10 +5,12 @@ import de.hysky.skyblocker.config.ConfigUtils;
import de.hysky.skyblocker.config.SkyblockerConfig;
import de.hysky.skyblocker.config.configs.GeneralConfig;
import de.hysky.skyblocker.skyblock.item.tooltip.adders.CraftPriceTooltip;
+import de.hysky.skyblocker.skyblock.item.slottext.SlotTextMode;
import de.hysky.skyblocker.skyblock.shortcut.ShortcutsConfigScreen;
import dev.isxander.yacl3.api.*;
import dev.isxander.yacl3.api.controller.FloatSliderControllerBuilder;
import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.gui.screen.option.KeybindsScreen;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
@@ -234,13 +236,18 @@ public class GeneralCategory {
.group(OptionGroup.createBuilder()
.name(Text.translatable("skyblocker.config.general.itemInfoDisplay"))
.collapsed(true)
- .option(Option.<Boolean>createBuilder()
+ .option(Option.<SlotTextMode>createBuilder()
.name(Text.translatable("skyblocker.config.general.itemInfoDisplay.slotText"))
.description(OptionDescription.of(Text.translatable("skyblocker.config.general.itemInfoDisplay.slotText.@Tooltip")))
- .binding(defaults.general.itemInfoDisplay.slotText,
- () -> config.general.itemInfoDisplay.slotText,
- newValue -> config.general.itemInfoDisplay.slotText = newValue)
- .controller(ConfigUtils::createBooleanController)
+ .binding(defaults.general.itemInfoDisplay.slotTextMode,
+ () -> config.general.itemInfoDisplay.slotTextMode,
+ newValue -> config.general.itemInfoDisplay.slotTextMode = newValue)
+ .controller(ConfigUtils::createEnumCyclingListController)
+ .build())
+ .option(ButtonOption.createBuilder()
+ .name(Text.translatable("skyblocker.config.shortcutToKeybindsSettings"))
+ .action((screen, opt) -> MinecraftClient.getInstance().setScreen(new KeybindsScreen(screen, MinecraftClient.getInstance().options)))
+ .text(Text.translatable("skyblocker.config.shortcutToKeybindsSettings.@Text"))
.build())
.option(Option.<Boolean>createBuilder()
.name(Text.translatable("skyblocker.config.general.itemInfoDisplay.attributeShardInfo"))
@@ -301,6 +308,11 @@ public class GeneralCategory {
newValue -> config.general.wikiLookup.enableWikiLookup = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
+ .option(ButtonOption.createBuilder()
+ .name(Text.translatable("skyblocker.config.shortcutToKeybindsSettings"))
+ .action((screen, opt) -> MinecraftClient.getInstance().setScreen(new KeybindsScreen(screen, MinecraftClient.getInstance().options)))
+ .text(Text.translatable("skyblocker.config.shortcutToKeybindsSettings.@Text"))
+ .build())
.option(Option.<Boolean>createBuilder()
.name(Text.translatable("skyblocker.config.general.wikiLookup.officialWiki"))
.description(OptionDescription.of(Text.translatable("skyblocker.config.general.wikiLookup.officialWiki.@Tooltip")))
diff --git a/src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java
index 4e11d869..796a6105 100644
--- a/src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java
+++ b/src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java
@@ -166,6 +166,14 @@ public class MiningCategory {
newValue -> config.mining.crystalsWaypoints.enabled = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
+ .option(Option.<Float>createBuilder()
+ .name(Text.translatable("skyblocker.config.mining.crystalsWaypoints.textScale"))
+ .description(OptionDescription.of(Text.translatable("skyblocker.config.mining.crystalsWaypoints.textScale.@Tooltip")))
+ .binding(defaults.mining.crystalsWaypoints.textScale,
+ () -> config.mining.crystalsWaypoints.textScale,
+ newValue -> config.mining.crystalsWaypoints.textScale = newValue)
+ .controller(FloatFieldControllerBuilder::create)
+ .build())
.option(Option.<Boolean>createBuilder()
.name(Text.translatable("skyblocker.config.mining.crystalsWaypoints.findInChat"))
.description(OptionDescription.of(Text.translatable("skyblocker.config.mining.crystalsWaypoints.findInChat.@Tooltip")))
@@ -174,6 +182,14 @@ public class MiningCategory {
newValue -> config.mining.crystalsWaypoints.findInChat = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver"))
+ .description(OptionDescription.of(Text.translatable("skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.@Tooltip")))
+ .binding(defaults.mining.crystalsWaypoints.wishingCompassSolver,
+ () -> config.mining.crystalsWaypoints.wishingCompassSolver,
+ newValue -> config.mining.crystalsWaypoints.wishingCompassSolver = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
.build())
@@ -193,14 +209,6 @@ public class MiningCategory {
newValue -> config.mining.commissionWaypoints.mode = newValue)
.controller(ConfigUtils::createEnumCyclingListController)
.build())
- .option(Option.<Boolean>createBuilder()
- .name(Text.translatable("skyblocker.config.mining.commissionWaypoints.useColor"))
- .description(OptionDescription.of(Text.translatable("skyblocker.config.mining.commissionWaypoints.useColor.@Tooltip")))
- .binding(defaults.mining.commissionWaypoints.useColor,
- () -> config.mining.commissionWaypoints.useColor,
- newValue -> config.mining.commissionWaypoints.useColor = newValue)
- .controller(ConfigUtils::createBooleanController)
- .build())
.option(Option.<Float>createBuilder()
.name(Text.translatable("skyblocker.config.mining.commissionWaypoints.textScale"))
.description(OptionDescription.of(Text.translatable("skyblocker.config.mining.commissionWaypoints.textScale.@Tooltip")))
@@ -210,6 +218,14 @@ public class MiningCategory {
.controller(FloatFieldControllerBuilder::create)
.build())
.option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("skyblocker.config.mining.commissionWaypoints.useColor"))
+ .description(OptionDescription.of(Text.translatable("skyblocker.config.mining.commissionWaypoints.useColor.@Tooltip")))
+ .binding(defaults.mining.commissionWaypoints.useColor,
+ () -> config.mining.commissionWaypoints.useColor,
+ newValue -> config.mining.commissionWaypoints.useColor = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<Boolean>createBuilder()
.name(Text.translatable("skyblocker.config.mining.commissionWaypoints.showBaseCamp"))
.description(OptionDescription.of(Text.translatable("skyblocker.config.mining.commissionWaypoints.showBaseCamp.@Tooltip")))
.binding(defaults.mining.commissionWaypoints.showBaseCamp,
diff --git a/src/main/java/de/hysky/skyblocker/config/configs/GeneralConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/GeneralConfig.java
index 691e6f79..61386452 100644
--- a/src/main/java/de/hysky/skyblocker/config/configs/GeneralConfig.java
+++ b/src/main/java/de/hysky/skyblocker/config/configs/GeneralConfig.java
@@ -3,6 +3,7 @@ package de.hysky.skyblocker.config.configs;
import de.hysky.skyblocker.SkyblockerMod;
import de.hysky.skyblocker.skyblock.item.CustomArmorAnimatedDyes;
import de.hysky.skyblocker.skyblock.item.CustomArmorTrims;
+import de.hysky.skyblocker.skyblock.item.slottext.SlotTextMode;
import dev.isxander.yacl3.config.v2.api.SerialEntry;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
@@ -163,10 +164,17 @@ public class GeneralConfig {
}
public static class ItemInfoDisplay {
+ @Deprecated
@SerialEntry
public boolean slotText = true;
@SerialEntry
+ public SlotTextMode slotTextMode = SlotTextMode.ENABLED;
+
+ @SerialEntry
+ public boolean slotTextToggled = true;
+
+ @SerialEntry
public boolean attributeShardInfo = true;
@SerialEntry
diff --git a/src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java
index d71f57b6..dcf70f24 100644
--- a/src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java
+++ b/src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java
@@ -94,7 +94,13 @@ public class MiningConfig {
public boolean enabled = true;
@SerialEntry
+ public float textScale = 1;
+
+ @SerialEntry
public boolean findInChat = true;
+
+ @SerialEntry
+ public boolean wishingCompassSolver = true;
}
public static class CommissionWaypoints {
@@ -102,10 +108,10 @@ public class MiningConfig {
public CommissionWaypointMode mode = CommissionWaypointMode.BOTH;
@SerialEntry
- public boolean useColor = true;
+ public float textScale = 1;
@SerialEntry
- public float textScale = 1;
+ public boolean useColor = true;
@SerialEntry
public boolean showBaseCamp = false;
diff --git a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java
index 7bbbac81..c0cd8b7b 100644
--- a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java
@@ -9,6 +9,7 @@ import de.hysky.skyblocker.skyblock.chocolatefactory.EggFinder;
import de.hysky.skyblocker.skyblock.crimson.dojo.DojoManager;
import de.hysky.skyblocker.skyblock.dungeon.DungeonScore;
import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager;
+import de.hysky.skyblocker.skyblock.dwarven.WishingCompassSolver;
import de.hysky.skyblocker.skyblock.end.BeaconHighlighter;
import de.hysky.skyblocker.skyblock.end.EnderNodes;
import de.hysky.skyblocker.skyblock.end.TheEnd;
@@ -100,6 +101,7 @@ public abstract class ClientPlayNetworkHandlerMixin {
MythologicalRitual.onParticle(packet);
DojoManager.onParticle(packet);
EnderNodes.onParticle(packet);
+ WishingCompassSolver.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/mixins/HandledScreenMixin.java b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java
index 709b8697..2f22a870 100644
--- a/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java
@@ -14,7 +14,6 @@ import de.hysky.skyblocker.skyblock.item.ItemProtection;
import de.hysky.skyblocker.skyblock.item.ItemRarityBackgrounds;
import de.hysky.skyblocker.skyblock.item.MuseumItemCache;
import de.hysky.skyblocker.skyblock.item.WikiLookup;
-import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
import de.hysky.skyblocker.skyblock.item.slottext.SlotTextManager;
import de.hysky.skyblocker.skyblock.item.tooltip.BackpackPreview;
import de.hysky.skyblocker.skyblock.item.tooltip.CompactorDeletorPreview;
@@ -22,11 +21,10 @@ import de.hysky.skyblocker.skyblock.quicknav.QuickNav;
import de.hysky.skyblocker.skyblock.quicknav.QuickNavButton;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.Utils;
-import de.hysky.skyblocker.utils.render.gui.ContainerSolver;
+import de.hysky.skyblocker.utils.container.ContainerSolver;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
-import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.inventory.SimpleInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
@@ -236,7 +234,7 @@ public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen
// Prevent clicks on filler items
if (SkyblockerConfigManager.get().uiAndVisuals.hideEmptyTooltips && FILLER_ITEMS.contains(stack.getName().getString()) &&
// Allow clicks in Ultrasequencer and Superpairs
- (!UltrasequencerSolver.INSTANCE.getName().matcher(title).matches() || SkyblockerConfigManager.get().helpers.experiments.enableUltrasequencerSolver)) {
+ (!UltrasequencerSolver.INSTANCE.getTitlePattern().matcher(title).matches() || SkyblockerConfigManager.get().helpers.experiments.enableUltrasequencerSolver)) {
ci.cancel();
return;
}
@@ -335,31 +333,8 @@ public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen
@Inject(method = "drawSlot", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawItemInSlot(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V"))
private void skyblocker$drawSlotText(DrawContext context, Slot slot, CallbackInfo ci) {
- List<SlotText> textList = SlotTextManager.getText(slot);
- if (textList.isEmpty()) return;
- MatrixStack matrices = context.getMatrices();
-
- for (SlotText slotText : textList) {
- matrices.push();
- matrices.translate(0.0f, 0.0f, 200.0f);
- int length = textRenderer.getWidth(slotText.text());
- if (length > 16) {
- matrices.scale(16.0f / length, 16.0f / length, 1.0f); //Make them fit in the slot. FYI, a slot is sized 16×16.
- final float x = (slot.x * length / 16.0f) - slot.x; //Save in a variable to not recalculate
- switch (slotText.position()) {
- case TOP_LEFT, TOP_RIGHT -> matrices.translate(x, (slot.y * length / 16.0f) - slot.y, 0.0f);
- case BOTTOM_LEFT, BOTTOM_RIGHT -> matrices.translate(x, ((slot.y + 16f - textRenderer.fontHeight + 2f + 0.7f) * length / 16.0f) - slot.y, 0.0f);
- }
- } else {
- switch (slotText.position()) {
- case TOP_LEFT -> { /*Do Nothing*/ }
- case TOP_RIGHT -> matrices.translate(16f - length, 0.0f, 0.0f);
- case BOTTOM_LEFT -> matrices.translate(0.0f, 16f - textRenderer.fontHeight + 2f, 0.0f);
- case BOTTOM_RIGHT -> matrices.translate(16f - length, 16f - textRenderer.fontHeight + 2f, 0.0f);
- }
- }
- context.drawText(textRenderer, slotText.text(), slot.x, slot.y, 0xFFFFFF, true);
- matrices.pop();
+ if (Utils.isOnSkyblock()) {
+ SlotTextManager.renderSlotText(context, textRenderer, slot);
}
}
}
diff --git a/src/main/java/de/hysky/skyblocker/mixins/PlayerListHudMixin.java b/src/main/java/de/hysky/skyblocker/mixins/PlayerListHudMixin.java
index a96a7727..2c7fde47 100644
--- a/src/main/java/de/hysky/skyblocker/mixins/PlayerListHudMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixins/PlayerListHudMixin.java
@@ -12,6 +12,7 @@ import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.hud.PlayerListHud;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.text.Text;
+import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@@ -42,8 +43,6 @@ public class PlayerListHudMixin {
w = (int) (w / scale);
h = (int) (h / scale);
- PlayerListMgr.updateFooter(footer);
-
try {
ScreenMaster.render(context, w,h);
// Screen screen = Screen.getCorrect(w, h, footer);
@@ -54,4 +53,9 @@ public class PlayerListHudMixin {
}
}
+ @Inject(at = @At("HEAD"), method = "setFooter")
+ public void skblocker$updateFooter(@Nullable Text footer, CallbackInfo info) {
+ PlayerListMgr.updateFooter(footer);
+ }
+
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/accessories/newyearcakes/NewYearCakeBagHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/accessories/newyearcakes/NewYearCakeBagHelper.java
index 747ce9b4..11c99daa 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/accessories/newyearcakes/NewYearCakeBagHelper.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/accessories/newyearcakes/NewYearCakeBagHelper.java
@@ -2,7 +2,7 @@ package de.hysky.skyblocker.skyblock.accessories.newyearcakes;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.utils.render.gui.ColorHighlight;
-import de.hysky.skyblocker.utils.render.gui.ContainerSolver;
+import de.hysky.skyblocker.utils.container.SimpleContainerSolver;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.client.MinecraftClient;
import net.minecraft.item.ItemStack;
@@ -10,18 +10,18 @@ import net.minecraft.screen.slot.Slot;
import java.util.List;
-public class NewYearCakeBagHelper extends ContainerSolver {
+public class NewYearCakeBagHelper extends SimpleContainerSolver {
public NewYearCakeBagHelper() {
super("New Year Cake Bag");
}
@Override
- protected boolean isEnabled() {
+ public boolean isEnabled() {
return SkyblockerConfigManager.get().helpers.enableNewYearCakesHelper;
}
@Override
- protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) {
+ public List<ColorHighlight> getColors(Int2ObjectMap<ItemStack> slots) {
MinecraftClient client = MinecraftClient.getInstance();
if (client.player != null) {
for (Slot slot : client.player.currentScreenHandler.slots) {
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/accessories/newyearcakes/NewYearCakesHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/accessories/newyearcakes/NewYearCakesHelper.java
index c403a81b..4b3dbda8 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/accessories/newyearcakes/NewYearCakesHelper.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/accessories/newyearcakes/NewYearCakesHelper.java
@@ -3,7 +3,7 @@ package de.hysky.skyblocker.skyblock.accessories.newyearcakes;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.utils.Utils;
import de.hysky.skyblocker.utils.render.gui.ColorHighlight;
-import de.hysky.skyblocker.utils.render.gui.ContainerSolver;
+import de.hysky.skyblocker.utils.container.SimpleContainerSolver;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
@@ -19,8 +19,8 @@ import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class NewYearCakesHelper extends ContainerSolver {
- private static final Logger LOGGER = LoggerFactory.getLogger(NewYearCakeBagHelper.class);
+public class NewYearCakesHelper extends SimpleContainerSolver {
+ private static final Logger LOGGER = LoggerFactory.getLogger(NewYearCakesHelper.class);
private static final Pattern NEW_YEAR_CAKE = Pattern.compile("New Year Cake \\(Year (?<year>\\d+)\\)");
private static final Pattern NEW_YEAR_CAKE_PURCHASE = Pattern.compile("You purchased New Year Cake \\(Year (?<year>\\d+)\\) for .+ coins!");
private static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance(Locale.US);
@@ -49,7 +49,7 @@ public class NewYearCakesHelper extends ContainerSolver {
}
@Override
- protected boolean isEnabled() {
+ public boolean isEnabled() {
return SkyblockerConfigManager.get().helpers.enableNewYearCakesHelper;
}
@@ -65,7 +65,7 @@ public class NewYearCakesHelper extends ContainerSolver {
}
@Override
- protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) {
+ public List<ColorHighlight> getColors(Int2ObjectMap<ItemStack> slots) {
String profile = Utils.getProfile();
if (cakes.isEmpty() || !cakes.containsKey(profile) || cakes.containsKey(profile) && cakes.get(profile).isEmpty()) return List.of();
List<ColorHighlight> highlights = new ArrayList<>();
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/bazaar/BazaarHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/bazaar/BazaarHelper.java
index 8b83b06b..8fbeb6e0 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/bazaar/BazaarHelper.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/bazaar/BazaarHelper.java
@@ -1,8 +1,8 @@
package de.hysky.skyblocker.skyblock.bazaar;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.skyblock.item.slottext.SimpleSlotTextAdder;
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;
@@ -11,12 +11,13 @@ import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import org.apache.commons.lang3.math.NumberUtils;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class BazaarHelper extends SlotTextAdder {
+public class BazaarHelper extends SimpleSlotTextAdder {
private static final Pattern FILLED_PATTERN = Pattern.compile("Filled: \\S+ \\(?([\\d.]+)%\\)?!?");
private static final int RED = 0xe60b1e;
private static final int YELLOW = 0xe6ba0b;
@@ -27,14 +28,19 @@ public class BazaarHelper extends SlotTextAdder {
}
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- if (!SkyblockerConfigManager.get().helpers.bazaar.enableBazaarHelper) return List.of();
+ public boolean isEnabled() {
+ return SkyblockerConfigManager.get().helpers.bazaar.enableBazaarHelper;
+ }
+
+ @Override
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
+ if (slot == null) return List.of();
// Skip the first row as it's always glass panes.
- if (slot.id < 10) return List.of();
+ if (slotId < 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)
+ if (slotId > 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;
+ int column = slotId % 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();
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/bazaar/ReorderHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/bazaar/ReorderHelper.java
index c2b11926..f6c53528 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/bazaar/ReorderHelper.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/bazaar/ReorderHelper.java
@@ -1,9 +1,9 @@
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.container.SimpleContainerSolver;
+import de.hysky.skyblocker.utils.container.TooltipAdder;
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;
@@ -19,7 +19,7 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class ReorderHelper extends ContainerSolver {
+public class ReorderHelper extends SimpleContainerSolver implements TooltipAdder {
private static final Pattern BUY_PATTERN = Pattern.compile("([\\d,]+)x missing items\\.");
private static final Pattern SELL_PATTERN = Pattern.compile("([\\d,]+)x items\\.");
@@ -28,12 +28,12 @@ public class ReorderHelper extends ContainerSolver {
}
@Override
- protected boolean isEnabled() {
+ public boolean isEnabled() {
return true;
}
@Override
- protected boolean onClickSlot(int slot, ItemStack stack, int screenId, String[] groups) {
+ public boolean onClickSlot(int slot, ItemStack stack, int screenId) {
// 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;
@@ -49,25 +49,24 @@ public class ReorderHelper extends ContainerSolver {
}
@Override
- protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) {
+ public List<ColorHighlight> getColors(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));
- }
+ @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));
}
}
}
+
+ @Override
+ public int getPriority() {
+ return Integer.MIN_VALUE;
+ }
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java
index 04f6536d..faaee6a4 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java
@@ -1,12 +1,12 @@
package de.hysky.skyblocker.skyblock.chocolatefactory;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
-import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
import de.hysky.skyblocker.skyblock.item.tooltip.adders.LineSmoothener;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.RegexUtils;
+import de.hysky.skyblocker.utils.container.SimpleContainerSolver;
+import de.hysky.skyblocker.utils.container.TooltipAdder;
import de.hysky.skyblocker.utils.render.gui.ColorHighlight;
-import de.hysky.skyblocker.utils.render.gui.ContainerSolver;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
@@ -28,7 +28,7 @@ import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class ChocolateFactorySolver extends ContainerSolver {
+public class ChocolateFactorySolver extends SimpleContainerSolver implements TooltipAdder {
//Patterns
private static final Pattern CPS_PATTERN = Pattern.compile("([\\d,.]+) Chocolate per second");
private static final Pattern CPS_INCREASE_PATTERN = Pattern.compile("\\+([\\d,]+) Chocolate per second");
@@ -52,19 +52,18 @@ public class ChocolateFactorySolver extends ContainerSolver {
private static final byte STRAY_RABBIT_START = 0;
private static final byte STRAY_RABBIT_END = 26;
- // TODO: Convert to instance fields in #788
- private static final ObjectArrayList<Rabbit> cpsIncreaseFactors = new ObjectArrayList<>(8);
- private static long totalChocolate = -1L;
- private static double totalCps = -1.0;
- private static double totalCpsMultiplier = -1.0;
- private static long requiredUntilNextPrestige = -1L;
- private static boolean canPrestige = false;
- private static boolean reachedMaxPrestige = false;
- private static double timeTowerMultiplier = -1.0;
- private static boolean isTimeTowerMaxed = false;
- private static boolean isTimeTowerActive = false;
- private static int bestUpgrade = -1;
- private static int bestAffordableUpgrade = -1;
+ private final ObjectArrayList<Rabbit> cpsIncreaseFactors = new ObjectArrayList<>(8);
+ private long totalChocolate = -1L;
+ private double totalCps = -1.0;
+ private double totalCpsMultiplier = -1.0;
+ private long requiredUntilNextPrestige = -1L;
+ private boolean canPrestige = false;
+ private boolean reachedMaxPrestige = false;
+ private double timeTowerMultiplier = -1.0;
+ private boolean isTimeTowerMaxed = false;
+ private boolean isTimeTowerActive = false;
+ private int bestUpgrade = -1;
+ private int bestAffordableUpgrade = -1;
private static StraySound ding = StraySound.NONE;
private static int dingTick = 0;
@@ -74,7 +73,9 @@ public class ChocolateFactorySolver extends ContainerSolver {
DECIMAL_FORMAT.setMaximumFractionDigits(1);
}
- public ChocolateFactorySolver() {
+ public static final ChocolateFactorySolver INSTANCE = new ChocolateFactorySolver();
+
+ private ChocolateFactorySolver() {
super("^Chocolate Factory$"); //There are multiple screens that fit the pattern `^Chocolate Factory`, so the $ is required
ClientTickEvents.START_CLIENT_TICK.register(ChocolateFactorySolver::onTick);
}
@@ -89,12 +90,14 @@ public class ChocolateFactorySolver extends ContainerSolver {
}
@Override
- protected boolean isEnabled() {
+ public boolean isEnabled() {
return SkyblockerConfigManager.get().helpers.chocolateFactory.enableChocolateFactoryHelper;
}
+ // ======== Container Solver ========
+
@Override
- protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) {
+ public List<ColorHighlight> getColors(Int2ObjectMap<ItemStack> slots) {
updateFactoryInfo(slots);
List<ColorHighlight> highlights = new ArrayList<>();
@@ -239,160 +242,163 @@ public class ChocolateFactorySolver extends ContainerSolver {
return highlights;
}
- @Override
- protected void reset() {
- cpsIncreaseFactors.clear();
- totalChocolate = -1L;
- totalCps = -1.0;
- totalCpsMultiplier = -1.0;
- requiredUntilNextPrestige = -1L;
- canPrestige = false;
- reachedMaxPrestige = false;
- timeTowerMultiplier = -1.0;
- isTimeTowerMaxed = false;
- isTimeTowerActive = false;
- bestUpgrade = -1;
- bestAffordableUpgrade = -1;
- ding = StraySound.NONE;
- }
+ // ======== Tooltip Adder ========
- private enum StraySound {
- NONE,
- NORMAL,
- GOLDEN
- }
-
- private record Rabbit(double cpsIncrease, long cost, int slot) {}
-
- public static final class Tooltip extends TooltipAdder {
- public Tooltip() {
- super("^Chocolate Factory$", 0); //The priority doesn't really matter here as this is the only tooltip adder for the Chocolate Factory.
- }
+ @Override
+ public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) {
+ if (focusedSlot == null) return;
- @Override
- public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) {
- if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableChocolateFactoryHelper || focusedSlot == null) return;
+ int lineIndex = lines.size();
+ //This boolean is used to determine if we should add a smooth line to separate the added information from the rest of the tooltip.
+ //It should be set to true if there's any information added, false otherwise.
+ boolean shouldAddLine = false;
- int lineIndex = lines.size();
- //This boolean is used to determine if we should add a smooth line to separate the added information from the rest of the tooltip.
- //It should be set to true if there's any information added, false otherwise.
- boolean shouldAddLine = false;
+ String lore = ItemUtils.concatenateLore(lines);
+ Matcher costMatcher = COST_PATTERN.matcher(lore);
+ OptionalLong cost = RegexUtils.getLongFromMatcher(costMatcher);
+ //Available on all items with a chocolate cost
+ if (cost.isPresent()) shouldAddLine |= addUpgradeTimerToLore(lines, cost.getAsLong());
- String lore = ItemUtils.concatenateLore(lines);
- Matcher costMatcher = COST_PATTERN.matcher(lore);
- OptionalLong cost = RegexUtils.getLongFromMatcher(costMatcher);
- //Available on all items with a chocolate cost
- if (cost.isPresent()) shouldAddLine |= addUpgradeTimerToLore(lines, cost.getAsLong());
+ int index = focusedSlot.id;
- int index = focusedSlot.id;
+ //Prestige item
+ if (index == PRESTIGE_SLOT) {
+ shouldAddLine |= addPrestigeTimerToLore(lines);
+ }
+ //Time tower
+ else if (index == TIME_TOWER_SLOT) {
+ shouldAddLine |= addTimeTowerStatsToLore(lines);
+ }
+ //Rabbits
+ else if (index == COACH_SLOT || (index >= RABBITS_START && index <= RABBITS_END)) {
+ shouldAddLine |= addRabbitStatsToLore(lines, index);
+ }
- //Prestige item
- if (index == PRESTIGE_SLOT) {
- shouldAddLine |= addPrestigeTimerToLore(lines);
- }
- //Time tower
- else if (index == TIME_TOWER_SLOT) {
- shouldAddLine |= addTimeTowerStatsToLore(lines);
- }
- //Rabbits
- else if (index == COACH_SLOT || (index >= RABBITS_START && index <= RABBITS_END)) {
- shouldAddLine |= addRabbitStatsToLore(lines, index);
- }
+ //This is an ArrayList, so this operation is probably not very efficient, but logically it's pretty much the only way I can think of
+ if (shouldAddLine) lines.add(lineIndex, LineSmoothener.createSmoothLine());
+ }
- //This is an ArrayList, so this operation is probably not very efficient, but logically it's pretty much the only way I can think of
- if (shouldAddLine) lines.add(lineIndex, LineSmoothener.createSmoothLine());
- }
+ private boolean addUpgradeTimerToLore(List<Text> lines, long cost) {
+ if (totalChocolate < 0L || totalCps < 0.0) return false;
+ lines.add(Text.empty()
+ .append(Text.literal("Time until upgrade: ").formatted(Formatting.GRAY))
+ .append(formatTime((cost - totalChocolate) / totalCps)));
+ return true;
+ }
- private boolean addUpgradeTimerToLore(List<Text> lines, long cost) {
- if (totalChocolate < 0L || totalCps < 0.0) return false;
+ private boolean addPrestigeTimerToLore(List<Text> lines) {
+ if (totalCps < 0.0 || reachedMaxPrestige) return false;
+ if (requiredUntilNextPrestige > 0 && !canPrestige) {
lines.add(Text.empty()
- .append(Text.literal("Time until upgrade: ").formatted(Formatting.GRAY))
- .append(formatTime((cost - totalChocolate) / totalCps)));
- return true;
- }
-
- private boolean addPrestigeTimerToLore(List<Text> lines) {
- if (totalCps < 0.0 || reachedMaxPrestige) return false;
- if (requiredUntilNextPrestige > 0 && !canPrestige) {
- lines.add(Text.empty()
- .append(Text.literal("Chocolate until next prestige: ").formatted(Formatting.GRAY))
- .append(Text.literal(DECIMAL_FORMAT.format(requiredUntilNextPrestige)).formatted(Formatting.GOLD)));
- }
- lines.add(Text.empty() //Keep this outside of the `if` to match the format of the upgrade tooltips, that say "Time until upgrade: Now" when it's possible
- .append(Text.literal("Time until next prestige: ").formatted(Formatting.GRAY))
- .append(formatTime(requiredUntilNextPrestige / totalCps)));
- return true;
+ .append(Text.literal("Chocolate until next prestige: ").formatted(Formatting.GRAY))
+ .append(Text.literal(DECIMAL_FORMAT.format(requiredUntilNextPrestige)).formatted(Formatting.GOLD)));
}
+ lines.add(Text.empty() //Keep this outside of the `if` to match the format of the upgrade tooltips, that say "Time until upgrade: Now" when it's possible
+ .append(Text.literal("Time until next prestige: ").formatted(Formatting.GRAY))
+ .append(formatTime(requiredUntilNextPrestige / totalCps)));
+ return true;
+ }
- private boolean addTimeTowerStatsToLore(List<Text> lines) {
- if (totalCps < 0.0 || totalCpsMultiplier < 0.0 || timeTowerMultiplier < 0.0) return false;
- lines.add(Text.literal("Current stats:").formatted(Formatting.GRAY));
+ private boolean addTimeTowerStatsToLore(List<Text> lines) {
+ if (totalCps < 0.0 || totalCpsMultiplier < 0.0 || timeTowerMultiplier < 0.0) return false;
+ lines.add(Text.literal("Current stats:").formatted(Formatting.GRAY));
+ lines.add(Text.empty()
+ .append(Text.literal(" CPS increase: ").formatted(Formatting.GRAY))
+ .append(Text.literal(DECIMAL_FORMAT.format(totalCps / totalCpsMultiplier * timeTowerMultiplier)).formatted(Formatting.GOLD)));
+ lines.add(Text.empty()
+ .append(Text.literal(" CPS when active: ").formatted(Formatting.GRAY))
+ .append(Text.literal(DECIMAL_FORMAT.format(isTimeTowerActive ? totalCps : totalCps / totalCpsMultiplier * (timeTowerMultiplier + totalCpsMultiplier))).formatted(Formatting.GOLD)));
+ if (!isTimeTowerMaxed) {
+ lines.add(Text.literal("Stats after upgrade:").formatted(Formatting.GRAY));
lines.add(Text.empty()
.append(Text.literal(" CPS increase: ").formatted(Formatting.GRAY))
- .append(Text.literal(DECIMAL_FORMAT.format(totalCps / totalCpsMultiplier * timeTowerMultiplier)).formatted(Formatting.GOLD)));
+ .append(Text.literal(DECIMAL_FORMAT.format(totalCps / (totalCpsMultiplier) * (timeTowerMultiplier + 0.1))).formatted(Formatting.GOLD)));
lines.add(Text.empty()
.append(Text.literal(" CPS when active: ").formatted(Formatting.GRAY))
- .append(Text.literal(DECIMAL_FORMAT.format(isTimeTowerActive ? totalCps : totalCps / totalCpsMultiplier * (timeTowerMultiplier + totalCpsMultiplier))).formatted(Formatting.GOLD)));
- if (!isTimeTowerMaxed) {
- lines.add(Text.literal("Stats after upgrade:").formatted(Formatting.GRAY));
- lines.add(Text.empty()
- .append(Text.literal(" CPS increase: ").formatted(Formatting.GRAY))
- .append(Text.literal(DECIMAL_FORMAT.format(totalCps / (totalCpsMultiplier) * (timeTowerMultiplier + 0.1))).formatted(Formatting.GOLD)));
- lines.add(Text.empty()
- .append(Text.literal(" CPS when active: ").formatted(Formatting.GRAY))
- .append(Text.literal(DECIMAL_FORMAT.format(isTimeTowerActive ? totalCps / totalCpsMultiplier * (totalCpsMultiplier + 0.1) : totalCps / totalCpsMultiplier * (timeTowerMultiplier + 0.1 + totalCpsMultiplier))).formatted(Formatting.GOLD)));
- }
- return true;
+ .append(Text.literal(DECIMAL_FORMAT.format(isTimeTowerActive ? totalCps / totalCpsMultiplier * (totalCpsMultiplier + 0.1) : totalCps / totalCpsMultiplier * (timeTowerMultiplier + 0.1 + totalCpsMultiplier))).formatted(Formatting.GOLD)));
}
+ return true;
+ }
- private boolean addRabbitStatsToLore(List<Text> lines, int slot) {
- if (cpsIncreaseFactors.isEmpty()) return false;
- for (Rabbit rabbit : cpsIncreaseFactors) {
- if (rabbit.slot == slot) {
- lines.add(Text.empty()
- .append(Text.literal("CPS Increase: ").formatted(Formatting.GRAY))
- .append(Text.literal(DECIMAL_FORMAT.format(rabbit.cpsIncrease)).formatted(Formatting.GOLD)));
-
- lines.add(Text.empty()
- .append(Text.literal("Cost per CPS: ").formatted(Formatting.GRAY))
- .append(Text.literal(DECIMAL_FORMAT.format(rabbit.cost / rabbit.cpsIncrease)).formatted(Formatting.GOLD)));
-
- if (rabbit.slot == bestUpgrade) {
- if (rabbit.cost <= totalChocolate) {
- lines.add(Text.literal("Best upgrade").formatted(Formatting.GREEN));
- } else {
- lines.add(Text.literal("Best upgrade, can't afford").formatted(Formatting.YELLOW));
- }
- } else if (rabbit.slot == bestAffordableUpgrade && rabbit.cost <= totalChocolate) {
- lines.add(Text.literal("Best upgrade you can afford").formatted(Formatting.GREEN));
+ private boolean addRabbitStatsToLore(List<Text> lines, int slot) {
+ if (cpsIncreaseFactors.isEmpty()) return false;
+ for (Rabbit rabbit : cpsIncreaseFactors) {
+ if (rabbit.slot == slot) {
+ lines.add(Text.empty()
+ .append(Text.literal("CPS Increase: ").formatted(Formatting.GRAY))
+ .append(Text.literal(DECIMAL_FORMAT.format(rabbit.cpsIncrease)).formatted(Formatting.GOLD)));
+
+ lines.add(Text.empty()
+ .append(Text.literal("Cost per CPS: ").formatted(Formatting.GRAY))
+ .append(Text.literal(DECIMAL_FORMAT.format(rabbit.cost / rabbit.cpsIncrease)).formatted(Formatting.GOLD)));
+
+ if (rabbit.slot == bestUpgrade) {
+ if (rabbit.cost <= totalChocolate) {
+ lines.add(Text.literal("Best upgrade").formatted(Formatting.GREEN));
+ } else {
+ lines.add(Text.literal("Best upgrade, can't afford").formatted(Formatting.YELLOW));
}
- return true;
+ } else if (rabbit.slot == bestAffordableUpgrade && rabbit.cost <= totalChocolate) {
+ lines.add(Text.literal("Best upgrade you can afford").formatted(Formatting.GREEN));
}
+ return true;
}
- return false;
}
+ return false;
+ }
- private MutableText formatTime(double seconds) {
- seconds = Math.ceil(seconds);
- if (seconds <= 0) return Text.literal("Now").formatted(Formatting.GREEN);
+ private MutableText formatTime(double seconds) {
+ seconds = Math.ceil(seconds);
+ if (seconds <= 0) return Text.literal("Now").formatted(Formatting.GREEN);
- StringBuilder builder = new StringBuilder();
- if (seconds >= 86400) {
- builder.append((int) (seconds / 86400)).append("d ");
- seconds %= 86400;
- }
- if (seconds >= 3600) {
- builder.append((int) (seconds / 3600)).append("h ");
- seconds %= 3600;
- }
- if (seconds >= 60) {
- builder.append((int) (seconds / 60)).append("m ");
- seconds %= 60;
- }
- if (seconds >= 1) {
- builder.append((int) seconds).append("s");
- }
- return Text.literal(builder.toString()).formatted(Formatting.GOLD);
+ StringBuilder builder = new StringBuilder();
+ if (seconds >= 86400) {
+ builder.append((int) (seconds / 86400)).append("d ");
+ seconds %= 86400;
}
+ if (seconds >= 3600) {
+ builder.append((int) (seconds / 3600)).append("h ");
+ seconds %= 3600;
+ }
+ if (seconds >= 60) {
+ builder.append((int) (seconds / 60)).append("m ");
+ seconds %= 60;
+ }
+ if (seconds >= 1) {
+ builder.append((int) seconds).append("s");
+ }
+ return Text.literal(builder.toString()).formatted(Formatting.GOLD);
+ }
+
+ @Override
+ public int getPriority() {
+ return 0; //The priority doesn't really matter here as this is the only tooltip adder for the Chocolate Factory.
+ }
+
+ // ======== Reset and Other Classes ========
+
+ @Override
+ public void reset() {
+ cpsIncreaseFactors.clear();
+ totalChocolate = -1L;
+ totalCps = -1.0;
+ totalCpsMultiplier = -1.0;
+ requiredUntilNextPrestige = -1L;
+ canPrestige = false;
+ reachedMaxPrestige = false;
+ timeTowerMultiplier = -1.0;
+ isTimeTowerMaxed = false;
+ isTimeTowerActive = false;
+ bestUpgrade = -1;
+ bestAffordableUpgrade = -1;
+ ding = StraySound.NONE;
+ }
+
+ private enum StraySound {
+ NONE,
+ NORMAL,
+ GOLDEN
}
+
+ private record Rabbit(double cpsIncrease, long cost, int slot) {}
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusHelper.java
index d317a2e8..1a0aa347 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusHelper.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusHelper.java
@@ -3,7 +3,7 @@ package de.hysky.skyblocker.skyblock.dungeon;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.render.gui.ColorHighlight;
-import de.hysky.skyblocker.utils.render.gui.ContainerSolver;
+import de.hysky.skyblocker.utils.container.SimpleContainerSolver;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.item.ItemStack;
@@ -11,19 +11,18 @@ import net.minecraft.item.ItemStack;
import java.util.ArrayList;
import java.util.List;
-public class CroesusHelper extends ContainerSolver {
-
+public class CroesusHelper extends SimpleContainerSolver {
public CroesusHelper() {
super("^Croesus$");
}
@Override
- protected boolean isEnabled() {
+ public boolean isEnabled() {
return SkyblockerConfigManager.get().dungeons.croesusHelper;
}
@Override
- protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) {
+ public List<ColorHighlight> getColors(Int2ObjectMap<ItemStack> slots) {
List<ColorHighlight> highlights = new ArrayList<>();
for (Int2ObjectMap.Entry<ItemStack> entry : slots.int2ObjectEntrySet()) {
ItemStack stack = entry.getValue();
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusProfit.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusProfit.java
index 0f459c9d..82acc3f2 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusProfit.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/CroesusProfit.java
@@ -1,16 +1,13 @@
package de.hysky.skyblocker.skyblock.dungeon;
-import com.google.gson.JsonObject;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
-import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.render.gui.ColorHighlight;
-import de.hysky.skyblocker.utils.render.gui.ContainerSolver;
+import de.hysky.skyblocker.utils.container.SimpleContainerSolver;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.item.ItemStack;
import net.minecraft.text.Text;
import net.minecraft.util.Util;
-
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -20,19 +17,19 @@ import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class CroesusProfit extends ContainerSolver {
- private static final Pattern ESSENCE_PATTERN = Pattern.compile("(?<type>[A-Za-z]+) Essence x(?<amount>[0-9]+)");
+public class CroesusProfit extends SimpleContainerSolver {
+ private static final Pattern ESSENCE_PATTERN = Pattern.compile("(?<type>[A-Za-z]+) Essence x(?<amount>\\d+)");
public CroesusProfit() {
super(".*Catacombs - Floor.*");
}
@Override
- protected boolean isEnabled() {
+ public boolean isEnabled() {
return SkyblockerConfigManager.get().dungeons.dungeonChestProfit.croesusProfit;
}
@Override
- protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) {
+ public List<ColorHighlight> getColors(Int2ObjectMap<ItemStack> slots) {
List<ColorHighlight> highlights = new ArrayList<>();
ItemStack bestChest = null, secondBestChest = null;
double bestValue = 0, secondBestValue = 0; // If negative value of chest - it is out of the question
@@ -82,7 +79,7 @@ public class CroesusProfit extends ContainerSolver {
} else if (lineString.isEmpty()) {
processingContents = false;
} else if (lineString.contains("Coins") && !processingContents) {
- chestPrice = Integer.parseInt(lineString.replaceAll(",", "").replaceAll("\\D", ""));
+ chestPrice = Integer.parseInt(lineString.replace(",", "").replaceAll("\\D", ""));
}
if (processingContents) {
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/ColorTerminal.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/ColorTerminal.java
index 7a966b48..6cbb86ec 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/ColorTerminal.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/ColorTerminal.java
@@ -1,8 +1,9 @@
package de.hysky.skyblocker.skyblock.dungeon.terminal;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.utils.container.ContainerSolver;
+import de.hysky.skyblocker.utils.container.SimpleContainerSolver;
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.item.Item;
import net.minecraft.item.ItemStack;
@@ -16,7 +17,7 @@ import org.slf4j.LoggerFactory;
import java.util.*;
-public final class ColorTerminal extends ContainerSolver implements TerminalSolver {
+public final class ColorTerminal extends SimpleContainerSolver implements TerminalSolver {
private static final Logger LOGGER = LoggerFactory.getLogger(ColorTerminal.class.getName());
private static final Map<String, DyeColor> colorFromName;
private DyeColor targetColor;
@@ -27,20 +28,20 @@ public final class ColorTerminal extends ContainerSolver implements TerminalSolv
}
@Override
- protected boolean isEnabled() {
+ public boolean isEnabled() {
targetColor = null;
return SkyblockerConfigManager.get().dungeons.terminals.solveColor;
}
@Override
- protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) {
- trimEdges(slots, 6);
+ public List<ColorHighlight> getColors(Int2ObjectMap<ItemStack> slots) {
+ ContainerSolver.trimEdges(slots, 6);
List<ColorHighlight> highlights = new ArrayList<>();
String colorString = groups[0];
if (targetColor == null) {
targetColor = colorFromName.get(colorString);
if (targetColor == null) {
- LOGGER.error("[Skyblocker] Couldn't find dye color corresponding to \"" + colorString + "\"");
+ LOGGER.error("[Skyblocker] Couldn't find dye color corresponding to \"{}\"", colorString);
return Collections.emptyList();
}
}
@@ -54,7 +55,7 @@ public final class ColorTerminal extends ContainerSolver implements TerminalSolv
}
@Override
- protected boolean onClickSlot(int slot, ItemStack stack, int screenId, String[] groups) {
+ public boolean onClickSlot(int slot, ItemStack stack, int screenId) {
if (stack.hasGlint() || !targetColor.equals(itemColor.get(stack.getItem()))) {
return shouldBlockIncorrectClicks();
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/LightsOnTerminal.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/LightsOnTerminal.java
index 4975b90b..741a2f9b 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/LightsOnTerminal.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/LightsOnTerminal.java
@@ -1,19 +1,19 @@
package de.hysky.skyblocker.skyblock.dungeon.terminal;
-import java.util.List;
-
+import de.hysky.skyblocker.utils.container.SimpleContainerSolver;
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.item.ItemStack;
import net.minecraft.item.Items;
+import java.util.List;
+
/**
* The terminal where you change all the panes that are red to green.
*
* This doesn't solve the terminal because you don't need a solver for it, but rather to simply allow for click blocking.
*/
-public final class LightsOnTerminal extends ContainerSolver implements TerminalSolver {
+public final class LightsOnTerminal extends SimpleContainerSolver implements TerminalSolver {
private static final List<ColorHighlight> EMPTY = List.of();
public LightsOnTerminal() {
@@ -21,17 +21,17 @@ public final class LightsOnTerminal extends ContainerSolver implements TerminalS
}
@Override
- protected boolean isEnabled() {
+ public boolean isEnabled() {
return shouldBlockIncorrectClicks();
}
@Override
- protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) {
+ public List<ColorHighlight> getColors(Int2ObjectMap<ItemStack> slots) {
return EMPTY;
}
@Override
- protected boolean onClickSlot(int slot, ItemStack stack, int screenId, String[] groups) {
+ public boolean onClickSlot(int slot, ItemStack stack, int screenId) {
return stack.isOf(Items.LIME_STAINED_GLASS_PANE);
}
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/OrderTerminal.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/OrderTerminal.java
index ae145993..507389c6 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/OrderTerminal.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/OrderTerminal.java
@@ -1,8 +1,9 @@
package de.hysky.skyblocker.skyblock.dungeon.terminal;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.utils.container.ContainerSolver;
+import de.hysky.skyblocker.utils.container.SimpleContainerSolver;
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.item.ItemStack;
import net.minecraft.item.Items;
@@ -11,8 +12,8 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-public final class OrderTerminal extends ContainerSolver implements TerminalSolver {
- private final int PANES_NUM = 14;
+public final class OrderTerminal extends SimpleContainerSolver implements TerminalSolver {
+ private static final int PANES_NUM = 14;
private int[] orderedSlots;
private int currentNum = Integer.MAX_VALUE;
@@ -21,14 +22,14 @@ public final class OrderTerminal extends ContainerSolver implements TerminalSolv
}
@Override
- protected boolean isEnabled() {
+ public boolean isEnabled() {
orderedSlots = null;
currentNum = 0;
return SkyblockerConfigManager.get().dungeons.terminals.solveOrder;
}
@Override
- protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) {
+ public List<ColorHighlight> getColors(Int2ObjectMap<ItemStack> slots) {
if(orderedSlots == null && !orderSlots(slots))
return Collections.emptyList();
while(currentNum < PANES_NUM && slots.containsKey(orderedSlots[currentNum]) && Items.LIME_STAINED_GLASS_PANE.equals(slots.get(orderedSlots[currentNum]).getItem()))
@@ -42,22 +43,21 @@ public final class OrderTerminal extends ContainerSolver implements TerminalSolv
}
public boolean orderSlots(Int2ObjectMap<ItemStack> slots) {
- trimEdges(slots, 4);
+ ContainerSolver.trimEdges(slots, 4);
orderedSlots = new int[PANES_NUM];
for(Int2ObjectMap.Entry<ItemStack> slot : slots.int2ObjectEntrySet()) {
if(Items.AIR.equals(slot.getValue().getItem())) {
orderedSlots = null;
return false;
}
- else
- orderedSlots[slot.getValue().getCount() - 1] = slot.getIntKey();
+ else orderedSlots[slot.getValue().getCount() - 1] = slot.getIntKey();
}
currentNum = 0;
return true;
}
@Override
- protected boolean onClickSlot(int slot, ItemStack stack, int screenId, String[] groups) {
+ public boolean onClickSlot(int slot, ItemStack stack, int screenId) {
if (stack == null || stack.isEmpty()) return false;
if (!stack.isOf(Items.RED_STAINED_GLASS_PANE) || stack.getCount() != currentNum + 1) {
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/StartsWithTerminal.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/StartsWithTerminal.java
index 8b0f1801..893e9f61 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/StartsWithTerminal.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/StartsWithTerminal.java
@@ -1,8 +1,9 @@
package de.hysky.skyblocker.skyblock.dungeon.terminal;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.utils.container.ContainerSolver;
+import de.hysky.skyblocker.utils.container.SimpleContainerSolver;
import de.hysky.skyblocker.utils.render.gui.ColorHighlight;
-import de.hysky.skyblocker.utils.render.gui.ContainerSolver;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectSet;
@@ -13,7 +14,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
-public final class StartsWithTerminal extends ContainerSolver implements TerminalSolver {
+public final class StartsWithTerminal extends SimpleContainerSolver implements TerminalSolver {
private final Int2ObjectOpenHashMap<ItemState> trackedItemStates = new Int2ObjectOpenHashMap<>();
private int lastKnownScreenId = Integer.MIN_VALUE;
@@ -22,13 +23,13 @@ public final class StartsWithTerminal extends ContainerSolver implements Termina
}
@Override
- protected boolean isEnabled() {
+ public boolean isEnabled() {
return SkyblockerConfigManager.get().dungeons.terminals.solveStartsWith;
}
@Override
- protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) {
- trimEdges(slots, 6);
+ public List<ColorHighlight> getColors(Int2ObjectMap<ItemStack> slots) {
+ ContainerSolver.trimEdges(slots, 6);
setupState(slots);
String prefix = groups[0];
@@ -50,7 +51,7 @@ public final class StartsWithTerminal extends ContainerSolver implements Termina
}
@Override
- protected boolean onClickSlot(int slot, ItemStack stack, int screenId, String[] groups) {
+ public boolean onClickSlot(int slot, ItemStack stack, int screenId) {
//Some random glass pane was clicked or something
if (!trackedItemStates.containsKey(slot) || stack == null || stack.isEmpty()) return false;
@@ -74,7 +75,7 @@ public final class StartsWithTerminal extends ContainerSolver implements Termina
return false;
}
- //We only setup the state when all items aren't null or empty. This prevents the state from being reset due to unsent items or server lag spikes/bad TPS (fix ur servers Hypixel)
+ //We only set up the state when all items aren't null or empty. This prevents the state from being reset due to unsent items or server lag spikes/bad TPS (fix ur servers Hypixel)
private void setupState(Int2ObjectMap<ItemStack> usefulSlots) {
Predicate<Int2ObjectMap.Entry<ItemStack>> notNullOrEmpty = e -> e.getValue() != null && !e.getValue().isEmpty();
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/TerminalSolver.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/TerminalSolver.java
index f20c35b5..cf384f08 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/TerminalSolver.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/terminal/TerminalSolver.java
@@ -3,7 +3,6 @@ package de.hysky.skyblocker.skyblock.dungeon.terminal;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
public sealed interface TerminalSolver permits ColorTerminal, LightsOnTerminal, OrderTerminal, StartsWithTerminal {
-
default boolean shouldBlockIncorrectClicks() {
return SkyblockerConfigManager.get().dungeons.terminals.blockIncorrectClicks;
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CommissionHighlight.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CommissionHighlight.java
index de26809c..c22a4440 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CommissionHighlight.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CommissionHighlight.java
@@ -2,8 +2,8 @@ package de.hysky.skyblocker.skyblock.dwarven;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.utils.ItemUtils;
+import de.hysky.skyblocker.utils.container.SimpleContainerSolver;
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.component.DataComponentTypes;
import net.minecraft.item.ItemStack;
@@ -11,19 +11,18 @@ import net.minecraft.item.ItemStack;
import java.util.ArrayList;
import java.util.List;
-public class CommissionHighlight extends ContainerSolver {
-
+public class CommissionHighlight extends SimpleContainerSolver {
public CommissionHighlight() {
super("^Commissions$");
}
@Override
- protected boolean isEnabled() {
+ public boolean isEnabled() {
return SkyblockerConfigManager.get().mining.commissionHighlight;
}
@Override
- protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) {
+ public List<ColorHighlight> getColors(Int2ObjectMap<ItemStack> slots) {
List<ColorHighlight> highlights = new ArrayList<>();
for (Int2ObjectMap.Entry<ItemStack> entry : slots.int2ObjectEntrySet()) {
ItemStack stack = entry.getValue();
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHud.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHud.java
index 7f4dbdbf..30bf6b03 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHud.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsHud.java
@@ -23,7 +23,7 @@ public class CrystalsHud {
private static final MinecraftClient CLIENT = MinecraftClient.getInstance();
protected static final Identifier MAP_TEXTURE = Identifier.of(SkyblockerMod.NAMESPACE, "textures/gui/crystals_map.png");
private static final Identifier MAP_ICON = Identifier.ofVanilla("textures/map/decorations/player.png");
- private static final List<String> SMALL_LOCATIONS = List.of("Fairy Grotto", "King Yolkar", "Corleone", "Odawa", "Key Guardian");
+ private static final List<String> SMALL_LOCATIONS = List.of("Fairy Grotto", "King Yolkar", "Corleone", "Odawa", "Key Guardian", "Unknown");
public static boolean visible = false;
@@ -54,8 +54,8 @@ public class CrystalsHud {
* Renders the map to the players UI. renders the background image ({@link CrystalsHud#MAP_TEXTURE}) of the map then if enabled special locations on the map. then finally the player to the map.
*
* @param context DrawContext to draw map to
- * @param hudX Top left X coordinate of the map
- * @param hudY Top left Y coordinate of the map
+ * @param hudX Top left X coordinate of the map
+ * @param hudY Top left Y coordinate of the map
*/
private static void render(DrawContext context, int hudX, int hudY) {
float scale = SkyblockerConfigManager.get().mining.crystalsHud.mapScaling;
@@ -72,19 +72,19 @@ public class CrystalsHud {
//if enabled add waypoint locations to map
if (SkyblockerConfigManager.get().mining.crystalsHud.showLocations) {
- Map<String,CrystalsWaypoint> ActiveWaypoints = CrystalsLocationsManager.activeWaypoints;
+ Map<String, MiningLocationLabel> ActiveWaypoints = CrystalsLocationsManager.activeWaypoints;
- for (CrystalsWaypoint waypoint : ActiveWaypoints.values()) {
- Color waypointColor = waypoint.category.color;
- Vector2ic renderPos = transformLocation(waypoint.pos.getX(), waypoint.pos.getZ());
+ for (MiningLocationLabel waypoint : ActiveWaypoints.values()) {
+ int waypointColor = waypoint.category().getColor();
+ Vector2ic renderPos = transformLocation(waypoint.centerPos().getX(), waypoint.centerPos().getZ());
int locationSize = SkyblockerConfigManager.get().mining.crystalsHud.locationSize;
- if (SMALL_LOCATIONS.contains(waypoint.name.getString())) {//if small location half the location size
+ if (SMALL_LOCATIONS.contains(waypoint.category().getName())) {//if small location half the location size
locationSize /= 2;
}
//fill square of size locationSize around the coordinates of the location
- context.fill(renderPos.x() - locationSize / 2, renderPos.y() - locationSize / 2, renderPos.x() + locationSize / 2, renderPos.y() + locationSize / 2, waypointColor.getRGB());
+ context.fill(renderPos.x() - locationSize / 2, renderPos.y() - locationSize / 2, renderPos.x() + locationSize / 2, renderPos.y() + locationSize / 2, waypointColor);
}
}
@@ -92,7 +92,6 @@ public class CrystalsHud {
if (CLIENT.player == null || CLIENT.getNetworkHandler() == null) {
return;
}
-
//get player location
double playerX = CLIENT.player.getX();
double playerZ = CLIENT.player.getZ();
@@ -109,8 +108,6 @@ public class CrystalsHud {
//draw marker on map
context.drawTexture(MAP_ICON, 0, 0, 2, 0, 5, 7, 8, 8);
-
- //todo add direction (can not work out how to rotate)
matrices.pop();
}
@@ -146,7 +143,6 @@ public class CrystalsHud {
/**
* Works out if the crystals map should be rendered and sets {@link CrystalsHud#visible} accordingly.
- *
*/
public static void update() {
if (CLIENT.player == null || CLIENT.getNetworkHandler() == null || !SkyblockerConfigManager.get().mining.crystalsHud.enabled) {
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 83167c18..22e494ab 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationsManager.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationsManager.java
@@ -21,16 +21,15 @@ import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
import net.minecraft.client.MinecraftClient;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.text.ClickEvent;
+import net.minecraft.text.HoverEvent;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Vec3d;
import org.slf4j.Logger;
-import java.awt.*;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -52,12 +51,15 @@ public class CrystalsLocationsManager {
private static final MinecraftClient CLIENT = MinecraftClient.getInstance();
/**
- * A look-up table to convert between location names and waypoint in the {@link CrystalsWaypoint.Category} values.
+ * A look-up table to convert between location names and waypoint in the {@link MiningLocationLabel.CrystalHollowsLocationsCategory} values.
*/
- private static final Map<String, CrystalsWaypoint.Category> WAYPOINT_LOCATIONS = Arrays.stream(CrystalsWaypoint.Category.values()).collect(Collectors.toMap(CrystalsWaypoint.Category::toString, Function.identity()));
- private static final Pattern TEXT_CWORDS_PATTERN = Pattern.compile("([0-9][0-9][0-9]) ([0-9][0-9][0-9]?) ([0-9][0-9][0-9])");
+ private static final Map<String, MiningLocationLabel.CrystalHollowsLocationsCategory> WAYPOINT_LOCATIONS = Arrays.stream(MiningLocationLabel.CrystalHollowsLocationsCategory.values()).collect(Collectors.toMap(MiningLocationLabel.CrystalHollowsLocationsCategory::getName, Function.identity()));
+ //Package-private for testing
+ static final Pattern TEXT_CWORDS_PATTERN = Pattern.compile("\\Dx?(\\d{3})(?=[, ]),? ?y?(\\d{2,3})(?=[, ]),? ?z?(\\d{3})\\D?(?!\\d)");
+ private static final int REMOVE_UNKNOWN_DISTANCE = 50;
- protected static Map<String, CrystalsWaypoint> activeWaypoints = new HashMap<>();
+ protected static Map<String, MiningLocationLabel> activeWaypoints = new HashMap<>();
+ protected static List<String> verifiedWaypoints = new ArrayList<>();
public static void init() {
// Crystal Hollows Waypoints
@@ -72,47 +74,65 @@ public class CrystalsLocationsManager {
}
private static void extractLocationFromMessage(Text message, Boolean overlay) {
- if (!SkyblockerConfigManager.get().mining.crystalsWaypoints.findInChat || !Utils.isInCrystalHollows()) {
+ if (!SkyblockerConfigManager.get().mining.crystalsWaypoints.findInChat || !Utils.isInCrystalHollows() || overlay) {
return;
}
-
+ String text = Formatting.strip(message.getString());
try {
- //get the message text
- String value = message.getString();
- Matcher matcher = TEXT_CWORDS_PATTERN.matcher(value);
- //if there are coordinates in the message try to get them and what they are talking about
- if (matcher.find()) {
- String location = matcher.group();
- int[] coordinates = Arrays.stream(location.split(" ", 3)).mapToInt(Integer::parseInt).toArray();
- BlockPos blockPos = new BlockPos(coordinates[0], coordinates[1], coordinates[2]);
-
- //if position is not in the hollows do not add it
- if (!checkInCrystals(blockPos)) {
- return;
- }
+ //make sure that it is only reading user messages and not from skyblocker
+ if (text.contains(":") && !text.startsWith(Constants.PREFIX.get().getString())) {
+ String userMessage = text.split(":", 2)[1];
+
+ //get the message text
+ Matcher matcher = TEXT_CWORDS_PATTERN.matcher(userMessage);
+ //if there are coordinates in the message try to get them and what they are talking about
+ if (matcher.find()) {
+ BlockPos blockPos = new BlockPos(Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)), Integer.parseInt(matcher.group(3)));
+ String location = blockPos.getX() + " " + blockPos.getY() + " " + blockPos.getZ();
+ //if position is not in the hollows do not add it
+ if (!checkInCrystals(blockPos)) {
+ return;
+ }
- //see if there is a name of a location to add to this
- for (String waypointLocation : WAYPOINT_LOCATIONS.keySet()) {
- if (value.toLowerCase().contains(waypointLocation.toLowerCase())) { //todo be more lenient
- //all data found to create waypoint
- addCustomWaypoint(waypointLocation, blockPos);
+ //see if there is a name of a location to add to this
+ for (String waypointLocation : WAYPOINT_LOCATIONS.keySet()) {
+ if (Arrays.stream(waypointLocation.toLowerCase().split(" ")).anyMatch(word -> userMessage.toLowerCase().contains(word))) { //check if contains a word of location
+ //all data found to create waypoint
+ //make sure the waypoint does not already exist in active waypoints, so waypoints can not get randomly moved
+ if (!activeWaypoints.containsKey(waypointLocation)) {
+ addCustomWaypoint(waypointLocation, blockPos);
+ }
+ return;
+ }
+ }
+
+ //if the location is not found ask the user for the location (could have been in a previous chat message)
+ if (CLIENT.player == null || CLIENT.getNetworkHandler() == null) {
return;
}
- }
- //if the location is not found ask the user for the location (could have been in a previous chat message)
- if (CLIENT.player == null || CLIENT.getNetworkHandler() == null) {
- return;
+ CLIENT.player.sendMessage(getLocationMenu(location, false), false);
}
-
- CLIENT.player.sendMessage(getLocationInputText(location), false);
}
+
} catch (Exception e) {
LOGGER.error("[Skyblocker Crystals Locations Manager] Encountered an exception while extracing a location from a chat message!", e);
}
+
+ //move waypoint to be more accurate based on locational chat messages if not already verifed
+ if (CLIENT.player != null && SkyblockerConfigManager.get().mining.crystalsWaypoints.enabled) {
+ for (MiningLocationLabel.CrystalHollowsLocationsCategory waypointLocation : WAYPOINT_LOCATIONS.values()) {
+ String waypointLinkedMessage = waypointLocation.getLinkedMessage();
+ String waypointName = waypointLocation.getName();
+ if (waypointLinkedMessage != null && text.contains(waypointLinkedMessage) && !verifiedWaypoints.contains(waypointName)) {
+ addCustomWaypoint(waypointLocation.getName(), CLIENT.player.getBlockPos());
+ verifiedWaypoints.add(waypointName);
+ }
+ }
+ }
}
- 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
@@ -122,16 +142,44 @@ public class CrystalsLocationsManager {
private static void registerWaypointLocationCommands(CommandDispatcher<FabricClientCommandSource> dispatcher, CommandRegistryAccess registryAccess) {
dispatcher.register(literal(SkyblockerMod.NAMESPACE)
.then(literal("crystalWaypoints")
- .then(argument("pos", ClientBlockPosArgumentType.blockPos())
+ .then(literal("add")
+ .executes(context -> {
+ if (CLIENT.player == null) {
+ return 0;
+ }
+ CLIENT.player.sendMessage(getLocationMenu((int) CLIENT.player.getX() + " " + (int) CLIENT.player.getY() + " " + (int) CLIENT.player.getZ(), true), false);
+ return Command.SINGLE_SUCCESS;
+ })
+ .then(argument("pos", ClientBlockPosArgumentType.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", ClientPosArgument.class)))
+ )
+ ))
+ .then(literal("share")
+ .executes(context -> {
+ if (CLIENT.player == null) {
+ return 0;
+ }
+ CLIENT.player.sendMessage(getPlacesMenu("share"), false);
+ return Command.SINGLE_SUCCESS;
+ })
.then(argument("place", StringArgumentType.greedyString())
.suggests((context, builder) -> suggestMatching(WAYPOINT_LOCATIONS.keySet(), builder))
- .executes(context -> addWaypointFromCommand(context.getSource(), getString(context, "place"), context.getArgument("pos", ClientPosArgument.class)))
+ .executes(context -> shareWaypoint(getString(context, "place")))
)
)
- .then(literal("share")
+ .then(literal("remove")
+ .executes(context -> {
+ if (CLIENT.player == null) {
+ return 0;
+ }
+ CLIENT.player.sendMessage(getPlacesMenu("remove"), false);
+ return Command.SINGLE_SUCCESS;
+ })
.then(argument("place", StringArgumentType.greedyString())
.suggests((context, builder) -> suggestMatching(WAYPOINT_LOCATIONS.keySet(), builder))
- .executes(context -> shareWaypoint(getString(context, "place")))
+ .executes(context -> removeWaypoint(getString(context, "place")))
)
)
)
@@ -139,21 +187,77 @@ public class CrystalsLocationsManager {
}
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;
- text.append(Text.literal(location).withColor(locationColor.getRGB()));
- text.append(Text.literal(" at : " + blockPos.getX() + " " + blockPos.getY() + " " + blockPos.getZ() + "."));
+ int locationColor = WAYPOINT_LOCATIONS.get(location).getColor();
- return text;
+ // Minecraft transforms all arguments (`%s`, `%d`, whatever) to `%$1s` DURING LOADING in `Language#load(InputStream, BiConsumer<String,String>)` for some unknown reason.
+ // And then `TranslatableTextContent#forEachPart` only accepts `%s` for some other unknown reason.
+ // So that's why the arguments are all `%s`. Wtf mojang?????????
+ return Constants.PREFIX.get().append(Text.translatableWithFallback("skyblocker.config.mining.crystalsWaypoints.addedWaypoint", "Added waypoint for '%s' at %s %s %s.", Text.literal(location).withColor(locationColor), blockPos.getX(), blockPos.getY(), blockPos.getZ()));
}
- private static Text getLocationInputText(String location) {
- MutableText text = Constants.PREFIX.get();
+ /**
+ * Creates a formated text with a list of possible places to add a waypoint for
+ *
+ * @param location the location where the waypoint will be created
+ * @param excludeUnknown if the {@link de.hysky.skyblocker.skyblock.dwarven.MiningLocationLabel.CrystalHollowsLocationsCategory#UNKNOWN Unknown} location should be available to add
+ * @return text for a message to send to the player
+ */
+ private static Text getLocationMenu(String location, boolean excludeUnknown) {
+
+ //if the user has all available waypoints active warn them instead of an empty list (excused unknown from check when disabled)
+ if (activeWaypoints.size() == WAYPOINT_LOCATIONS.size() || (excludeUnknown && WAYPOINT_LOCATIONS.size() - activeWaypoints.size() == 1 && !activeWaypoints.containsKey(MiningLocationLabel.CrystalHollowsLocationsCategory.UNKNOWN.getName()))) {
+ return Constants.PREFIX.get().append(Text.translatable("skyblocker.config.mining.crystalsWaypoints.allActive").formatted(Formatting.RED));
+ }
+
+ //add starting message
+ MutableText text = Text.empty();
+ //add possible locations to the message
for (String waypointLocation : WAYPOINT_LOCATIONS.keySet()) {
- Color locationColor = WAYPOINT_LOCATIONS.get(waypointLocation).color;
- text.append(Text.literal("[" + waypointLocation + "]").withColor(locationColor.getRGB()).styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/skyblocker crystalWaypoints " + location + " " + waypointLocation))));
+ //do not show option to add waypoints for existing locations or unknown if its disabled
+ if (activeWaypoints.containsKey(waypointLocation) || (excludeUnknown && Objects.equals(waypointLocation, MiningLocationLabel.CrystalHollowsLocationsCategory.UNKNOWN.getName()))) {
+ continue;
+ }
+ int locationColor = WAYPOINT_LOCATIONS.get(waypointLocation).getColor();
+ text.append(Text.literal("[" + waypointLocation + "]").withColor(locationColor).styled(style -> style
+ .withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/skyblocker crystalWaypoints add " + location + " " + waypointLocation))
+ .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.translatable("skyblocker.config.mining.crystalsWaypoints.getLocationHover.add").withColor(locationColor))))
+ );
+ }
+
+ return Constants.PREFIX.get().append(Text.translatable("skyblocker.config.mining.crystalsWaypoints.markLocation", location, text));
+ }
+
+ /**
+ * Creates a formated text with a list of found places to remove / share a waypoint for
+ *
+ * @param action the action the command should perform (remove / share)
+ * @return text for a message to send to the player
+ */
+ private static Text getPlacesMenu(String action) {
+ MutableText text = Constants.PREFIX.get();
+
+ //if the user has no active warn them instead of an empty list
+ if (activeWaypoints.isEmpty()) {
+ return text.append(Text.translatable("skyblocker.config.mining.crystalsWaypoints.noActive").formatted(Formatting.RED));
+ }
+
+ //depending on the action load the correct prefix and hover message
+ MutableText hoverMessage;
+ if (action.equals("remove")) {
+ text.append(Text.translatable("skyblocker.config.mining.crystalsWaypoints.getLocationHover.remove").append(Text.literal(": ")));
+ hoverMessage = Text.translatable("skyblocker.config.mining.crystalsWaypoints.getLocationHover.remove");
+ } else {
+ text.append(Text.translatable("skyblocker.config.mining.crystalsWaypoints.getLocationHover.share").append(Text.literal(": ")));
+ hoverMessage = Text.translatable("skyblocker.config.mining.crystalsWaypoints.getLocationHover.share");
+ }
+
+ for (String waypointLocation : activeWaypoints.keySet()) {
+ int locationColor = WAYPOINT_LOCATIONS.get(waypointLocation).getColor();
+ text.append(Text.literal("[" + waypointLocation + "]").withColor(locationColor).styled(style -> style
+ .withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/skyblocker crystalWaypoints " + action + " " + waypointLocation))
+ .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, hoverMessage.withColor(locationColor))))
+ );
}
return text;
@@ -178,8 +282,8 @@ public class CrystalsLocationsManager {
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());
+ Vec3d pos = activeWaypoints.get(place).centerPos();
+ MessageScheduler.INSTANCE.sendMessageAfterCooldown(Constants.PREFIX.get().getString() + " " + place + ": " + (int) pos.getX() + ", " + (int) pos.getY() + ", " + (int) pos.getZ());
} else {
//send fail message
if (CLIENT.player == null || CLIENT.getNetworkHandler() == null) {
@@ -191,25 +295,57 @@ public class CrystalsLocationsManager {
return Command.SINGLE_SUCCESS;
}
+ public static int removeWaypoint(String place) {
+ if (CLIENT.player == null || CLIENT.getNetworkHandler() == null) {
+ return 0;
+ }
+ if (activeWaypoints.containsKey(place)) {
+ CLIENT.player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.config.mining.crystalsWaypoints.removeSuccess").formatted(Formatting.GREEN)).append(Text.literal(place).withColor(WAYPOINT_LOCATIONS.get(place).getColor())), false);
+ activeWaypoints.remove(place);
+ verifiedWaypoints.remove(place);
+ } else {
+ //send fail message
+ CLIENT.player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.config.mining.crystalsWaypoints.removeFail").formatted(Formatting.RED)), false);
+ }
- private static void addCustomWaypoint(String waypointName, BlockPos pos) {
- CrystalsWaypoint.Category category = WAYPOINT_LOCATIONS.get(waypointName);
- CrystalsWaypoint waypoint = new CrystalsWaypoint(category, Text.literal(waypointName), pos);
+ return Command.SINGLE_SUCCESS;
+ }
+
+
+ protected static void addCustomWaypoint(String waypointName, BlockPos pos) {
+ removeUnknownNear(pos);
+ MiningLocationLabel.CrystalHollowsLocationsCategory category = WAYPOINT_LOCATIONS.get(waypointName);
+ MiningLocationLabel waypoint = new MiningLocationLabel(category, pos);
activeWaypoints.put(waypointName, waypoint);
}
+ /**
+ * Removes unknown waypoint from active waypoints if it's close to a location
+ *
+ * @param location center location
+ */
+ private static void removeUnknownNear(BlockPos location) {
+ String name = MiningLocationLabel.CrystalHollowsLocationsCategory.UNKNOWN.getName();
+ MiningLocationLabel unknownWaypoint = activeWaypoints.getOrDefault(name, null);
+ if (unknownWaypoint != null) {
+ double distance = unknownWaypoint.centerPos().distanceTo(location.toCenterPos());
+ if (distance < REMOVE_UNKNOWN_DISTANCE) {
+ activeWaypoints.remove(name);
+ }
+ }
+ }
+
public static void render(WorldRenderContext context) {
if (SkyblockerConfigManager.get().mining.crystalsWaypoints.enabled) {
- for (CrystalsWaypoint crystalsWaypoint : activeWaypoints.values()) {
- if (crystalsWaypoint.shouldRender()) {
- crystalsWaypoint.render(context);
- }
+ for (MiningLocationLabel crystalsWaypoint : activeWaypoints.values()) {
+ crystalsWaypoint.render(context);
}
}
}
private static void reset() {
activeWaypoints.clear();
+ verifiedWaypoints.clear();
}
public static void update() {
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsWaypoint.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsWaypoint.java
deleted file mode 100644
index dc40f82c..00000000
--- a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsWaypoint.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package de.hysky.skyblocker.skyblock.dwarven;
-
-import de.hysky.skyblocker.config.SkyblockerConfigManager;
-import de.hysky.skyblocker.config.configs.UIAndVisualsConfig;
-import de.hysky.skyblocker.utils.render.RenderHelper;
-import de.hysky.skyblocker.utils.waypoint.Waypoint;
-import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.entity.Entity;
-import net.minecraft.text.Text;
-import net.minecraft.util.DyeColor;
-import net.minecraft.util.Formatting;
-import net.minecraft.util.math.BlockPos;
-import net.minecraft.util.math.Vec3d;
-
-import java.awt.*;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-import java.util.function.ToDoubleFunction;
-
-public class CrystalsWaypoint extends Waypoint {
- private static final Supplier<UIAndVisualsConfig.Waypoints> CONFIG = () -> SkyblockerConfigManager.get().uiAndVisuals.waypoints;
- private static final Supplier<Type> TYPE_SUPPLIER = () -> CONFIG.get().waypointType;
- final Category category;
- final Text name;
- private final Vec3d centerPos;
-
- CrystalsWaypoint(Category category, Text name, BlockPos pos) {
- super(pos, TYPE_SUPPLIER, category.colorComponents);
- this.category = category;
- this.name = name;
- this.centerPos = pos.toCenterPos();
- }
-
- static ToDoubleFunction<CrystalsWaypoint> getSquaredDistanceToFunction(Entity entity) {
- return crystalsWaypoint -> entity.squaredDistanceTo(crystalsWaypoint.centerPos);
- }
-
- static Predicate<CrystalsWaypoint> getRangePredicate(Entity entity) {
- return crystalsWaypoint -> entity.squaredDistanceTo(crystalsWaypoint.centerPos) <= 36D;
- }
-
- @Override
- public boolean shouldRender() {
- return super.shouldRender();
- }
-
- @Override
- public boolean equals(Object obj) {
- return super.equals(obj) || obj instanceof CrystalsWaypoint other && category == other.category && name.equals(other.name) && pos.equals(other.pos);
- }
-
- /**
- * Renders the secret waypoint, including a waypoint through {@link Waypoint#render(WorldRenderContext)}, the name, and the distance from the player.
- */
- @Override
- public void render(WorldRenderContext context) {
- super.render(context);
-
- Vec3d posUp = centerPos.add(0, 1, 0);
- RenderHelper.renderText(context, name, posUp, true);
- double distance = context.camera().getPos().distanceTo(centerPos);
- RenderHelper.renderText(context, Text.literal(Math.round(distance) + "m").formatted(Formatting.YELLOW), posUp, 1, MinecraftClient.getInstance().textRenderer.fontHeight + 1, true);
-
- }
-
- /**
- * enum for the different waypoints used int the crystals hud each with a {@link Category#name} and associated {@link Category#color}
- */
- enum Category {
- JUNGLE_TEMPLE("Jungle Temple", new Color(DyeColor.PURPLE.getSignColor())),
- MINES_OF_DIVAN("Mines of Divan", Color.GREEN),
- GOBLIN_QUEENS_DEN("Goblin Queen's Den", new Color(DyeColor.ORANGE.getSignColor())),
- LOST_PRECURSOR_CITY("Lost Precursor City", Color.CYAN),
- KHAZAD_DUM("Khazad-dûm", Color.YELLOW),
- FAIRY_GROTTO("Fairy Grotto", Color.PINK),
- DRAGONS_LAIR("Dragon's Lair", Color.BLACK),
- CORLEONE("Corleone", Color.WHITE),
- KING_YOLKAR("King Yolkar", Color.RED),
- ODAWA("Odawa", Color.MAGENTA),
- KEY_GUARDIAN("Key Guardian", Color.LIGHT_GRAY);
-
- public final Color color;
- private final String name;
- private final float[] colorComponents;
-
- Category(String name, Color color) {
- this.name = name;
- this.color = color;
- this.colorComponents = color.getColorComponents(null);
- }
-
- @Override
- public String toString() {
- return name;
- }
- }
-}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/MetalDetector.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/MetalDetector.java
index 294b2c3d..ae45ff0b 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/MetalDetector.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/MetalDetector.java
@@ -4,6 +4,8 @@ import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.utils.Constants;
import de.hysky.skyblocker.utils.Utils;
import de.hysky.skyblocker.utils.render.RenderHelper;
+import de.hysky.skyblocker.utils.waypoint.NamedWaypoint;
+import de.hysky.skyblocker.utils.waypoint.Waypoint;
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.WorldRenderContext;
@@ -17,6 +19,7 @@ import net.minecraft.util.math.Box;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3i;
+import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -26,7 +29,7 @@ import java.util.regex.Pattern;
public class MetalDetector {
private static final MinecraftClient CLIENT = MinecraftClient.getInstance();
- private static final float[] LIGHT_GRAY = { 192 / 255f, 192 / 255f, 192 / 255f };
+ private static final float[] LIGHT_GRAY = {192 / 255f, 192 / 255f, 192 / 255f};
private static final Pattern TREASURE_PATTERN = Pattern.compile("(§3§lTREASURE: §b)(\\d+\\.?\\d?)m");
private static final Pattern KEEPER_PATTERN = Pattern.compile("Keeper of (\\w+)");
private static final Map<String, Vec3i> keeperOffsets = Map.of(
@@ -242,14 +245,14 @@ public class MetalDetector {
//only one location render just that and guiding line to it
if (possibleBlocks.size() == 1) {
Vec3i block = possibleBlocks.getFirst().add(0, -1, 0); //the block you are taken to is one block above the chest
- CrystalsWaypoint waypoint = new CrystalsWaypoint(CrystalsWaypoint.Category.CORLEONE, Text.translatable("skyblocker.dwarvenMines.metalDetectorHelper.treasure"), new BlockPos(block.getX(), block.getY(), block.getZ()));
+ NamedWaypoint waypoint = new NamedWaypoint(new BlockPos(block.getX(), block.getY(), block.getZ()), Text.translatable("skyblocker.dwarvenMines.metalDetectorHelper.treasure").getString(), Color.yellow.getColorComponents(null));
waypoint.render(context);
RenderHelper.renderLineFromCursor(context, Vec3d.ofCenter(block), LIGHT_GRAY, 1f, 5f);
return;
}
for (Vec3i block : possibleBlocks) {
- CrystalsWaypoint waypoint = new CrystalsWaypoint(CrystalsWaypoint.Category.CORLEONE, Text.translatable("skyblocker.dwarvenMines.metalDetectorHelper.possible"), new BlockPos(block.getX(), block.getY(), block.getZ()));
+ NamedWaypoint waypoint = new NamedWaypoint(new BlockPos(block.getX(), block.getY(), block.getZ()), Text.translatable("skyblocker.dwarvenMines.metalDetectorHelper.possible").getString(), Color.white.getColorComponents(null));
waypoint.render(context);
}
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/MiningLocationLabel.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/MiningLocationLabel.java
index 1f373b55..3817f6c7 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/MiningLocationLabel.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/MiningLocationLabel.java
@@ -1,15 +1,20 @@
package de.hysky.skyblocker.skyblock.dwarven;
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.Renderable;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import net.minecraft.client.MinecraftClient;
import net.minecraft.text.Text;
+import net.minecraft.util.DyeColor;
import net.minecraft.util.Formatting;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
+import java.awt.*;
+
+// TODO: Clean up into the waypoint system with a new `DistancedWaypoint` that extends `NamedWaypoint` for this and secret waypoints.
public record MiningLocationLabel(Category category, Vec3d centerPos) implements Renderable {
public MiningLocationLabel(Category category, BlockPos pos) {
this(category, pos.toCenterPos());
@@ -24,13 +29,16 @@ public record MiningLocationLabel(Category category, Vec3d centerPos) implements
/**
* Renders the name and distance to the label scaled so can be seen at a distance
+ *
* @param context render context
*/
@Override
public void render(WorldRenderContext context) {
Vec3d posUp = centerPos.add(0, 1, 0);
double distance = context.camera().getPos().distanceTo(centerPos);
- float scale = (float) (SkyblockerConfigManager.get().mining.commissionWaypoints.textScale * (distance / 10));
+ //set scale config based on if in crystals or not
+ float textScale = Utils.isInCrystalHollows() ? SkyblockerConfigManager.get().mining.crystalsWaypoints.textScale : SkyblockerConfigManager.get().mining.commissionWaypoints.textScale;
+ float scale = (float) (textScale * (distance / 10));
RenderHelper.renderText(context, getName(), posUp, scale, true);
RenderHelper.renderText(context, Text.literal(Math.round(distance) + "m").formatted(Formatting.YELLOW), posUp, scale, MinecraftClient.getInstance().textRenderer.fontHeight + 1, true);
}
@@ -154,4 +162,47 @@ public record MiningLocationLabel(Category category, Vec3d centerPos) implements
return color;
}
}
+
+ /**
+ * enum for the different waypoints used int the crystals hud each with a {@link CrystalHollowsLocationsCategory#name} and associated {@link CrystalHollowsLocationsCategory#color}
+ */
+ enum CrystalHollowsLocationsCategory implements Category {
+ UNKNOWN("Unknown", Color.WHITE, null), //used when a location is known but what's at the location is not known
+ JUNGLE_TEMPLE("Jungle Temple", new Color(DyeColor.PURPLE.getSignColor()), "[NPC] Kalhuiki Door Guardian:"),
+ MINES_OF_DIVAN("Mines of Divan", Color.GREEN, " Jade Crystal"),
+ GOBLIN_QUEENS_DEN("Goblin Queen's Den", new Color(DyeColor.ORANGE.getSignColor()), " Amber Crystal"),
+ LOST_PRECURSOR_CITY("Lost Precursor City", Color.CYAN, " Sapphire Crystal"),
+ KHAZAD_DUM("Khazad-dûm", Color.YELLOW, " Topaz Crystal"),
+ FAIRY_GROTTO("Fairy Grotto", Color.PINK, null),
+ DRAGONS_LAIR("Dragon's Lair", Color.BLACK, null),
+ CORLEONE("Corleone", Color.WHITE, null),
+ KING_YOLKAR("King Yolkar", Color.RED, "[NPC] King Yolkar:"),
+ ODAWA("Odawa", Color.MAGENTA, "[NPC] Odawa:"),
+ KEY_GUARDIAN("Key Guardian", Color.LIGHT_GRAY, null);
+
+ public final Color color;
+ private final String name;
+ private final String linkedMessage;
+
+ CrystalHollowsLocationsCategory(String name, Color color, String linkedMessage) {
+ this.name = name;
+ this.color = color;
+ this.linkedMessage = linkedMessage;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public int getColor() {
+ return this.color.getRGB();
+ }
+
+ public String getLinkedMessage() {
+ return this.linkedMessage;
+ }
+ }
+
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/WishingCompassSolver.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/WishingCompassSolver.java
new file mode 100644
index 00000000..7b14002b
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/WishingCompassSolver.java
@@ -0,0 +1,389 @@
+package de.hysky.skyblocker.skyblock.dwarven;
+
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListMgr;
+import de.hysky.skyblocker.utils.Constants;
+import de.hysky.skyblocker.utils.Utils;
+import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents;
+import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
+import net.fabricmc.fabric.api.event.player.UseBlockCallback;
+import net.fabricmc.fabric.api.event.player.UseItemCallback;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.item.ItemStack;
+import net.minecraft.network.packet.s2c.play.ParticleS2CPacket;
+import net.minecraft.particle.ParticleTypes;
+import net.minecraft.text.Text;
+import net.minecraft.util.ActionResult;
+import net.minecraft.util.Formatting;
+import net.minecraft.util.Hand;
+import net.minecraft.util.TypedActionResult;
+import net.minecraft.util.hit.BlockHitResult;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Box;
+import net.minecraft.util.math.Vec3d;
+import net.minecraft.world.World;
+import org.apache.commons.math3.geometry.euclidean.threed.Line;
+import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Stream;
+
+public class WishingCompassSolver {
+ private static final MinecraftClient CLIENT = MinecraftClient.getInstance();
+ private static final Map<Zone, Box> ZONE_BOUNDING_BOXES = Map.of(
+ Zone.CRYSTAL_NUCLEUS, new Box(462, 63, 461, 564, 181, 565),
+ Zone.JUNGLE, new Box(201, 63, 201, 513, 189, 513),
+ Zone.MITHRIL_DEPOSITS, new Box(512, 63, 201, 824, 189, 513),
+ Zone.GOBLIN_HOLDOUT, new Box(201, 63, 512, 513, 189, 824),
+ Zone.PRECURSOR_REMNANTS, new Box(512, 63, 512, 824, 189, 824),
+ Zone.MAGMA_FIELDS, new Box(201, 30, 201, 824, 64, 824)
+ );
+ private static final Vec3d JUNGLE_TEMPLE_DOOR_OFFSET = new Vec3d(-57, 36, -21);
+ /**
+ * The number of particles to use to get direction of a line
+ */
+ private static final long PARTICLES_PER_LINE = 25;
+ /**
+ * The time in milliseconds to wait for the next particle until assumed failed
+ */
+ private static final long PARTICLES_MAX_DELAY = 500;
+ /**
+ * The maximum distance a particle can be from the last to be considered part of the line
+ */
+ private static final double PARTICLES_MAX_DISTANCE = 0.9;
+ /**
+ * the distance squared the player has to be from where they used the first compass to where they use the second
+ */
+ private static final long DISTANCE_BETWEEN_USES = 64;
+
+ private static SolverStates currentState = SolverStates.NOT_STARTED;
+ private static Vec3d startPosOne = Vec3d.ZERO;
+ private static Vec3d startPosTwo = Vec3d.ZERO;
+ private static Vec3d directionOne = Vec3d.ZERO;
+ private static Vec3d directionTwo = Vec3d.ZERO;
+ private static long particleUsedCountOne = 0;
+ private static long particleUsedCountTwo = 0;
+ private static long particleLastUpdate = System.currentTimeMillis();
+ private static Vec3d particleLastPos = Vec3d.ZERO;
+
+
+ public static void init() {
+ UseItemCallback.EVENT.register(WishingCompassSolver::onItemInteract);
+ UseBlockCallback.EVENT.register(WishingCompassSolver::onBlockInteract);
+ ClientReceiveMessageEvents.GAME.register(WishingCompassSolver::failMessageListener);
+ ClientPlayConnectionEvents.JOIN.register((_handler, _sender, _client) -> reset());
+ }
+
+ /**
+ * When a filed message is sent in chat, reset the wishing compass solver to start
+ * @param text message
+ * @param b overlay
+ */
+ private static void failMessageListener(Text text, boolean b) {
+ if (!Utils.isInCrystalHollows()) {
+ return;
+ }
+ if (Formatting.strip(text.getString()).equals("The Wishing Compass can't seem to locate anything!")) {
+ currentState = SolverStates.NOT_STARTED;
+ }
+ }
+
+ private static void reset() {
+ currentState = SolverStates.NOT_STARTED;
+ startPosOne = Vec3d.ZERO;
+ startPosTwo = Vec3d.ZERO;
+ directionOne = Vec3d.ZERO;
+ directionTwo = Vec3d.ZERO;
+ particleUsedCountOne = 0;
+ particleUsedCountTwo = 0;
+ particleLastUpdate = System.currentTimeMillis();
+ particleLastPos = Vec3d.ZERO;
+ }
+
+ private static boolean isKingsScentPresent() {
+ String footer = PlayerListMgr.getFooter();
+ if (footer == null) {
+ return false;
+ }
+ return footer.contains("King's Scent I");
+ }
+
+ private static boolean isKeyInInventory() {
+ return CLIENT.player != null && CLIENT.player.getInventory().main.stream().anyMatch(stack -> stack != null && Objects.equals(stack.getSkyblockId(), "JUNGLE_KEY"));
+ }
+
+ private static Zone getZoneOfLocation(Vec3d location) {
+ return ZONE_BOUNDING_BOXES.entrySet().stream().filter(zone -> zone.getValue().contains(location)).findFirst().map(Map.Entry::getKey).orElse(Zone.CRYSTAL_NUCLEUS); //default to nucleus if somehow not in another zone
+ }
+
+ private static Boolean isZoneComplete(Zone zone) {
+ if (CLIENT.getNetworkHandler() == null || CLIENT.player == null) {
+ return false;
+ }
+
+ //make sure the data is in tab and if not tell the user
+ if (PlayerListMgr.getPlayerStringList().stream().noneMatch(entry -> entry.equals("Crystals:"))) {
+ CLIENT.player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.enableTabMessage")), false);
+ return false;
+ }
+
+ //return if the crystal for a zone is found
+ Stream<String> displayNameStream = PlayerListMgr.getPlayerStringList().stream();
+ return switch (zone) {
+ case JUNGLE -> displayNameStream.noneMatch(entry -> entry.equals("Amethyst: ✖ Not Found"));
+ case MITHRIL_DEPOSITS -> displayNameStream.noneMatch(entry -> entry.equals("Jade: ✖ Not Found"));
+ case GOBLIN_HOLDOUT -> displayNameStream.noneMatch(entry -> entry.equals("Amber: ✖ Not Found"));
+ case PRECURSOR_REMNANTS -> displayNameStream.noneMatch(entry -> entry.equals("Sapphire: ✖ Not Found"));
+ case MAGMA_FIELDS -> displayNameStream.noneMatch(entry -> entry.equals("Topaz: ✖ Not Found"));
+ default -> false;
+ };
+ }
+
+ private static MiningLocationLabel.CrystalHollowsLocationsCategory getTargetLocation(Zone startingZone) {
+ //if the zone is complete return null
+ if (isZoneComplete(startingZone)) {
+ return MiningLocationLabel.CrystalHollowsLocationsCategory.UNKNOWN;
+ }
+ return switch (startingZone) {
+ case JUNGLE -> isKeyInInventory() ? MiningLocationLabel.CrystalHollowsLocationsCategory.JUNGLE_TEMPLE : MiningLocationLabel.CrystalHollowsLocationsCategory.ODAWA;
+ case MITHRIL_DEPOSITS -> MiningLocationLabel.CrystalHollowsLocationsCategory.MINES_OF_DIVAN;
+ case GOBLIN_HOLDOUT -> isKingsScentPresent() ? MiningLocationLabel.CrystalHollowsLocationsCategory.GOBLIN_QUEENS_DEN : MiningLocationLabel.CrystalHollowsLocationsCategory.KING_YOLKAR;
+ case PRECURSOR_REMNANTS -> MiningLocationLabel.CrystalHollowsLocationsCategory.LOST_PRECURSOR_CITY;
+ case MAGMA_FIELDS -> MiningLocationLabel.CrystalHollowsLocationsCategory.KHAZAD_DUM;
+ default -> MiningLocationLabel.CrystalHollowsLocationsCategory.UNKNOWN;
+ };
+ }
+
+ /**
+ * Verifies that a location could be correct and not to far out of zone. This is a problem when areas sometimes do not exist and is not a perfect solution
+ * @param startingZone zone player is searching in
+ * @param pos location where the area should be
+ * @return corrected location
+ */
+ private static Boolean verifyLocation(Zone startingZone, Vec3d pos) {
+ return ZONE_BOUNDING_BOXES.get(startingZone).expand(100, 0, 100).contains(pos);
+ }
+
+ public static void onParticle(ParticleS2CPacket packet) {
+ if (!Utils.isInCrystalHollows() || !ParticleTypes.HAPPY_VILLAGER.equals(packet.getParameters().getType())) {
+ return;
+ }
+ //get location of particle
+ Vec3d particlePos = new Vec3d(packet.getX(), packet.getY(), packet.getZ());
+ //update particle used time
+ particleLastUpdate = System.currentTimeMillis();
+ //ignore particle not in the line
+ if (particlePos.distanceTo(particleLastPos) > PARTICLES_MAX_DISTANCE) {
+ return;
+ }
+ particleLastPos = particlePos;
+
+ switch (currentState) {
+ case PROCESSING_FIRST_USE -> {
+ Vec3d particleDirection = particlePos.subtract(startPosOne).normalize();
+ //move direction to fit with particle
+ directionOne = directionOne.add(particleDirection.multiply((double) 1 / PARTICLES_PER_LINE));
+ particleUsedCountOne += 1;
+ //if used enough particle go to next state
+ if (particleUsedCountOne >= PARTICLES_PER_LINE) {
+ currentState = SolverStates.WAITING_FOR_SECOND;
+ if (CLIENT.player != null) {
+ CLIENT.player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.wishingCompassUsedMessage").formatted(Formatting.GREEN)), false);
+ }
+ }
+ }
+ case PROCESSING_SECOND_USE -> {
+ Vec3d particleDirection = particlePos.subtract(startPosTwo).normalize();
+ //move direction to fit with particle
+ directionTwo = directionTwo.add(particleDirection.multiply((double) 1 / PARTICLES_PER_LINE));
+ particleUsedCountTwo += 1;
+ //if used enough particle go to next state
+ if (particleUsedCountTwo >= PARTICLES_PER_LINE) {
+ processSolution();
+ }
+ }
+ }
+ }
+
+ private static void processSolution() {
+ if (CLIENT.player == null) {
+ reset();
+ return;
+ }
+ Vec3d targetLocation = solve(startPosOne, startPosTwo, directionOne, directionTwo);
+ if (targetLocation == null) {
+ CLIENT.player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.somethingWentWrongMessage").formatted(Formatting.RED)), false);
+ } else {
+ //send message to player with location and name
+ Zone playerZone = getZoneOfLocation(startPosOne);
+ MiningLocationLabel.CrystalHollowsLocationsCategory location = getTargetLocation(playerZone);
+ //set to unknown if the target is to far from the region it's allowed to spawn in
+ if (!verifyLocation(playerZone, targetLocation)) {
+ location = MiningLocationLabel.CrystalHollowsLocationsCategory.UNKNOWN;
+ CLIENT.player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.targetLocationToFar").formatted(Formatting.RED)), false);
+ }
+ //offset the jungle location to its doors
+ if (location == MiningLocationLabel.CrystalHollowsLocationsCategory.JUNGLE_TEMPLE) {
+ targetLocation = targetLocation.add(JUNGLE_TEMPLE_DOOR_OFFSET);
+ }
+
+ CLIENT.player.sendMessage(Constants.PREFIX.get()
+ .append(Text.translatable("skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.foundMessage").formatted(Formatting.GREEN))
+ .append(Text.literal(location.getName()).withColor(location.getColor()))
+ .append(Text.literal(": " + (int) targetLocation.getX() + " " + (int) targetLocation.getY() + " " + (int) targetLocation.getZ())),
+ false);
+
+ //add waypoint
+ CrystalsLocationsManager.addCustomWaypoint(location.getName(), BlockPos.ofFloored(targetLocation));
+ }
+
+ //reset ready for another go
+ reset();
+ }
+
+ /**
+ * using the stating locations and line direction solve for where the location must be
+ */
+ protected static Vec3d solve(Vec3d startPosOne, Vec3d startPosTwo, Vec3d directionOne, Vec3d directionTwo) {
+ //convert format to get lines for the intersection solving
+ Vector3D lineOneStart = new Vector3D(startPosOne.x, startPosOne.y, startPosOne.z);
+ Vector3D lineOneEnd = new Vector3D(directionOne.x, directionOne.y, directionOne.z).add(lineOneStart);
+ Vector3D lineTwoStart = new Vector3D(startPosTwo.x, startPosTwo.y, startPosTwo.z);
+ Vector3D lineTwoEnd = new Vector3D(directionTwo.x, directionTwo.y, directionTwo.z).add(lineTwoStart);
+ Line line = new Line(lineOneStart, lineOneEnd, 1);
+ Line lineTwo = new Line(lineTwoStart, lineTwoEnd, 1);
+ Vector3D intersection = line.intersection(lineTwo);
+
+ //return final target location
+ if (intersection == null || intersection.equals(new Vector3D(0, 0, 0))) {
+ return null;
+ }
+ return new Vec3d(intersection.getX(), intersection.getY(), intersection.getZ());
+ }
+
+ private static ActionResult onBlockInteract(PlayerEntity playerEntity, World world, Hand hand, BlockHitResult blockHitResult) {
+ if (CLIENT.player == null) {
+ return null;
+ }
+ ItemStack stack = CLIENT.player.getStackInHand(hand);
+ //make sure the user is in the crystal hollows and holding the wishing compass
+ if (!Utils.isInCrystalHollows() || !SkyblockerConfigManager.get().mining.crystalsWaypoints.wishingCompassSolver || !Objects.equals(stack.getSkyblockId(), "WISHING_COMPASS")) {
+ return ActionResult.PASS;
+ }
+ if (useCompass()) {
+ return ActionResult.FAIL;
+ }
+
+ return ActionResult.PASS;
+ }
+
+ private static TypedActionResult<ItemStack> onItemInteract(PlayerEntity playerEntity, World world, Hand hand) {
+ if (CLIENT.player == null) {
+ return null;
+ }
+ ItemStack stack = CLIENT.player.getStackInHand(hand);
+ //make sure the user is in the crystal hollows and holding the wishing compass
+ if (!Utils.isInCrystalHollows() || !SkyblockerConfigManager.get().mining.crystalsWaypoints.wishingCompassSolver || !Objects.equals(stack.getSkyblockId(), "WISHING_COMPASS")) {
+ return TypedActionResult.pass(stack);
+ }
+ if (useCompass()) {
+ return TypedActionResult.fail(stack);
+ }
+
+ return TypedActionResult.pass(stack);
+ }
+
+ /**
+ * Computes what to do next when a compass is used.
+ *
+ * @return if the use event should be canceled
+ */
+ private static boolean useCompass() {
+ if (CLIENT.player == null) {
+ return true;
+ }
+ Vec3d playerPos = CLIENT.player.getEyePos();
+ Zone currentZone = getZoneOfLocation(playerPos);
+
+ switch (currentState) {
+ case NOT_STARTED -> {
+ //do not start if the player is in nucleus as this does not work well
+ if (currentZone == Zone.CRYSTAL_NUCLEUS) {
+ CLIENT.player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.useOutsideNucleusMessage")), false);
+ return true;
+ }
+ startNewState(SolverStates.PROCESSING_FIRST_USE);
+ }
+
+ case WAITING_FOR_SECOND -> {
+ //only continue if the player is far enough away from the first position to get a better reading
+ if (startPosOne.squaredDistanceTo(playerPos) < DISTANCE_BETWEEN_USES) {
+ CLIENT.player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.moveFurtherMessage")), false);
+ return true;
+ } else {
+ //make sure the player is in the same zone as they used to first or restart
+ if (currentZone != getZoneOfLocation(startPosOne)) {
+ CLIENT.player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.changingZoneMessage")), false);
+ reset();
+ startNewState(SolverStates.PROCESSING_FIRST_USE);
+ } else {
+ startNewState(SolverStates.PROCESSING_SECOND_USE);
+ }
+ }
+ }
+
+ case PROCESSING_FIRST_USE, PROCESSING_SECOND_USE -> {
+ //if still looking for particles for line tell the user to wait
+ //else tell the user something went wrong and its starting again
+ if (System.currentTimeMillis() - particleLastUpdate < PARTICLES_MAX_DELAY) {
+ CLIENT.player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.waitLongerMessage").formatted(Formatting.RED)), false);
+ return true;
+ } else {
+ CLIENT.player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.couldNotDetectLastUseMessage").formatted(Formatting.RED)), false);
+ reset();
+ startNewState(SolverStates.PROCESSING_FIRST_USE);
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static void startNewState(SolverStates newState) {
+ if (CLIENT.player == null) {
+ return;
+ }
+ //get where eye pos independent of if player is crouching
+ Vec3d playerPos = CLIENT.player.getPos().add(0, 1.62, 0);
+
+ if (newState == SolverStates.PROCESSING_FIRST_USE) {
+ currentState = SolverStates.PROCESSING_FIRST_USE;
+ startPosOne = playerPos;
+ particleLastUpdate = System.currentTimeMillis();
+ particleLastPos = playerPos;
+ } else if (newState == SolverStates.PROCESSING_SECOND_USE) {
+ currentState = SolverStates.PROCESSING_SECOND_USE;
+ startPosTwo = playerPos;
+ particleLastUpdate = System.currentTimeMillis();
+ particleLastPos = playerPos;
+ }
+ }
+
+ private enum SolverStates {
+ NOT_STARTED,
+ PROCESSING_FIRST_USE,
+ WAITING_FOR_SECOND,
+ PROCESSING_SECOND_USE,
+ }
+
+ private enum Zone {
+ CRYSTAL_NUCLEUS,
+ JUNGLE,
+ MITHRIL_DEPOSITS,
+ GOBLIN_HOLDOUT,
+ PRECURSOR_REMNANTS,
+ MAGMA_FIELDS,
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/experiment/ChronomatronSolver.java b/src/main/java/de/hysky/skyblocker/skyblock/experiment/ChronomatronSolver.java
index 308452ef..a4d34a1b 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/experiment/ChronomatronSolver.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/experiment/ChronomatronSolver.java
@@ -103,7 +103,7 @@ public final class ChronomatronSolver extends ExperimentSolver {
}
@Override
- protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) {
+ public List<ColorHighlight> getColors(Int2ObjectMap<ItemStack> slots) {
List<ColorHighlight> highlights = new ArrayList<>();
if (getState() == State.SHOW && chronomatronSlots.size() > chronomatronCurrentOrdinal) {
for (Int2ObjectMap.Entry<ItemStack> indexStack : slots.int2ObjectEntrySet()) {
@@ -119,8 +119,7 @@ public final class ChronomatronSolver extends ExperimentSolver {
}
@Override
- protected void reset() {
- super.reset();
+ public void reset() {
chronomatronSlots.clear();
chronomatronChainLengthCount = 0;
chronomatronCurrentSlot = 0;
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/experiment/ExperimentSolver.java b/src/main/java/de/hysky/skyblocker/skyblock/experiment/ExperimentSolver.java
index ad2800e0..8d9b8311 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/experiment/ExperimentSolver.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/experiment/ExperimentSolver.java
@@ -2,16 +2,18 @@ package de.hysky.skyblocker.skyblock.experiment;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.config.configs.HelperConfig;
-import de.hysky.skyblocker.utils.render.gui.ContainerSolver;
+import de.hysky.skyblocker.utils.container.SimpleContainerSolver;
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
import net.minecraft.item.ItemStack;
+import org.intellij.lang.annotations.Language;
+import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
-public sealed abstract class ExperimentSolver extends ContainerSolver permits ChronomatronSolver, SuperpairsSolver, UltrasequencerSolver {
+public abstract sealed class ExperimentSolver extends SimpleContainerSolver permits ChronomatronSolver, SuperpairsSolver, UltrasequencerSolver {
public enum State {
REMEMBER, WAIT, SHOW, END
}
@@ -19,7 +21,7 @@ public sealed abstract class ExperimentSolver extends ContainerSolver permits Ch
private State state = State.REMEMBER;
private final Map<Integer, ItemStack> slots = new HashMap<>();
- protected ExperimentSolver(String containerName) {
+ protected ExperimentSolver(@NotNull @Language("RegExp") String containerName) {
super(containerName);
}
@@ -36,22 +38,20 @@ public sealed abstract class ExperimentSolver extends ContainerSolver permits Ch
}
@Override
- protected final boolean isEnabled() {
+ public final boolean isEnabled() {
return isEnabled(SkyblockerConfigManager.get().helpers.experiments);
}
protected abstract boolean isEnabled(HelperConfig.Experiments experimentsConfig);
@Override
- protected void start(GenericContainerScreen screen) {
- super.start(screen);
+ public void start(GenericContainerScreen screen) {
state = State.REMEMBER;
ScreenEvents.afterTick(screen).register(this::tick);
}
@Override
- protected void reset() {
- super.reset();
+ public void reset() {
state = State.REMEMBER;
slots.clear();
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/experiment/SuperpairsSolver.java b/src/main/java/de/hysky/skyblocker/skyblock/experiment/SuperpairsSolver.java
index 5c2ed152..f2d4c55d 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/experiment/SuperpairsSolver.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/experiment/SuperpairsSolver.java
@@ -33,14 +33,12 @@ public final class SuperpairsSolver extends ExperimentSolver {
}
@Override
- protected void start(GenericContainerScreen screen) {
- super.start(screen);
+ public void start(GenericContainerScreen screen) {
setState(State.SHOW);
}
@Override
- protected void reset() {
- super.reset();
+ public void reset() {
superpairsPrevClickedSlot = 0;
superpairsCurrentSlot = null;
superpairsDuplicatedSlots.clear();
@@ -63,7 +61,7 @@ public final class SuperpairsSolver extends ExperimentSolver {
}
@Override
- protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> displaySlots) {
+ public List<ColorHighlight> getColors(Int2ObjectMap<ItemStack> displaySlots) {
List<ColorHighlight> highlights = new ArrayList<>();
if (getState() == State.SHOW) {
for (Int2ObjectMap.Entry<ItemStack> indexStack : displaySlots.int2ObjectEntrySet()) {
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/experiment/UltrasequencerSolver.java b/src/main/java/de/hysky/skyblocker/skyblock/experiment/UltrasequencerSolver.java
index a4d1e4b6..f39c1ffe 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/experiment/UltrasequencerSolver.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/experiment/UltrasequencerSolver.java
@@ -2,6 +2,7 @@ package de.hysky.skyblocker.skyblock.experiment;
import de.hysky.skyblocker.config.configs.HelperConfig;
import de.hysky.skyblocker.utils.render.gui.ColorHighlight;
+import de.hysky.skyblocker.utils.container.ContainerSolver;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
@@ -55,7 +56,7 @@ public final class UltrasequencerSolver extends ExperimentSolver {
case WAIT -> {
if (genericContainerScreen.getScreenHandler().getInventory().getStack(49).getName().getString().startsWith("Timer: ")) {
setState(State.SHOW);
- markHighlightsDirty();
+ ContainerSolver.markHighlightsDirty();
}
}
case END -> {
@@ -76,7 +77,7 @@ public final class UltrasequencerSolver extends ExperimentSolver {
}
@Override
- protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) {
+ public List<ColorHighlight> getColors(Int2ObjectMap<ItemStack> slots) {
return getState() == State.SHOW && ultrasequencerNextSlot != 0 ? List.of(ColorHighlight.green(ultrasequencerNextSlot)) : new ArrayList<>();
}
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SimpleSlotTextAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SimpleSlotTextAdder.java
new file mode 100644
index 00000000..205e48d8
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SimpleSlotTextAdder.java
@@ -0,0 +1,39 @@
+package de.hysky.skyblocker.skyblock.item.slottext;
+
+import de.hysky.skyblocker.utils.container.RegexContainerMatcher;
+import de.hysky.skyblocker.utils.container.SlotTextAdder;
+import org.intellij.lang.annotations.Language;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.regex.Pattern;
+
+/**
+ * Simple implementation of a slot text adder.
+ * Extend this class and add it to {@link SlotTextManager#adders} to add text to any arbitrary slot.
+ */
+public abstract class SimpleSlotTextAdder extends RegexContainerMatcher implements SlotTextAdder {
+ /**
+ * Utility constructor that will compile the given string into a pattern.
+ *
+ * @see #SimpleSlotTextAdder(Pattern)
+ */
+ protected SimpleSlotTextAdder(@NotNull @Language("RegExp") String titlePattern) {
+ super(titlePattern);
+ }
+
+ /**
+ * Creates a SlotTextAdder that will be applied to screens with titles that match the given pattern.
+ *
+ * @param titlePattern The pattern to match the screen title against.
+ */
+ protected SimpleSlotTextAdder(@NotNull Pattern titlePattern) {
+ super(titlePattern);
+ }
+
+ /**
+ * Creates a SlotTextAdder that will be applied to all screens.
+ */
+ protected SimpleSlotTextAdder() {
+ super();
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextAdder.java
deleted file mode 100644
index 71d9aa30..00000000
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextAdder.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package de.hysky.skyblocker.skyblock.item.slottext;
-
-import de.hysky.skyblocker.config.SkyblockerConfigManager;
-import de.hysky.skyblocker.utils.render.gui.AbstractContainerMatcher;
-import net.minecraft.screen.slot.Slot;
-import org.intellij.lang.annotations.Language;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.List;
-import java.util.regex.Pattern;
-
-/**
- * Extend this class and add it to {@link SlotTextManager#adders} to add text to any arbitrary slot.
- */
-public abstract class SlotTextAdder extends AbstractContainerMatcher {
- /**
- * Utility constructor that will compile the given string into a pattern.
- *
- * @see #SlotTextAdder(Pattern)
- */
- protected SlotTextAdder(@NotNull @Language("RegExp") String titlePattern) {
- super(titlePattern);
- }
-
- /**
- * Creates a SlotTextAdder that will be applied to screens with titles that match the given pattern.
- *
- * @param titlePattern The pattern to match the screen title against.
- */
- protected SlotTextAdder(@NotNull Pattern titlePattern) {
- super(titlePattern);
- }
-
- /**
- * Creates a SlotTextAdder that will be applied to all screens.
- */
- protected SlotTextAdder() {
- super();
- }
-
- /**
- * This method will be called for each rendered slot. Consider using a switch statement on {@link Slot#id} if you wish to add different text to different slots.
- *
- * @return A list of positioned text to be rendered. Return {@link List#of()} if no text should be rendered.
- * @implNote By minecraft's design, scaled text inexplicably moves around.
- * So, limit your text to 3 characters (or roughly less than 20 width) if you want it to not look horrible.
- */
- public abstract @NotNull List<SlotText> getText(Slot slot);
-
- /**
- * Override this method to add conditions to enable or disable this adder.
- * @return Whether this adder is enabled.
- * @implNote The slot text adders only work while in skyblock, so no need to check for that again.
- */
- public boolean isEnabled() {
- return SkyblockerConfigManager.get().general.itemInfoDisplay.slotText;
- }
-}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextManager.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextManager.java
index aa9bf939..a28e204c 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextManager.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextManager.java
@@ -1,13 +1,23 @@
package de.hysky.skyblocker.skyblock.item.slottext;
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.skyblock.bazaar.BazaarHelper;
import de.hysky.skyblocker.skyblock.item.slottext.adders.*;
import de.hysky.skyblocker.utils.Utils;
+import de.hysky.skyblocker.utils.container.SlotTextAdder;
+import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
-import net.minecraft.client.gui.screen.Screen;
+import net.fabricmc.fabric.api.client.screen.v1.ScreenKeyboardEvents;
+import net.minecraft.client.font.TextRenderer;
+import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
+import net.minecraft.client.option.KeyBinding;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.lwjgl.glfw.GLFW;
import java.util.ArrayList;
import java.util.List;
@@ -35,24 +45,35 @@ public class SlotTextManager {
new StatsTuningAdder()
};
private static final ArrayList<SlotTextAdder> currentScreenAdders = new ArrayList<>();
+ private static final KeyBinding keyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding("key.skyblocker.slottext", GLFW.GLFW_KEY_LEFT_ALT, "key.categories.skyblocker"));
+ private static boolean keyHeld = false;
private SlotTextManager() {
}
public static void init() {
ScreenEvents.AFTER_INIT.register((client, screen, width, height) -> {
- if (screen instanceof HandledScreen<?> && Utils.isOnSkyblock()) {
- onScreenChange(screen);
+ if (screen instanceof HandledScreen<?> handledScreen && Utils.isOnSkyblock()) {
+ onScreenChange(handledScreen);
ScreenEvents.remove(screen).register(ignored -> currentScreenAdders.clear());
}
+ ScreenKeyboardEvents.afterKeyPress(screen).register((screen1, key, scancode, modifiers) -> {
+ if (keyBinding.matchesKey(key, scancode)) {
+ SkyblockerConfigManager.get().general.itemInfoDisplay.slotTextToggled = !SkyblockerConfigManager.get().general.itemInfoDisplay.slotTextToggled;
+ keyHeld = true;
+ }
+ });
+ ScreenKeyboardEvents.afterKeyRelease(screen).register((screen1, key, scancode, modifiers) -> {
+ if (keyBinding.matchesKey(key, scancode)) {
+ keyHeld = false;
+ }
+ });
});
}
- private static void onScreenChange(Screen screen) {
- final String title = screen.getTitle().getString();
+ private static void onScreenChange(HandledScreen<?> screen) {
for (SlotTextAdder adder : adders) {
- if (!adder.isEnabled()) continue;
- if (adder.titlePattern == null || adder.titlePattern.matcher(title).find()) {
+ if (adder.isEnabled() && adder.test(screen)) {
currentScreenAdders.add(adder);
}
}
@@ -66,12 +87,54 @@ public class SlotTextManager {
* The order of the adders remains the same as they were added to the {@link SlotTextManager#adders} array.
*/
@NotNull
- public static List<SlotText> getText(Slot slot) {
- if (currentScreenAdders.isEmpty()) return List.of();
+ public static List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
+ if (currentScreenAdders.isEmpty() || !isEnabled()) return List.of();
for (SlotTextAdder adder : currentScreenAdders) {
- List<SlotText> text = adder.getText(slot);
+ List<SlotText> text = adder.getText(slot, stack, slotId);
if (!text.isEmpty()) return text;
}
return List.of();
}
+
+ public static void renderSlotText(DrawContext context, TextRenderer textRenderer, @NotNull Slot slot) {
+ renderSlotText(context, textRenderer, slot, slot.getStack(), slot.id, slot.x, slot.y);
+ }
+
+ public static void renderSlotText(DrawContext context, TextRenderer textRenderer, @Nullable Slot slot, ItemStack stack, int slotId, int x, int y) {
+ List<SlotText> textList = getText(slot, stack, slotId);
+ if (textList.isEmpty()) return;
+ MatrixStack matrices = context.getMatrices();
+
+ for (SlotText slotText : textList) {
+ matrices.push();
+ matrices.translate(0.0f, 0.0f, 200.0f);
+ int length = textRenderer.getWidth(slotText.text());
+ if (length > 16) {
+ matrices.scale(16f / length, 16f / length, 1.0f);
+ switch (slotText.position()) {
+ case TOP_LEFT, TOP_RIGHT -> matrices.translate(x * length / 16f - x, (y * length / 16.0f) - y, 0.0f);
+ case BOTTOM_LEFT, BOTTOM_RIGHT -> matrices.translate(x * length / 16f - x, ((y + 16f - textRenderer.fontHeight + 2f + 0.7f) * length / 16.0f) - y, 0.0f);
+ }
+ } else {
+ switch (slotText.position()) {
+ case TOP_LEFT -> { /*Do Nothing*/ }
+ case TOP_RIGHT -> matrices.translate(16f - length, 0.0f, 0.0f);
+ case BOTTOM_LEFT -> matrices.translate(0.0f, 16f - textRenderer.fontHeight + 2f, 0.0f);
+ case BOTTOM_RIGHT -> matrices.translate(16f - length, 16f - textRenderer.fontHeight + 2f, 0.0f);
+ }
+ }
+ context.drawText(textRenderer, slotText.text(), x, y, 0xFFFFFF, true);
+ matrices.pop();
+ }
+ }
+
+ public static boolean isEnabled() {
+ return switch (SkyblockerConfigManager.get().general.itemInfoDisplay.slotTextMode) {
+ case ENABLED -> true;
+ case DISABLED -> false;
+ case PRESS_TO_TOGGLE -> SkyblockerConfigManager.get().general.itemInfoDisplay.slotTextToggled;
+ case HOLD_TO_HIDE -> !keyHeld;
+ case HOLD_TO_SHOW -> keyHeld;
+ };
+ }
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextMode.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextMode.java
new file mode 100644
index 00000000..1f043888
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/SlotTextMode.java
@@ -0,0 +1,23 @@
+package de.hysky.skyblocker.skyblock.item.slottext;
+
+/**
+ * Used in {@link SlotTextManager#isEnabled()} to determine whether the slot text should be shown or not.
+ */
+public enum SlotTextMode {
+ ENABLED,
+ HOLD_TO_SHOW,
+ PRESS_TO_TOGGLE,
+ HOLD_TO_HIDE,
+ DISABLED;
+
+ @Override
+ public String toString() {
+ return switch (this) {
+ case ENABLED -> "Enabled";
+ case HOLD_TO_SHOW -> "Hold to Show";
+ case PRESS_TO_TOGGLE -> "Press to Toggle";
+ case HOLD_TO_HIDE -> "Hold to Hide";
+ case DISABLED -> "Disabled";
+ };
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/TextPosition.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/TextPosition.java
index 052b228d..59f5e7e8 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/TextPosition.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/TextPosition.java
@@ -1,5 +1,8 @@
package de.hysky.skyblocker.skyblock.item.slottext;
+/**
+ * Used in {@link SlotText#position} to determine where the slot text should be rendered.
+ */
public enum TextPosition {
TOP_LEFT,
TOP_RIGHT,
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/AttributeShardAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/AttributeShardAdder.java
index eac0a7f0..27856ab8 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/AttributeShardAdder.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/AttributeShardAdder.java
@@ -2,7 +2,7 @@ package de.hysky.skyblocker.skyblock.item.slottext.adders;
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.skyblock.item.slottext.SimpleSlotTextAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
@@ -10,12 +10,12 @@ import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
-import net.minecraft.util.Formatting;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
-public class AttributeShardAdder extends SlotTextAdder {
+public class AttributeShardAdder extends SimpleSlotTextAdder {
private static final Object2ObjectMap<String, String> ID_2_SHORT_NAME = new Object2ObjectOpenHashMap<>();
static {
@@ -70,8 +70,7 @@ public class AttributeShardAdder extends SlotTextAdder {
}
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- final ItemStack stack = slot.getStack();
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
NbtCompound customData = ItemUtils.getCustomData(stack);
if (!ItemUtils.getItemId(stack).equals("ATTRIBUTE_SHARD")) return List.of();
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/CatacombsLevelAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/CatacombsLevelAdder.java
index 6c99ebf9..ce0e3872 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/CatacombsLevelAdder.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/CatacombsLevelAdder.java
@@ -1,7 +1,7 @@
package de.hysky.skyblocker.skyblock.item.slottext.adders;
import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
-import de.hysky.skyblocker.skyblock.item.slottext.SlotTextAdder;
+import de.hysky.skyblocker.skyblock.item.slottext.SimpleSlotTextAdder;
import de.hysky.skyblocker.utils.RomanNumerals;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
@@ -9,6 +9,7 @@ import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import org.apache.commons.lang3.math.NumberUtils;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.regex.Matcher;
@@ -20,17 +21,17 @@ public class CatacombsLevelAdder {
private CatacombsLevelAdder() {
}
- public static class Dungeoneering extends SlotTextAdder {
+ public static class Dungeoneering extends SimpleSlotTextAdder {
private static final Pattern LEVEL_PATTERN = Pattern.compile(".*?(?:(?<arabic>\\d+)|(?<roman>\\S+))? ?✯?");
public Dungeoneering() {
super("^Dungeoneering");
}
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- switch (slot.id) {
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
+ switch (slotId) {
case 12, 29, 30, 31, 32, 33 -> {
- Matcher matcher = LEVEL_PATTERN.matcher(slot.getStack().getName().getString());
+ Matcher matcher = LEVEL_PATTERN.matcher(stack.getName().getString());
if (!matcher.matches()) return List.of();
String arabic = matcher.group("arabic");
String roman = matcher.group("roman");
@@ -53,17 +54,17 @@ public class CatacombsLevelAdder {
}
}
- public static class DungeonClasses extends SlotTextAdder {
+ public static class DungeonClasses extends SimpleSlotTextAdder {
public DungeonClasses() {
super("^Dungeon Classes"); //Applies to both screens as they are same in both the placement and the style of the level text.
}
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- switch (slot.id) {
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
+ switch (slotId) {
case 11, 12, 13, 14, 15 -> {
- String level = getBracketedLevelFromName(slot.getStack());
+ String level = getBracketedLevelFromName(stack);
if (!NumberUtils.isDigits(level)) return List.of();
return List.of(SlotText.bottomLeft(Text.literal(level).withColor(0xFFDDC1)));
}
@@ -74,17 +75,17 @@ public class CatacombsLevelAdder {
}
}
- public static class ReadyUp extends SlotTextAdder {
+ public static class ReadyUp extends SimpleSlotTextAdder {
public ReadyUp() {
super("^Ready Up");
}
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- switch (slot.id) {
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
+ switch (slotId) {
case 29, 30, 31, 32, 33 -> {
- String level = getBracketedLevelFromName(slot.getStack());
+ String level = getBracketedLevelFromName(stack);
if (!NumberUtils.isDigits(level)) return List.of();
return List.of(SlotText.bottomLeft(Text.literal(level).withColor(0xFFDDC1)));
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/CollectionAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/CollectionAdder.java
index d6ced22a..66d7f6e1 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/CollectionAdder.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/CollectionAdder.java
@@ -1,19 +1,20 @@
package de.hysky.skyblocker.skyblock.item.slottext.adders;
import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
-import de.hysky.skyblocker.skyblock.item.slottext.SlotTextAdder;
+import de.hysky.skyblocker.skyblock.item.slottext.SimpleSlotTextAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.RomanNumerals;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class CollectionAdder extends SlotTextAdder {
+public class CollectionAdder extends SimpleSlotTextAdder {
private static final Pattern COLLECTION = Pattern.compile("^[\\w ]+ (?<level>[IVXLCDM]+)$");
public CollectionAdder() {
@@ -21,8 +22,7 @@ public class CollectionAdder extends SlotTextAdder {
}
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- final ItemStack stack = slot.getStack();
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
Matcher matcher = COLLECTION.matcher(stack.getName().getString());
if (matcher.matches()) {
int level = RomanNumerals.romanToDecimal(matcher.group("level"));
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/CommunityShopAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/CommunityShopAdder.java
index d94d6405..4450c0b3 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/CommunityShopAdder.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/CommunityShopAdder.java
@@ -1,7 +1,7 @@
package de.hysky.skyblocker.skyblock.item.slottext.adders;
import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
-import de.hysky.skyblocker.skyblock.item.slottext.SlotTextAdder;
+import de.hysky.skyblocker.skyblock.item.slottext.SimpleSlotTextAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.RomanNumerals;
import net.minecraft.item.ItemStack;
@@ -10,51 +10,50 @@ import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
-public class CommunityShopAdder extends SlotTextAdder {
+public class CommunityShopAdder extends SimpleSlotTextAdder {
private static final byte CATEGORIES_START = 10;
private static final byte CATEGORIES_END = 14; //Inclusive
+ private static byte currentScreen = -1; // 0 = city projects, 1 = upgrades, 2 = booster cookie, 3 = bits shop, 4 = fire sales, any other number = invalid
public CommunityShopAdder() {
super("^Community Shop");
}
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- for (byte i = CATEGORIES_START; i <= CATEGORIES_END; i++) {
- if (slot.inventory.getStack(i).isOf(Items.LIME_STAINED_GLASS_PANE)) { //Only the selected category has a lime stained glass pane, the others have a gray one.
- return switch (i) { //This is a switch to allow adding more categories easily in the future, if we ever add more.
- case 11 -> getTextForUpgradesScreen(slot);
- default -> List.of();
- };
- }
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
+ if (slotId >= CATEGORIES_START && slotId <= CATEGORIES_END && stack.isOf(Items.LIME_STAINED_GLASS_PANE)) { //Only the selected category has a lime stained glass pane, the others have a gray one.
+ currentScreen = (byte) (slotId - CATEGORIES_START);
+ return List.of();
}
- return List.of();
+ return switch (currentScreen) { //This is a switch statement to allow easily adding other categories in the future.
+ case 1 -> getTextForUpgradesScreen(stack, slotId);
+ default -> List.of();
+ };
}
- private static List<SlotText> getTextForUpgradesScreen(Slot slot) {
- final ItemStack stack = slot.getStack();
- switch (slot.id) {
- case 30, 31, 32, 33, 34, 38, 39, 40, 41, 42, 43, 44 -> {
+ private static List<SlotText> getTextForUpgradesScreen(ItemStack stack, int slotId) {
+ return switch (slotId) {
+ case 30, 31, 32, 33, 34, 38, 39, 40, 41, 42, 43, 44 -> {
String name = stack.getName().getString();
int lastIndex = name.lastIndexOf(' ');
String roman = name.substring(lastIndex + 1); // + 1 as we don't want the space
- if (!RomanNumerals.isValidRomanNumeral(roman)) return List.of();
+ if (!RomanNumerals.isValidRomanNumeral(roman)) yield List.of();
List<Text> lore = ItemUtils.getLore(stack);
- if (lore.isEmpty()) return List.of();
+ if (lore.isEmpty()) yield List.of();
String lastLine = lore.getLast().getString();
- return List.of(SlotText.bottomLeft(switch (lastLine) {
+ yield List.of(SlotText.bottomLeft(switch (lastLine) {
case "Maxed out!" -> Text.literal("Max").withColor(0xfab387);
case "Currently upgrading!", "Click to instantly upgrade!" -> Text.literal("⏰").withColor(0xf9e2af).formatted(Formatting.BOLD);
case "Click to claim!" -> Text.literal("✅").withColor(0xa6e3a1).formatted(Formatting.BOLD);
default -> Text.literal(String.valueOf(RomanNumerals.romanToDecimal(roman))).withColor(0xcba6f7);
}));
-
}
- }
- return List.of();
+ default -> List.of();
+ };
}
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/EnchantmentLevelAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/EnchantmentLevelAdder.java
index 5530035d..b4f89cdd 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/EnchantmentLevelAdder.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/EnchantmentLevelAdder.java
@@ -1,7 +1,7 @@
package de.hysky.skyblocker.skyblock.item.slottext.adders;
import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
-import de.hysky.skyblocker.skyblock.item.slottext.SlotTextAdder;
+import de.hysky.skyblocker.skyblock.item.slottext.SimpleSlotTextAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.RomanNumerals;
import net.minecraft.item.ItemStack;
@@ -10,23 +10,22 @@ import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
-import net.minecraft.util.Formatting;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
-public class EnchantmentLevelAdder extends SlotTextAdder {
+public class EnchantmentLevelAdder extends SimpleSlotTextAdder {
public EnchantmentLevelAdder() {
super();
}
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- final ItemStack itemStack = slot.getStack();
- if (!itemStack.isOf(Items.ENCHANTED_BOOK)) return List.of();
- String name = itemStack.getName().getString();
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
+ if (!stack.isOf(Items.ENCHANTED_BOOK)) return List.of();
+ String name = stack.getName().getString();
if (name.equals("Enchanted Book")) {
- NbtCompound nbt = ItemUtils.getCustomData(itemStack);
+ NbtCompound nbt = ItemUtils.getCustomData(stack);
if (nbt.isEmpty() || !nbt.contains("enchantments", NbtElement.COMPOUND_TYPE)) return List.of();
NbtCompound enchantments = nbt.getCompound("enchantments");
if (enchantments.getSize() != 1) return List.of(); //Only makes sense to display the level when there's one enchant.
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/EssenceShopAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/EssenceShopAdder.java
index 65574a5a..ec0eb346 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/EssenceShopAdder.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/EssenceShopAdder.java
@@ -1,13 +1,14 @@
package de.hysky.skyblocker.skyblock.item.slottext.adders;
import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
-import de.hysky.skyblocker.skyblock.item.slottext.SlotTextAdder;
+import de.hysky.skyblocker.skyblock.item.slottext.SimpleSlotTextAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.RomanNumerals;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.text.NumberFormat;
import java.util.List;
@@ -15,7 +16,7 @@ import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class EssenceShopAdder extends SlotTextAdder {
+public class EssenceShopAdder extends SimpleSlotTextAdder {
private static final Pattern ESSENCELEVEL = Pattern.compile("^[\\w ]+ (?<level>[IVXLCDM]+)$");
private static final Pattern UNLOCKED = Pattern.compile("UNLOCKED");
private static final Pattern ESSENCE = Pattern.compile("Your \\w+ Essence: (?<essence>[\\d,]+)");
@@ -25,9 +26,7 @@ public class EssenceShopAdder extends SlotTextAdder {
}
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- final ItemStack stack = slot.getStack();
-
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
Matcher essenceLevelMatcher = ESSENCELEVEL.matcher(stack.getName().getString());
Matcher essenceAmountMatcher = ItemUtils.getLoreLineIfMatch(stack, ESSENCE);
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/MinionLevelAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/MinionLevelAdder.java
index fc46f153..b54e6c73 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/MinionLevelAdder.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/MinionLevelAdder.java
@@ -1,30 +1,29 @@
package de.hysky.skyblocker.skyblock.item.slottext.adders;
import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
-import de.hysky.skyblocker.skyblock.item.slottext.SlotTextAdder;
+import de.hysky.skyblocker.skyblock.item.slottext.SimpleSlotTextAdder;
import de.hysky.skyblocker.utils.RomanNumerals;
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.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class MinionLevelAdder extends SlotTextAdder {
+public class MinionLevelAdder extends SimpleSlotTextAdder {
private static final Pattern MINION_PATTERN = Pattern.compile(".* Minion ([IVXLCDM]+)");
public MinionLevelAdder() {
super();
}
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- ItemStack itemStack = slot.getStack();
- if (!itemStack.isOf(Items.PLAYER_HEAD)) return List.of();
- Matcher matcher = MINION_PATTERN.matcher(itemStack.getName().getString());
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
+ if (!stack.isOf(Items.PLAYER_HEAD)) return List.of();
+ Matcher matcher = MINION_PATTERN.matcher(stack.getName().getString());
if (!matcher.matches()) return List.of();
String romanNumeral = matcher.group(1);
if (!RomanNumerals.isValidRomanNumeral(romanNumeral)) return List.of();
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PetLevelAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PetLevelAdder.java
index 3049cd3f..fbacc65c 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PetLevelAdder.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PetLevelAdder.java
@@ -1,7 +1,7 @@
package de.hysky.skyblocker.skyblock.item.slottext.adders;
import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
-import de.hysky.skyblocker.skyblock.item.slottext.SlotTextAdder;
+import de.hysky.skyblocker.skyblock.item.slottext.SimpleSlotTextAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
@@ -9,21 +9,21 @@ import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
import org.apache.commons.lang3.math.NumberUtils;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
-public class PetLevelAdder extends SlotTextAdder {
+public class PetLevelAdder extends SimpleSlotTextAdder {
public PetLevelAdder() {
super();
}
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- ItemStack itemStack = slot.getStack();
- if (!itemStack.isOf(Items.PLAYER_HEAD)) return List.of();
- String level = CatacombsLevelAdder.getBracketedLevelFromName(itemStack);
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
+ if (!stack.isOf(Items.PLAYER_HEAD)) return List.of();
+ String level = CatacombsLevelAdder.getBracketedLevelFromName(stack);
if (!NumberUtils.isDigits(level) || "100".equals(level) || "200".equals(level)) return List.of();
- if (!ItemUtils.getItemId(itemStack).equals("PET")) return List.of();
+ if (!ItemUtils.getItemId(stack).equals("PET")) return List.of();
return List.of(SlotText.topLeft(Text.literal(level).withColor(0xFFDDC1)));
}
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PotionLevelAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PotionLevelAdder.java
index 1c3ef4bc..e229bc57 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PotionLevelAdder.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PotionLevelAdder.java
@@ -1,7 +1,7 @@
package de.hysky.skyblocker.skyblock.item.slottext.adders;
import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
-import de.hysky.skyblocker.skyblock.item.slottext.SlotTextAdder;
+import de.hysky.skyblocker.skyblock.item.slottext.SimpleSlotTextAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
@@ -9,18 +9,18 @@ import net.minecraft.nbt.NbtElement;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
-public class PotionLevelAdder extends SlotTextAdder {
+public class PotionLevelAdder extends SimpleSlotTextAdder {
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- final ItemStack stack = slot.getStack();
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
NbtCompound customData = ItemUtils.getCustomData(stack);
String title = stack.getName().getString();
if (customData.contains("potion_level", NbtElement.INT_TYPE) && !title.contains("Healer Class") && !title.contains("Class Passives")) {
if (title.contains("Healer Level ")){
- String level = title.replaceAll("[^0-9]", "");
+ String level = title.replaceAll("\\D", "");
return List.of(SlotText.bottomRight(Text.literal(level).withColor(0xFFFFFF)));
} else {
int level = customData.getInt("potion_level");
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PowerStonesGuideAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PowerStonesGuideAdder.java
index 0bb37165..e3ee5eda 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PowerStonesGuideAdder.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PowerStonesGuideAdder.java
@@ -1,18 +1,19 @@
package de.hysky.skyblocker.skyblock.item.slottext.adders;
import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
-import de.hysky.skyblocker.skyblock.item.slottext.SlotTextAdder;
+import de.hysky.skyblocker.skyblock.item.slottext.SimpleSlotTextAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class PowerStonesGuideAdder extends SlotTextAdder {
+public class PowerStonesGuideAdder extends SimpleSlotTextAdder {
private static final Pattern LEARNED = Pattern.compile("Learned: (Yes|Not Yet) (?<symbol>[✖✔])");
public PowerStonesGuideAdder() {
@@ -20,18 +21,13 @@ public class PowerStonesGuideAdder extends SlotTextAdder {
}
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- final ItemStack stack = slot.getStack();
-
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
Matcher match = ItemUtils.getLoreLineIfMatch(stack, LEARNED);
if (match == null) return List.of();
String symbol = match.group("symbol");
- Text text;
- if (symbol.equals("✖")) {
- text = Text.literal("✖").withColor(0xFF7276);
- } else {
- text = Text.literal("✔").withColor(0x90ee90);
- }
+ Text text = symbol.equals("✖")
+ ? Text.literal("✖").withColor(0xFF7276)
+ : Text.literal("✔").withColor(0x90ee90);
return List.of(SlotText.bottomRight(text));
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PrehistoricEggAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PrehistoricEggAdder.java
index ce29297e..87781e1e 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PrehistoricEggAdder.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/PrehistoricEggAdder.java
@@ -1,7 +1,7 @@
package de.hysky.skyblocker.skyblock.item.slottext.adders;
import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
-import de.hysky.skyblocker.skyblock.item.slottext.SlotTextAdder;
+import de.hysky.skyblocker.skyblock.item.slottext.SimpleSlotTextAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
@@ -9,26 +9,25 @@ import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
-import net.minecraft.util.Formatting;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
-public class PrehistoricEggAdder extends SlotTextAdder {
+public class PrehistoricEggAdder extends SimpleSlotTextAdder {
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- final ItemStack stack = slot.getStack();
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
if (!stack.isOf(Items.PLAYER_HEAD) || !StringUtils.equals(stack.getSkyblockId(), "PREHISTORIC_EGG")) return List.of();
NbtCompound nbt = ItemUtils.getCustomData(stack);
if (!nbt.contains("blocks_walked", NbtElement.INT_TYPE)) return List.of();
int walked = nbt.getInt("blocks_walked");
- String walkedstr;
- if (walked < 1000) walkedstr = String.valueOf(walked);
- else if (walked < 10000) walkedstr = String.format("%.1fk", walked/1000.0f);
- else walkedstr = walked / 1000 + "k";
+ String walkedStr;
+ if (walked < 1000) walkedStr = String.valueOf(walked);
+ else if (walked < 10000) walkedStr = String.format("%.1fk", walked/1000.0f);
+ else walkedStr = walked / 1000 + "k";
- return List.of(SlotText.bottomLeft(Text.literal(walkedstr).withColor(0xFFDDC1)));
+ return List.of(SlotText.bottomLeft(Text.literal(walkedStr).withColor(0xFFDDC1)));
}
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/RancherBootsSpeedAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/RancherBootsSpeedAdder.java
index 7de5a5be..b34e67c1 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/RancherBootsSpeedAdder.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/RancherBootsSpeedAdder.java
@@ -1,21 +1,21 @@
package de.hysky.skyblocker.skyblock.item.slottext.adders;
import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
-import de.hysky.skyblocker.skyblock.item.slottext.SlotTextAdder;
+import de.hysky.skyblocker.skyblock.item.slottext.SimpleSlotTextAdder;
import de.hysky.skyblocker.utils.ItemUtils;
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.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class RancherBootsSpeedAdder extends SlotTextAdder {
+public class RancherBootsSpeedAdder extends SimpleSlotTextAdder {
private static final Pattern SPEED_PATTERN = Pattern.compile("Current Speed Cap: (\\d+) ?(\\d+)?");
public RancherBootsSpeedAdder() {
@@ -23,11 +23,10 @@ public class RancherBootsSpeedAdder extends SlotTextAdder {
}
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- final ItemStack itemStack = slot.getStack();
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
// V null-safe equals.
- if (!itemStack.isOf(Items.LEATHER_BOOTS) && !StringUtils.equals(itemStack.getSkyblockId(), "RANCHERS_BOOTS")) return List.of();
- Matcher matcher = ItemUtils.getLoreLineIfMatch(slot.getStack(), SPEED_PATTERN);
+ if (!stack.isOf(Items.LEATHER_BOOTS) && !StringUtils.equals(stack.getSkyblockId(), "RANCHERS_BOOTS")) return List.of();
+ Matcher matcher = ItemUtils.getLoreLineIfMatch(stack, SPEED_PATTERN);
if (matcher == null) return List.of();
String speed = matcher.group(2);
if (speed == null) speed = matcher.group(1); //2nd group only matches when the speed cap is set to a number beyond the player's actual speed cap.
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/SkillLevelAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/SkillLevelAdder.java
index 18dbd2f7..5ffce34a 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/SkillLevelAdder.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/SkillLevelAdder.java
@@ -1,7 +1,7 @@
package de.hysky.skyblocker.skyblock.item.slottext.adders;
import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
-import de.hysky.skyblocker.skyblock.item.slottext.SlotTextAdder;
+import de.hysky.skyblocker.skyblock.item.slottext.SimpleSlotTextAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.RomanNumerals;
import net.minecraft.item.ItemStack;
@@ -9,20 +9,20 @@ import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
-public class SkillLevelAdder extends SlotTextAdder {
+public class SkillLevelAdder extends SimpleSlotTextAdder {
public SkillLevelAdder() {
super("^Your Skills");
}
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- switch (slot.id) {
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
+ switch (slotId) {
case 19, 20, 21, 22, 23, 24, 25, 29, 30, 31, 32 -> { //These are the slots that contain the skill items. Note that they aren't continuous, as there are 2 rows.
- String name = slot.getStack().getName().getString();
- final ItemStack stack = slot.getStack();
+ String name = stack.getName().getString();
int lastIndex = name.lastIndexOf(' ');
if (lastIndex == -1) return List.of(SlotText.bottomLeft(Text.literal("0").formatted(Formatting.LIGHT_PURPLE))); //Skills without any levels don't display any roman numerals. Probably because 0 doesn't exist.
String romanNumeral = name.substring(lastIndex + 1); //+1 because we don't need the space itself
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/SkyblockLevelAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/SkyblockLevelAdder.java
index 0fc07922..aa7b577e 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/SkyblockLevelAdder.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/SkyblockLevelAdder.java
@@ -1,24 +1,26 @@
package de.hysky.skyblocker.skyblock.item.slottext.adders;
import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
-import de.hysky.skyblocker.skyblock.item.slottext.SlotTextAdder;
+import de.hysky.skyblocker.skyblock.item.slottext.SimpleSlotTextAdder;
import de.hysky.skyblocker.utils.ItemUtils;
+import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
import org.apache.commons.lang3.math.NumberUtils;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
-public class SkyblockLevelAdder extends SlotTextAdder {
+public class SkyblockLevelAdder extends SimpleSlotTextAdder {
public SkyblockLevelAdder() {
super("^SkyBlock Menu");
}
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- if (slot.getIndex() != 22) return List.of();
- List<Text> lore = ItemUtils.getLore(slot.getStack());
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
+ if (slotId != 22) return List.of();
+ List<Text> lore = ItemUtils.getLore(stack);
if (lore.isEmpty()) return List.of();
List<Text> siblings = lore.getFirst().getSiblings();
if (siblings.size() < 3) return List.of();
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/StatsTuningAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/StatsTuningAdder.java
index 3079d8f2..5c175b1b 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/StatsTuningAdder.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/StatsTuningAdder.java
@@ -1,18 +1,19 @@
package de.hysky.skyblocker.skyblock.item.slottext.adders;
import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
-import de.hysky.skyblocker.skyblock.item.slottext.SlotTextAdder;
+import de.hysky.skyblocker.skyblock.item.slottext.SimpleSlotTextAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class StatsTuningAdder extends SlotTextAdder {
+public class StatsTuningAdder extends SimpleSlotTextAdder {
private static final Pattern STATHAS = Pattern.compile("Stat has: (?<points>\\d+) (points|point)");
private static final Pattern UNASSIGNEDPOINTS = Pattern.compile("Unassigned Points: (?<points>\\d+)!!!");
@@ -21,9 +22,7 @@ public class StatsTuningAdder extends SlotTextAdder {
}
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- final ItemStack stack = slot.getStack();
-
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
Matcher statMatcher = ItemUtils.getLoreLineIfMatch(stack, STATHAS);
Matcher unassignedMatcher = ItemUtils.getLoreLineIfMatch(stack, UNASSIGNEDPOINTS);
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/YourEssenceAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/YourEssenceAdder.java
index ec1bd561..98dd9807 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/YourEssenceAdder.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/slottext/adders/YourEssenceAdder.java
@@ -1,12 +1,13 @@
package de.hysky.skyblocker.skyblock.item.slottext.adders;
import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
-import de.hysky.skyblocker.skyblock.item.slottext.SlotTextAdder;
+import de.hysky.skyblocker.skyblock.item.slottext.SimpleSlotTextAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.text.NumberFormat;
import java.util.List;
@@ -14,7 +15,7 @@ import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class YourEssenceAdder extends SlotTextAdder {
+public class YourEssenceAdder extends SimpleSlotTextAdder {
private static final Pattern ESSENCE = Pattern.compile("You currently own (?<essence>[\\d,]+)");
public YourEssenceAdder() {
@@ -22,8 +23,7 @@ public class YourEssenceAdder extends SlotTextAdder {
}
@Override
- public @NotNull List<SlotText> getText(Slot slot) {
- final ItemStack stack = slot.getStack();
+ public @NotNull List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId) {
String name = stack.getName().getString();
if (name.contains("Essence")) {
List<Text> lore = ItemUtils.getLore(stack);
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/BackpackPreview.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/BackpackPreview.java
index cad1eaab..3fb52b3a 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/BackpackPreview.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/BackpackPreview.java
@@ -7,6 +7,7 @@ import de.hysky.skyblocker.SkyblockerMod;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.skyblock.item.ItemProtection;
import de.hysky.skyblocker.skyblock.item.ItemRarityBackgrounds;
+import de.hysky.skyblocker.skyblock.item.slottext.SlotTextManager;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.Utils;
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
@@ -15,7 +16,6 @@ import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
-import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.SimpleInventory;
@@ -50,6 +50,8 @@ public class BackpackPreview {
private static final Storage[] storages = new Storage[STORAGE_SIZE];
+ private BackpackPreview() {}
+
/**
* The profile id of the currently loaded backpack preview.
*/
@@ -119,7 +121,7 @@ public class BackpackPreview {
writer.write(new StringNbtWriter().apply(Storage.CODEC.encodeStart(getOps(), storages[index]).getOrThrow()));
storages[index].markClean();
} catch (Exception e) {
- LOGGER.error("Failed to save backpack preview file: {}", storageFile.getFileName().toString(), e);
+ LOGGER.error("Failed to save backpack preview file: {}", storageFile.getFileName(), e);
}
}
@@ -171,6 +173,7 @@ public class BackpackPreview {
context.drawItem(currentStack, itemX, itemY);
context.drawItemInSlot(textRenderer, currentStack, itemX, itemY);
+ SlotTextManager.renderSlotText(context, textRenderer, null, currentStack, i, itemX, itemY);
}
matrices.pop();
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/SimpleTooltipAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/SimpleTooltipAdder.java
new file mode 100644
index 00000000..565fecbb
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/SimpleTooltipAdder.java
@@ -0,0 +1,57 @@
+package de.hysky.skyblocker.skyblock.item.tooltip;
+
+import de.hysky.skyblocker.utils.container.RegexContainerMatcher;
+import de.hysky.skyblocker.utils.container.TooltipAdder;
+import org.intellij.lang.annotations.Language;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.regex.Pattern;
+
+/**
+ * Simple implementation of a tooltip adder.
+ * Extend this class and add it to {@link TooltipManager#adders} to add additional text to tooltips.
+ */
+public abstract class SimpleTooltipAdder extends RegexContainerMatcher implements TooltipAdder {
+ /**
+ * The priority of this adder. Lower priority means it will be applied first.
+ * @apiNote Consider adding this as a parameter to your class' constructor and
+ * setting it from {@link TooltipManager#adders} to make it easy to read and maintain.
+ */
+ private final int priority;
+
+ /**
+ * Utility constructor that will compile the given string into a pattern.
+ *
+ * @see #SimpleTooltipAdder(Pattern, int)
+ */
+ protected SimpleTooltipAdder(@NotNull @Language("RegExp") String titlePattern, int priority) {
+ super(titlePattern);
+ this.priority = priority;
+ }
+
+ /**
+ * Creates a TooltipAdder that will be applied to screens with titles that match the given pattern.
+ *
+ * @param titlePattern The pattern to match the screen title against.
+ * @param priority The priority of this adder. Lower priority means it will be applied first.
+ */
+ protected SimpleTooltipAdder(@NotNull Pattern titlePattern, int priority) {
+ super(titlePattern);
+ this.priority = priority;
+ }
+
+ /**
+ * Creates a TooltipAdder that will be applied to all screens.
+ *
+ * @param priority The priority of this adder. Lower priority means it will be applied first.
+ */
+ protected SimpleTooltipAdder(int priority) {
+ super();
+ this.priority = priority;
+ }
+
+ @Override
+ public int getPriority() {
+ return priority;
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipAdder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipAdder.java
deleted file mode 100644
index f3395def..00000000
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipAdder.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package de.hysky.skyblocker.skyblock.item.tooltip;
-
-import de.hysky.skyblocker.utils.render.gui.AbstractContainerMatcher;
-import net.minecraft.item.ItemStack;
-import net.minecraft.screen.slot.Slot;
-import net.minecraft.text.Text;
-import org.intellij.lang.annotations.Language;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.List;
-import java.util.regex.Pattern;
-
-/**
- * Extend this class and add it to {@link TooltipManager#adders} to add additional text to tooltips.
- */
-public abstract class TooltipAdder extends AbstractContainerMatcher {
- /**
- * The priority of this adder. Lower priority means it will be applied first.
- * @apiNote Consider taking this value on your class' constructor and setting it from {@link TooltipManager#adders} to make it easy to read and maintain.
- */
- public final int priority;
-
- protected TooltipAdder(@Language("RegExp") String titlePattern, int priority) {
- super(titlePattern);
- this.priority = priority;
- }
-
- protected TooltipAdder(Pattern titlePattern, int priority) {
- super(titlePattern);
- this.priority = priority;
- }
-
- /**
- * Creates a TooltipAdder that will be applied to all screens.
- */
- protected TooltipAdder(int priority) {
- super();
- this.priority = priority;
- }
-
- /**
- * @implNote The first element of the lines list holds the item's display name,
- * as it's a list of all lines that will be displayed in the tooltip.
- */
- public abstract void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines);
-}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java
index 46f4cb58..d8327383 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java
@@ -118,16 +118,6 @@ public enum TooltipInfoType implements Runnable {
}
/**
- * Checks if the tooltip is enabled and the data has the given member name and sends a warning message if data is null.
- *
- * @param memberName the member name to check
- * @return whether the tooltip is enabled and the data has the given member name or not
- */
- public boolean isTooltipEnabledAndHasOrNullWarning(String memberName) {
- return isTooltipEnabled() && hasOrNullWarning(memberName);
- }
-
- /**
* Downloads the data if it is enabled.
*
* @param futureList the list to add the future to
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipManager.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipManager.java
index c3399b58..3b4cb41c 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipManager.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipManager.java
@@ -4,8 +4,8 @@ import de.hysky.skyblocker.mixins.accessors.HandledScreenAccessor;
import de.hysky.skyblocker.skyblock.bazaar.ReorderHelper;
import de.hysky.skyblocker.skyblock.chocolatefactory.ChocolateFactorySolver;
import de.hysky.skyblocker.skyblock.item.tooltip.adders.*;
-import de.hysky.skyblocker.skyblock.item.tooltip.adders.CraftPriceTooltip;
import de.hysky.skyblocker.utils.Utils;
+import de.hysky.skyblocker.utils.container.TooltipAdder;
import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback;
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
import net.minecraft.client.MinecraftClient;
@@ -24,8 +24,8 @@ public class TooltipManager {
private static final TooltipAdder[] adders = new TooltipAdder[]{
new LineSmoothener(), // Applies before anything else
new SupercraftReminder(),
- new ChocolateFactorySolver.Tooltip(),
- new ReorderHelper.Tooltip(),
+ ChocolateFactorySolver.INSTANCE,
+ new ReorderHelper(),
new NpcPriceTooltip(1),
new BazaarPriceTooltip(2),
new LBinTooltip(3),
@@ -59,14 +59,13 @@ public class TooltipManager {
}
private static void onScreenChange(Screen screen) {
- final String title = screen.getTitle().getString();
currentScreenAdders.clear();
for (TooltipAdder adder : adders) {
- if (adder.titlePattern == null || adder.titlePattern.matcher(title).find()) {
+ if (adder.isEnabled() && adder.test(screen)) {
currentScreenAdders.add(adder);
}
}
- currentScreenAdders.sort(Comparator.comparingInt(adder -> adder.priority));
+ currentScreenAdders.sort(Comparator.comparingInt(TooltipAdder::getPriority));
}
/**
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/AccessoryTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/AccessoryTooltip.java
index caed0e0e..a5e13501 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/AccessoryTooltip.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/AccessoryTooltip.java
@@ -1,7 +1,7 @@
package de.hysky.skyblocker.skyblock.item.tooltip.adders;
import de.hysky.skyblocker.skyblock.item.tooltip.AccessoriesHelper;
-import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
+import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder;
import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType;
import it.unimi.dsi.fastutil.Pair;
import net.minecraft.item.ItemStack;
@@ -13,7 +13,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
-public class AccessoryTooltip extends TooltipAdder {
+public class AccessoryTooltip extends SimpleTooltipAdder {
public AccessoryTooltip(int priority) {
super(priority);
}
@@ -21,7 +21,7 @@ public class AccessoryTooltip extends TooltipAdder {
@Override
public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) {
final String internalID = stack.getSkyblockId();
- if (TooltipInfoType.ACCESSORIES.isTooltipEnabledAndHasOrNullWarning(internalID)) {
+ if (TooltipInfoType.ACCESSORIES.hasOrNullWarning(internalID)) {
Pair<AccessoriesHelper.AccessoryReport, String> report = AccessoriesHelper.calculateReport4Accessory(internalID);
if (report.left() != AccessoriesHelper.AccessoryReport.INELIGIBLE) {
@@ -42,4 +42,9 @@ public class AccessoryTooltip extends TooltipAdder {
}
}
}
+
+ @Override
+ public boolean isEnabled() {
+ return TooltipInfoType.ACCESSORIES.isTooltipEnabled();
+ }
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/AvgBinTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/AvgBinTooltip.java
index d7a56b95..e81879af 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/AvgBinTooltip.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/AvgBinTooltip.java
@@ -1,9 +1,8 @@
package de.hysky.skyblocker.skyblock.item.tooltip.adders;
-import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.config.configs.GeneralConfig;
import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip;
-import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
+import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder;
import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
@@ -13,7 +12,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
-public class AvgBinTooltip extends TooltipAdder {
+public class AvgBinTooltip extends SimpleTooltipAdder {
public AvgBinTooltip(int priority) {
super(priority);
}
@@ -24,40 +23,44 @@ public class AvgBinTooltip extends TooltipAdder {
String internalID = stack.getSkyblockId();
if (neuName == null || internalID == null) return;
- if (SkyblockerConfigManager.get().general.itemTooltip.enableAvgBIN) {
- if (TooltipInfoType.ONE_DAY_AVERAGE.getData() == null || TooltipInfoType.THREE_DAY_AVERAGE.getData() == null) {
- ItemTooltip.nullWarning();
- } else {
+ if (TooltipInfoType.ONE_DAY_AVERAGE.getData() == null || TooltipInfoType.THREE_DAY_AVERAGE.getData() == null) {
+ ItemTooltip.nullWarning();
+ } else {
/*
We are skipping check average prices for potions, runes
and enchanted books because there is no data for their in API.
*/
- if (!neuName.isEmpty() && LBinTooltip.lbinExist) {
- GeneralConfig.Average type = ItemTooltip.config.avg;
+ if (!neuName.isEmpty() && LBinTooltip.lbinExist) {
+ GeneralConfig.Average type = ItemTooltip.config.avg;
- // "No data" line because of API not keeping old data, it causes NullPointerException
- if (type == GeneralConfig.Average.ONE_DAY || type == GeneralConfig.Average.BOTH) {
- lines.add(
- Text.literal(String.format("%-19s", "1 Day Avg. Price:"))
- .formatted(Formatting.GOLD)
- .append(TooltipInfoType.ONE_DAY_AVERAGE.getData().get(neuName) == null
- ? Text.literal("No data").formatted(Formatting.RED)
- : ItemTooltip.getCoinsMessage(TooltipInfoType.ONE_DAY_AVERAGE.getData().get(neuName).getAsDouble(), stack.getCount())
- )
- );
- }
- if (type == GeneralConfig.Average.THREE_DAY || type == GeneralConfig.Average.BOTH) {
- lines.add(
- Text.literal(String.format("%-19s", "3 Day Avg. Price:"))
- .formatted(Formatting.GOLD)
- .append(TooltipInfoType.THREE_DAY_AVERAGE.getData().get(neuName) == null
- ? Text.literal("No data").formatted(Formatting.RED)
- : ItemTooltip.getCoinsMessage(TooltipInfoType.THREE_DAY_AVERAGE.getData().get(neuName).getAsDouble(), stack.getCount())
- )
- );
- }
+ // "No data" line because of API not keeping old data, it causes NullPointerException
+ if (type == GeneralConfig.Average.ONE_DAY || type == GeneralConfig.Average.BOTH) {
+ lines.add(
+ Text.literal(String.format("%-19s", "1 Day Avg. Price:"))
+ .formatted(Formatting.GOLD)
+ .append(TooltipInfoType.ONE_DAY_AVERAGE.getData().get(neuName) == null
+ ? Text.literal("No data").formatted(Formatting.RED)
+ : ItemTooltip.getCoinsMessage(TooltipInfoType.ONE_DAY_AVERAGE.getData().get(neuName).getAsDouble(), stack.getCount())
+ )
+ );
+ }
+ if (type == GeneralConfig.Average.THREE_DAY || type == GeneralConfig.Average.BOTH) {
+ lines.add(
+ Text.literal(String.format("%-19s", "3 Day Avg. Price:"))
+ .formatted(Formatting.GOLD)
+ .append(TooltipInfoType.THREE_DAY_AVERAGE.getData().get(neuName) == null
+ ? Text.literal("No data").formatted(Formatting.RED)
+ : ItemTooltip.getCoinsMessage(TooltipInfoType.THREE_DAY_AVERAGE.getData().get(neuName).getAsDouble(), stack.getCount())
+ )
+ );
}
}
}
}
+
+ @Override
+ public boolean isEnabled() {
+ //Both 1 day and 3 day averages use the same config option, so we only need to check one
+ return TooltipInfoType.THREE_DAY_AVERAGE.isTooltipEnabled();
+ }
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/BazaarPriceTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/BazaarPriceTooltip.java
index d2fa563b..658c50a9 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/BazaarPriceTooltip.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/BazaarPriceTooltip.java
@@ -2,7 +2,7 @@ package de.hysky.skyblocker.skyblock.item.tooltip.adders;
import com.google.gson.JsonObject;
import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip;
-import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
+import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder;
import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
@@ -13,7 +13,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
-public class BazaarPriceTooltip extends TooltipAdder {
+public class BazaarPriceTooltip extends SimpleTooltipAdder {
public static boolean bazaarExist = false;
public BazaarPriceTooltip(int priority) {
@@ -30,7 +30,7 @@ public class BazaarPriceTooltip extends TooltipAdder {
if (name.startsWith("ISSHINY_")) name = "SHINY_" + internalID;
- if (TooltipInfoType.BAZAAR.isTooltipEnabledAndHasOrNullWarning(name)) {
+ if (TooltipInfoType.BAZAAR.hasOrNullWarning(name)) {
int amount;
if (lines.get(1).getString().endsWith("Sack")) {
//The amount is in the 2nd sibling of the 3rd line of the lore. here V
@@ -54,4 +54,9 @@ public class BazaarPriceTooltip extends TooltipAdder {
bazaarExist = true;
}
}
+
+ @Override
+ public boolean isEnabled() {
+ return TooltipInfoType.BAZAAR.isTooltipEnabled();
+ }
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ColorTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ColorTooltip.java
index 7546d37a..8d9d8fbb 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ColorTooltip.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ColorTooltip.java
@@ -1,6 +1,6 @@
package de.hysky.skyblocker.skyblock.item.tooltip.adders;
-import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
+import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder;
import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType;
import de.hysky.skyblocker.utils.Constants;
import de.hysky.skyblocker.utils.ItemUtils;
@@ -18,7 +18,7 @@ import org.slf4j.LoggerFactory;
import java.util.List;
-public class ColorTooltip extends TooltipAdder {
+public class ColorTooltip extends SimpleTooltipAdder {
private static final Logger LOGGER = LoggerFactory.getLogger(ColorTooltip.class);
public ColorTooltip(int priority) {
@@ -26,9 +26,14 @@ public class ColorTooltip extends TooltipAdder {
}
@Override
+ public boolean isEnabled() {
+ return TooltipInfoType.COLOR.isTooltipEnabled();
+ }
+
+ @Override
public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) {
final String internalID = stack.getSkyblockId();
- if (TooltipInfoType.COLOR.isTooltipEnabledAndHasOrNullWarning(internalID) && stack.contains(DataComponentTypes.DYED_COLOR)) {
+ if (TooltipInfoType.COLOR.hasOrNullWarning(internalID) && stack.contains(DataComponentTypes.DYED_COLOR)) {
//DyedColorComponent#getColor can be ARGB so we mask out the alpha bits
int dyeColor = stack.get(DataComponentTypes.DYED_COLOR).rgb() & 0x00FFFFFF;
String colorHex = String.format("%06X", dyeColor);
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/CraftPriceTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/CraftPriceTooltip.java
index f7af446e..20b6b962 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/CraftPriceTooltip.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/CraftPriceTooltip.java
@@ -3,7 +3,7 @@ package de.hysky.skyblocker.skyblock.item.tooltip.adders;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.config.configs.GeneralConfig;
import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip;
-import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
+import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder;
import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType;
import de.hysky.skyblocker.utils.NEURepoManager;
import io.github.moulberry.repo.data.NEUIngredient;
@@ -18,12 +18,11 @@ import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
-public class CraftPriceTooltip extends TooltipAdder {
+public class CraftPriceTooltip extends SimpleTooltipAdder {
protected static final Logger LOGGER = LoggerFactory.getLogger(CraftPriceTooltip.class.getName());
private static final Map<String, Double> cachedCraftCosts = new ConcurrentHashMap<>();
private static final int MAX_RECURSION_DEPTH = 15;
@@ -34,8 +33,6 @@ public class CraftPriceTooltip extends TooltipAdder {
@Override
public void addToTooltip(@Nullable Slot focusedSloFt, ItemStack stack, List<Text> lines) {
- if (SkyblockerConfigManager.get().general.itemTooltip.enableCraftingCost == GeneralConfig.Craft.OFF) return;
-
String internalID = stack.getSkyblockId();
if (stack.getNeuName() == null || internalID == null) return;
@@ -112,4 +109,9 @@ public class CraftPriceTooltip extends TooltipAdder {
public static void clearCache() {
cachedCraftCosts.clear();
}
+
+ @Override
+ public boolean isEnabled() {
+ return SkyblockerConfigManager.get().general.itemTooltip.enableCraftingCost != GeneralConfig.Craft.OFF;
+ }
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/DungeonQualityTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/DungeonQualityTooltip.java
index 0b1d993d..f6efc2f2 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/DungeonQualityTooltip.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/DungeonQualityTooltip.java
@@ -1,7 +1,7 @@
package de.hysky.skyblocker.skyblock.item.tooltip.adders;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
-import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
+import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
@@ -12,14 +12,13 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
-public class DungeonQualityTooltip extends TooltipAdder {
+public class DungeonQualityTooltip extends SimpleTooltipAdder {
public DungeonQualityTooltip(int priority) {
super(priority);
}
@Override
public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) {
- if (!SkyblockerConfigManager.get().general.itemTooltip.dungeonQuality) return;
NbtCompound customData = ItemUtils.getCustomData(stack);
if (customData == null || !customData.contains("baseStatBoostPercentage")) return;
int baseStatBoostPercentage = customData.getInt("baseStatBoostPercentage");
@@ -40,7 +39,7 @@ public class DungeonQualityTooltip extends TooltipAdder {
}
}
- final String getItemTierFloor(int tier) {
+ private String getItemTierFloor(int tier) {
return switch (tier) {
case 0 -> "E";
case 1 -> "F1";
@@ -56,4 +55,9 @@ public class DungeonQualityTooltip extends TooltipAdder {
default -> "Unknown";
};
}
+
+ @Override
+ public boolean isEnabled() {
+ return SkyblockerConfigManager.get().general.itemTooltip.dungeonQuality;
+ }
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/EssenceShopPrice.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/EssenceShopPrice.java
index 5a7051d3..bc478d50 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/EssenceShopPrice.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/EssenceShopPrice.java
@@ -3,7 +3,7 @@ package de.hysky.skyblocker.skyblock.item.tooltip.adders;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
-import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
+import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.RegexUtils;
import it.unimi.dsi.fastutil.objects.Object2LongArrayMap;
@@ -20,7 +20,7 @@ import java.util.OptionalLong;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class EssenceShopPrice extends TooltipAdder {
+public class EssenceShopPrice extends SimpleTooltipAdder {
private static final Pattern ESSENCE_PATTERN = Pattern.compile("Cost (?<amount>[\\d,]+) (?<type>[A-Za-z]+) Essence");
private static final NumberFormat DECIMAL_FORMAT = NumberFormat.getInstance(Locale.US);
private static final String[] ESSENCE_TYPES = {"WITHER", "SPIDER", "UNDEAD", "DRAGON", "GOLD", "DIAMOND", "ICE", "CRIMSON"};
@@ -45,8 +45,6 @@ public class EssenceShopPrice extends TooltipAdder {
//Todo: maybe move the price value right after the essence amount ex: "1,500 Wither Essence (645k coins)"
@Override
public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) {
- if (!SkyblockerConfigManager.get().general.itemTooltip.showEssenceCost) return;
-
String lore = ItemUtils.concatenateLore(lines);
Matcher essenceMatcher = ESSENCE_PATTERN.matcher(lore);
OptionalLong cost = RegexUtils.getLongFromMatcher(essenceMatcher);
@@ -64,4 +62,9 @@ public class EssenceShopPrice extends TooltipAdder {
.append(Text.literal(")").formatted(Formatting.GRAY))
);
}
+
+ @Override
+ public boolean isEnabled() {
+ return SkyblockerConfigManager.get().general.itemTooltip.showEssenceCost;
+ }
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/LBinTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/LBinTooltip.java
index e6930c32..aa90bf09 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/LBinTooltip.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/LBinTooltip.java
@@ -1,7 +1,7 @@
package de.hysky.skyblocker.skyblock.item.tooltip.adders;
import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip;
-import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
+import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder;
import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
@@ -11,7 +11,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
-public class LBinTooltip extends TooltipAdder {
+public class LBinTooltip extends SimpleTooltipAdder {
public static boolean lbinExist = false;
public LBinTooltip(int priority) {
@@ -19,6 +19,11 @@ public class LBinTooltip extends TooltipAdder {
}
@Override
+ public boolean isEnabled() {
+ return TooltipInfoType.LOWEST_BINS.isTooltipEnabled();
+ }
+
+ @Override
public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) {
lbinExist = false;
final String internalID = stack.getSkyblockId();
@@ -30,7 +35,7 @@ public class LBinTooltip extends TooltipAdder {
// bazaarOpened & bazaarExist check for lbin, because Skytils keeps some bazaar item data in lbin api
- if (TooltipInfoType.LOWEST_BINS.isTooltipEnabledAndHasOrNullWarning(name) && !BazaarPriceTooltip.bazaarExist) {
+ if (TooltipInfoType.LOWEST_BINS.hasOrNullWarning(name) && !BazaarPriceTooltip.bazaarExist) {
lines.add(Text.literal(String.format("%-19s", "Lowest BIN Price:"))
.formatted(Formatting.GOLD)
.append(ItemTooltip.getCoinsMessage(TooltipInfoType.LOWEST_BINS.getData().get(name).getAsDouble(), stack.getCount())));
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/LineSmoothener.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/LineSmoothener.java
index 0e997834..347abdad 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/LineSmoothener.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/LineSmoothener.java
@@ -1,6 +1,6 @@
package de.hysky.skyblocker.skyblock.item.tooltip.adders;
-import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
+import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
@@ -9,7 +9,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
-public class LineSmoothener extends TooltipAdder {
+public class LineSmoothener extends SimpleTooltipAdder {
//This is static to not create a new text object for each line in every item
private static final Text BUMPY_LINE = Text.literal("-----------------").formatted(Formatting.DARK_GRAY, Formatting.STRIKETHROUGH);
@@ -17,6 +17,11 @@ public class LineSmoothener extends TooltipAdder {
return Text.literal(" ").formatted(Formatting.DARK_GRAY, Formatting.STRIKETHROUGH, Formatting.BOLD);
}
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+
public LineSmoothener() {
super(Integer.MIN_VALUE);
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MotesTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MotesTooltip.java
index a0aa8d94..42348b78 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MotesTooltip.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MotesTooltip.java
@@ -1,7 +1,7 @@
package de.hysky.skyblocker.skyblock.item.tooltip.adders;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
-import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
+import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder;
import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
@@ -13,7 +13,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Locale;
-public class MotesTooltip extends TooltipAdder {
+public class MotesTooltip extends SimpleTooltipAdder {
public MotesTooltip(int priority) {
super(priority);
}
@@ -21,13 +21,18 @@ public class MotesTooltip extends TooltipAdder {
@Override
public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) {
final String internalID = stack.getSkyblockId();
- if (internalID != null && TooltipInfoType.MOTES.isTooltipEnabledAndHasOrNullWarning(internalID)) {
+ if (internalID != null && TooltipInfoType.MOTES.hasOrNullWarning(internalID)) {
lines.add(Text.literal(String.format("%-20s", "Motes Price:"))
.formatted(Formatting.LIGHT_PURPLE)
.append(getMotesMessage(TooltipInfoType.MOTES.getData().get(internalID).getAsInt(), stack.getCount())));
}
}
+ @Override
+ public boolean isEnabled() {
+ return TooltipInfoType.MOTES.isTooltipEnabled();
+ }
+
private static Text getMotesMessage(int price, int count) {
float motesMultiplier = SkyblockerConfigManager.get().otherLocations.rift.mcGrubberStacks * 0.05f + 1;
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MuseumTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MuseumTooltip.java
index 5c21d2df..6a53dbdb 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MuseumTooltip.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/MuseumTooltip.java
@@ -1,7 +1,7 @@
package de.hysky.skyblocker.skyblock.item.tooltip.adders;
import de.hysky.skyblocker.skyblock.item.MuseumItemCache;
-import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
+import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder;
import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType;
import de.hysky.skyblocker.utils.ItemUtils;
import net.minecraft.item.ItemStack;
@@ -13,15 +13,20 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
-public class MuseumTooltip extends TooltipAdder {
+public class MuseumTooltip extends SimpleTooltipAdder {
public MuseumTooltip(int priority) {
super(priority);
}
@Override
+ public boolean isEnabled() {
+ return TooltipInfoType.MUSEUM.isTooltipEnabled();
+ }
+
+ @Override
public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) {
final String internalID = stack.getSkyblockId();
- if (TooltipInfoType.MUSEUM.isTooltipEnabledAndHasOrNullWarning(internalID)) {
+ if (TooltipInfoType.MUSEUM.hasOrNullWarning(internalID)) {
String itemCategory = TooltipInfoType.MUSEUM.getData().get(internalID).getAsString();
String format = switch (itemCategory) {
case "Weapons" -> "%-18s";
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/NpcPriceTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/NpcPriceTooltip.java
index d556c9b2..17cb80e3 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/NpcPriceTooltip.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/NpcPriceTooltip.java
@@ -1,7 +1,7 @@
package de.hysky.skyblocker.skyblock.item.tooltip.adders;
import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip;
-import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
+import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder;
import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
@@ -12,15 +12,20 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
-public class NpcPriceTooltip extends TooltipAdder {
+public class NpcPriceTooltip extends SimpleTooltipAdder {
public NpcPriceTooltip(int priority) {
super(priority);
}
@Override
+ public boolean isEnabled() {
+ return TooltipInfoType.NPC.isTooltipEnabled();
+ }
+
+ @Override
public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) {
final String internalID = stack.getSkyblockId();
- if (internalID != null && TooltipInfoType.NPC.isTooltipEnabledAndHasOrNullWarning(internalID)) {
+ if (internalID != null && TooltipInfoType.NPC.hasOrNullWarning(internalID)) {
int amount;
if (lines.get(1).getString().endsWith("Sack")) {
//The amount is in the 2nd sibling of the 3rd line of the lore. here V
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java
index 9f405c58..31aa3de4 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/ObtainedDateTooltip.java
@@ -1,6 +1,6 @@
package de.hysky.skyblocker.skyblock.item.tooltip.adders;
-import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
+import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder;
import de.hysky.skyblocker.skyblock.item.tooltip.TooltipInfoType;
import de.hysky.skyblocker.utils.ItemUtils;
import net.minecraft.item.ItemStack;
@@ -18,7 +18,7 @@ import java.time.temporal.TemporalAccessor;
import java.util.List;
import java.util.Locale;
-public class ObtainedDateTooltip extends TooltipAdder {
+public class ObtainedDateTooltip extends SimpleTooltipAdder {
private static final DateTimeFormatter OBTAINED_DATE_FORMATTER = DateTimeFormatter.ofPattern("MMMM d, yyyy").withZone(ZoneId.systemDefault()).localizedBy(Locale.ENGLISH);
private static final DateTimeFormatter OLD_OBTAINED_DATE_FORMAT = DateTimeFormatter.ofPattern("M/d/yy h:m a").withZone(ZoneId.of("UTC")).localizedBy(Locale.ENGLISH);
@@ -27,15 +27,17 @@ public class ObtainedDateTooltip extends TooltipAdder {
}
@Override
- public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) {
- if (TooltipInfoType.OBTAINED.isTooltipEnabled()) {
- String timestamp = getTimestamp(stack);
+ public boolean isEnabled() {
+ return TooltipInfoType.OBTAINED.isTooltipEnabled();
+ }
- if (!timestamp.isEmpty()) {
- lines.add(Text.empty()
- .append(Text.literal(String.format("%-21s", "Obtained: ")).formatted(Formatting.LIGHT_PURPLE))
- .append(Text.literal(timestamp).formatted(Formatting.RED)));
- }
+ @Override
+ public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) {
+ String timestamp = getTimestamp(stack);
+ if (!timestamp.isEmpty()) {
+ lines.add(Text.empty()
+ .append(Text.literal(String.format("%-21s", "Obtained: ")).formatted(Formatting.LIGHT_PURPLE))
+ .append(Text.literal(timestamp).formatted(Formatting.RED)));
}
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/SupercraftReminder.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/SupercraftReminder.java
index 47d2bd48..c34e1650 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/SupercraftReminder.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/adders/SupercraftReminder.java
@@ -1,6 +1,6 @@
package de.hysky.skyblocker.skyblock.item.tooltip.adders;
-import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
+import de.hysky.skyblocker.skyblock.item.tooltip.SimpleTooltipAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
@@ -12,7 +12,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.regex.Pattern;
-public class SupercraftReminder extends TooltipAdder {
+public class SupercraftReminder extends SimpleTooltipAdder {
private static final byte SUPERCRAFT_SLOT = 32;
private static final byte RECIPE_RESULT_SLOT = 25;
@@ -29,4 +29,9 @@ public class SupercraftReminder extends TooltipAdder {
if (lines.get(lines.size() - 2).getString().equals("Recipe not unlocked!")) index--; //Place it right below the "Right-Click to set amount" line
lines.add(index, Text.literal("Shift-Click to maximize the amount!").formatted(Formatting.GOLD));
}
+
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/PlayerListMgr.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/PlayerListMgr.java
index 472cf700..b08a09d6 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/PlayerListMgr.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/util/PlayerListMgr.java
@@ -1,19 +1,20 @@
package de.hysky.skyblocker.skyblock.tabhud.util;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
import de.hysky.skyblocker.mixins.accessors.PlayerListHudAccessor;
import de.hysky.skyblocker.utils.Utils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* This class may be used to get data from the player list. It doesn't get its
@@ -24,8 +25,15 @@ public class PlayerListMgr {
public static final Logger LOGGER = LoggerFactory.getLogger("Skyblocker Regex");
- private static List<PlayerListEntry> playerList;
- private static String footer;
+ /**
+ * The player list in tab.
+ */
+ private static List<PlayerListEntry> playerList = new ArrayList<>(); // Initialize to prevent npe.
+ /**
+ * The player list in tab, but a list of strings instead of {@link PlayerListEntry}s.
+ */
+ private static List<String> playerStringList = new ArrayList<>();
+ private static String footer;
public static void updateList() {
@@ -38,25 +46,40 @@ public class PlayerListMgr {
// check is needed, else game crashes on server leave
if (cpnwh != null) {
playerList = cpnwh.getPlayerList().stream().sorted(PlayerListHudAccessor.getOrdering()).toList();
+ playerStringList = playerList.stream().map(PlayerListEntry::getDisplayName).filter(Objects::nonNull).map(Text::getString).map(String::strip).toList();
}
}
- public static void updateFooter(Text f) {
- if (f == null) {
- footer = null;
- } else {
- footer = f.getString();
- }
- }
+ /**
+ * @return the cached player list
+ */
+ public static List<PlayerListEntry> getPlayerList() {
+ return playerList;
+ }
+
+ /**
+ * @return the cached player list as a list of strings
+ */
+ public static List<String> getPlayerStringList() {
+ return playerStringList;
+ }
+
+ public static void updateFooter(Text f) {
+ if (f == null) {
+ footer = null;
+ } else {
+ footer = f.getString();
+ }
+ }
- public static String getFooter() {
- return footer;
- }
+ public static String getFooter() {
+ return footer;
+ }
/**
* Get the display name at some index of the player list and apply a pattern to
* it
- *
+ *
* @return the matcher if p fully matches, else null
*/
public static Matcher regexAt(int idx, Pattern p) {
@@ -78,7 +101,7 @@ public class PlayerListMgr {
/**
* Get the display name at some index of the player list as string
- *
+ *
* @return the string or null, if the display name is null, empty or whitespace
* only
*/
@@ -105,9 +128,9 @@ public class PlayerListMgr {
/**
* Gets the display name at some index of the player list
- *
+ *
* @return the text or null, if the display name is null
- *
+ *
* @implNote currently designed specifically for crimson isles faction quests
* widget and the rift widgets, might not work correctly without
* modification for other stuff. you've been warned!
@@ -157,7 +180,7 @@ public class PlayerListMgr {
/**
* Get the display name at some index of the player list as Text as seen in the
* game
- *
+ *
* @return the PlayerListEntry at that index
*/
public static PlayerListEntry getRaw(int idx) {
diff --git a/src/main/java/de/hysky/skyblocker/utils/Utils.java b/src/main/java/de/hysky/skyblocker/utils/Utils.java
index 042095d1..4de32710 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 com.mojang.util.UndashedUuid;
+import de.hysky.skyblocker.debug.Debug;
import de.hysky.skyblocker.events.SkyblockEvents;
import de.hysky.skyblocker.mixins.accessors.MessageHandlerAccessor;
import de.hysky.skyblocker.skyblock.item.MuseumItemCache;
@@ -17,7 +18,6 @@ import net.azureaaron.hmapi.network.packet.s2c.HelloS2CPacket;
import net.azureaaron.hmapi.network.packet.s2c.HypixelS2CPacket;
import net.azureaaron.hmapi.network.packet.v1.s2c.LocationUpdateS2CPacket;
import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents;
-import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.network.PlayerListEntry;
@@ -239,9 +239,8 @@ public class Utils {
public static void updatePlayerPresenceFromScoreboard(MinecraftClient client) {
List<String> sidebar = STRING_SCOREBOARD;
- FabricLoader fabricLoader = FabricLoader.getInstance();
if (client.world == null || client.isInSingleplayer() || sidebar.isEmpty()) {
- if (fabricLoader.isDevelopmentEnvironment()) {
+ if (Debug.debugEnabled()) {
sidebar = Collections.emptyList();
} else {
isOnSkyblock = false;
@@ -249,13 +248,13 @@ public class Utils {
}
}
- if (sidebar.isEmpty() && !fabricLoader.isDevelopmentEnvironment()) return;
+ if (sidebar.isEmpty() && !Debug.debugEnabled()) return;
- if (fabricLoader.isDevelopmentEnvironment() || isConnectedToHypixel(client)) {
+ if (Debug.debugEnabled() || isConnectedToHypixel(client)) {
if (!isOnHypixel) {
isOnHypixel = true;
}
- if (fabricLoader.isDevelopmentEnvironment() || sidebar.getFirst().contains("SKYBLOCK") || sidebar.getFirst().contains("SKIBLOCK")) {
+ if (Debug.debugEnabled() || sidebar.getFirst().contains("SKYBLOCK") || sidebar.getFirst().contains("SKIBLOCK")) {
if (!isOnSkyblock) {
if (!isInjected) {
isInjected = true;
diff --git a/src/main/java/de/hysky/skyblocker/utils/container/ContainerMatcher.java b/src/main/java/de/hysky/skyblocker/utils/container/ContainerMatcher.java
new file mode 100644
index 00000000..159f399e
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/utils/container/ContainerMatcher.java
@@ -0,0 +1,20 @@
+package de.hysky.skyblocker.utils.container;
+
+import net.minecraft.client.gui.screen.Screen;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.function.Predicate;
+
+public interface ContainerMatcher extends Predicate<Screen> {
+ /**
+ * Tests if the given screen should be handled by this matcher.
+ * @return {@code true} if this matcher should apply to the given screen, {@code false} otherwise
+ */
+ @Override
+ boolean test(@NotNull Screen screen);
+
+ /**
+ * @return {@code true} if this matcher is enabled, {@code false} otherwise
+ */
+ boolean isEnabled();
+}
diff --git a/src/main/java/de/hysky/skyblocker/utils/container/ContainerSolver.java b/src/main/java/de/hysky/skyblocker/utils/container/ContainerSolver.java
new file mode 100644
index 00000000..c6162049
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/utils/container/ContainerSolver.java
@@ -0,0 +1,38 @@
+package de.hysky.skyblocker.utils.container;
+
+import de.hysky.skyblocker.SkyblockerMod;
+import de.hysky.skyblocker.utils.Resettable;
+import de.hysky.skyblocker.utils.render.gui.ColorHighlight;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
+import net.minecraft.item.ItemStack;
+
+import java.util.List;
+
+public interface ContainerSolver extends ContainerMatcher, Resettable {
+ List<ColorHighlight> getColors(Int2ObjectMap<ItemStack> slots);
+
+ default void start(GenericContainerScreen screen) {}
+
+ @Override
+ default void reset() {}
+
+ default boolean onClickSlot(int slot, ItemStack stack, int screenId) {
+ return false;
+ }
+
+ static void markHighlightsDirty() {
+ SkyblockerMod.getInstance().containerSolverManager.markDirty();
+ }
+
+ static void trimEdges(Int2ObjectMap<ItemStack> slots, int rows) {
+ for (int i = 0; i < rows; i++) {
+ slots.remove(9 * i);
+ slots.remove(9 * i + 8);
+ }
+ for (int i = 1; i < 8; i++) {
+ slots.remove(i);
+ slots.remove((rows - 1) * 9 + i);
+ }
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/utils/container/ContainerSolverManager.java b/src/main/java/de/hysky/skyblocker/utils/container/ContainerSolverManager.java
new file mode 100644
index 00000000..cf98941c
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/utils/container/ContainerSolverManager.java
@@ -0,0 +1,154 @@
+package de.hysky.skyblocker.utils.container;
+
+import com.mojang.blaze3d.systems.RenderSystem;
+import de.hysky.skyblocker.mixins.accessors.HandledScreenAccessor;
+import de.hysky.skyblocker.skyblock.accessories.newyearcakes.NewYearCakeBagHelper;
+import de.hysky.skyblocker.skyblock.accessories.newyearcakes.NewYearCakesHelper;
+import de.hysky.skyblocker.skyblock.bazaar.ReorderHelper;
+import de.hysky.skyblocker.skyblock.chocolatefactory.ChocolateFactorySolver;
+import de.hysky.skyblocker.skyblock.dungeon.CroesusHelper;
+import de.hysky.skyblocker.skyblock.dungeon.CroesusProfit;
+import de.hysky.skyblocker.skyblock.dungeon.terminal.ColorTerminal;
+import de.hysky.skyblocker.skyblock.dungeon.terminal.LightsOnTerminal;
+import de.hysky.skyblocker.skyblock.dungeon.terminal.OrderTerminal;
+import de.hysky.skyblocker.skyblock.dungeon.terminal.StartsWithTerminal;
+import de.hysky.skyblocker.skyblock.dwarven.CommissionHighlight;
+import de.hysky.skyblocker.skyblock.experiment.ChronomatronSolver;
+import de.hysky.skyblocker.skyblock.experiment.SuperpairsSolver;
+import de.hysky.skyblocker.skyblock.experiment.UltrasequencerSolver;
+import de.hysky.skyblocker.utils.Utils;
+import de.hysky.skyblocker.utils.render.gui.ColorHighlight;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap;
+import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
+import net.minecraft.client.gui.DrawContext;
+import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.item.ItemStack;
+import net.minecraft.screen.slot.Slot;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+/**
+ * Manager class for {@link SimpleContainerSolver}s like terminal solvers and experiment solvers. To add a new gui solver, extend {@link SimpleContainerSolver} and register it in {@link #ContainerSolverManager()}.
+ */
+public class ContainerSolverManager {
+ private final ContainerSolver[] solvers;
+ private ContainerSolver currentSolver = null;
+ private List<ColorHighlight> highlights;
+ /**
+ * Useful for keeping track of a solver's state in a Screen instance, such as if Hypixel closes & reopens a screen after every click (as they do with terminals).
+ */
+ private int screenId = 0;
+
+ public ContainerSolverManager() {
+ solvers = new ContainerSolver[]{
+ new ColorTerminal(),
+ new OrderTerminal(),
+ new StartsWithTerminal(),
+ new LightsOnTerminal(),
+ new CroesusHelper(),
+ new CroesusProfit(),
+ new ChronomatronSolver(),
+ new CommissionHighlight(),
+ new SuperpairsSolver(),
+ UltrasequencerSolver.INSTANCE,
+ new NewYearCakeBagHelper(),
+ NewYearCakesHelper.INSTANCE,
+ ChocolateFactorySolver.INSTANCE,
+ new ReorderHelper()
+ };
+ }
+
+ public ContainerSolver getCurrentSolver() {
+ return currentSolver;
+ }
+
+ public void init() {
+ ScreenEvents.BEFORE_INIT.register((client, screen, scaledWidth, scaledHeight) -> {
+ if (Utils.isOnSkyblock() && screen instanceof GenericContainerScreen genericContainerScreen) {
+ ScreenEvents.afterRender(screen).register((screen1, context, mouseX, mouseY, delta) -> {
+ MatrixStack matrices = context.getMatrices();
+ matrices.push();
+ matrices.translate(((HandledScreenAccessor) genericContainerScreen).getX(), ((HandledScreenAccessor) genericContainerScreen).getY(), 300);
+ onDraw(context, genericContainerScreen.getScreenHandler().slots.subList(0, genericContainerScreen.getScreenHandler().getRows() * 9));
+ matrices.pop();
+ });
+ ScreenEvents.remove(screen).register(screen1 -> clearScreen());
+ onSetScreen(genericContainerScreen);
+ } else {
+ clearScreen();
+ }
+ });
+ }
+
+ public void onSetScreen(@NotNull GenericContainerScreen screen) {
+ String screenName = screen.getTitle().getString();
+ for (ContainerSolver solver : solvers) {
+ if (solver.isEnabled()) {
+ if (solver instanceof SimpleContainerSolver containerSolver && containerSolver.test(screenName)) {
+ ++screenId;
+ currentSolver = containerSolver;
+ currentSolver.start(screen);
+ markDirty();
+
+ return;
+ } else if (solver.test(screen)) {
+ ++screenId;
+ currentSolver = solver;
+ currentSolver.start(screen);
+ markDirty();
+
+ return;
+ }
+ }
+ }
+ clearScreen();
+ }
+
+ public void clearScreen() {
+ if (currentSolver != null) {
+ currentSolver.reset();
+ currentSolver = null;
+ }
+ }
+
+ public void markDirty() {
+ highlights = null;
+ }
+
+ /**
+ * @return Whether the click should be disallowed.
+ */
+ public boolean onSlotClick(int slot, ItemStack stack) {
+ if (currentSolver != null) {
+ return currentSolver.onClickSlot(slot, stack, screenId);
+ }
+
+ return false;
+ }
+
+ public void onDraw(DrawContext context, List<Slot> slots) {
+ if (currentSolver == null)
+ return;
+ if (highlights == null)
+ highlights = currentSolver.getColors(slotMap(slots));
+ RenderSystem.enableDepthTest();
+ RenderSystem.colorMask(true, true, true, false);
+ for (ColorHighlight highlight : highlights) {
+ Slot slot = slots.get(highlight.slot());
+ int color = highlight.color();
+ context.fill(slot.x, slot.y, slot.x + 16, slot.y + 16, color);
+ }
+ RenderSystem.colorMask(true, true, true, true);
+ }
+
+ private Int2ObjectMap<ItemStack> slotMap(List<Slot> slots) {
+ Int2ObjectMap<ItemStack> slotMap = new Int2ObjectRBTreeMap<>();
+ for (int i = 0; i < slots.size(); i++) {
+ slotMap.put(i, slots.get(i).getStack());
+ }
+ return slotMap;
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/utils/container/RegexContainerMatcher.java b/src/main/java/de/hysky/skyblocker/utils/container/RegexContainerMatcher.java
new file mode 100644
index 00000000..4f9d49ae
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/utils/container/RegexContainerMatcher.java
@@ -0,0 +1,68 @@
+package de.hysky.skyblocker.utils.container;
+
+import de.hysky.skyblocker.skyblock.ChestValue;
+import net.minecraft.client.gui.screen.Screen;
+import org.intellij.lang.annotations.Language;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A regex implementation of {@link ContainerMatcher} that matches the title of the screen.
+ */
+public abstract class RegexContainerMatcher implements ContainerMatcher {
+ /**
+ * The title of the screen must match this pattern for this to be applied. Null means it will be applied to all screens.
+ *
+ * @implNote Don't end your regex with a {@code $} as {@link ChestValue} appends text to the end of the title,
+ * so the regex will stop matching if the player uses chest value.
+ */
+ @Nullable
+ public final Pattern titlePattern;
+
+ @Nullable
+ public String[] groups = null;
+
+ @Override
+ public boolean test(@NotNull Screen screen) {
+ return test(screen.getTitle().getString());
+ }
+
+ public boolean test(@NotNull String title) {
+ if (titlePattern == null) return true;
+ Matcher matcher = titlePattern.matcher(title);
+ if (matcher.matches()) {
+ int groupCount = matcher.groupCount();
+ if (groupCount >= 1) { //No need to initialize the array if there are no groups
+ groups = new String[groupCount];
+ for (int i = 0; i < groupCount; i++) {
+ groups[i] = matcher.group(i + 1); // +1 because first group is the whole match, which is useless
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ protected RegexContainerMatcher() {
+ this((Pattern) null);
+ }
+
+ protected RegexContainerMatcher(@NotNull @Language("RegExp") String titlePattern) {
+ this(Pattern.compile(titlePattern));
+ }
+
+ protected RegexContainerMatcher(@Nullable Pattern titlePattern) {
+ this.titlePattern = titlePattern;
+ }
+
+ public @Nullable Pattern getTitlePattern() {
+ return titlePattern;
+ }
+
+ public final @Nullable String[] getGroups() {
+ return groups;
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/utils/container/SimpleContainerSolver.java b/src/main/java/de/hysky/skyblocker/utils/container/SimpleContainerSolver.java
new file mode 100644
index 00000000..7d8b7417
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/utils/container/SimpleContainerSolver.java
@@ -0,0 +1,38 @@
+package de.hysky.skyblocker.utils.container;
+
+import org.intellij.lang.annotations.Language;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.regex.Pattern;
+
+/**
+ * Simple implementation of a container solver. Extend this class to add a new gui solver,
+ * like terminal solvers or experiment solvers and add it to {@link ContainerSolverManager#solvers}.
+ */
+public abstract class SimpleContainerSolver extends RegexContainerMatcher implements ContainerSolver {
+ /**
+ * Utility constructor that will compile the given string into a pattern.
+ *
+ * @see #SimpleContainerSolver(Pattern)
+ */
+ protected SimpleContainerSolver(@NotNull @Language("RegExp") String titlePattern) {
+ super(titlePattern);
+ }
+
+ /**
+ * Creates a ContainerSolver that will be applied to screens with titles that match the given pattern.
+ *
+ * @param titlePattern The pattern to match the screen title against.
+ */
+ protected SimpleContainerSolver(@NotNull Pattern titlePattern) {
+ super(titlePattern);
+ }
+
+ // A container solver that applies to every screen doesn't make sense,
+ // so we don't provide a constructor for that and force getTitlePattern to be @NotNull
+ @Override
+ public @NotNull Pattern getTitlePattern() {
+ assert super.getTitlePattern() != null;
+ return super.getTitlePattern();
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/utils/container/SlotTextAdder.java b/src/main/java/de/hysky/skyblocker/utils/container/SlotTextAdder.java
new file mode 100644
index 00000000..72f92547
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/utils/container/SlotTextAdder.java
@@ -0,0 +1,30 @@
+package de.hysky.skyblocker.utils.container;
+
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
+import de.hysky.skyblocker.skyblock.item.slottext.SlotTextMode;
+import net.minecraft.item.ItemStack;
+import net.minecraft.screen.slot.Slot;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+public interface SlotTextAdder extends ContainerMatcher {
+
+ /**
+ * This method will be called for each rendered slot. Consider using a switch statement on {@code slotId} if you wish to limit the text to specific slots.
+ *
+ * @return A list of positioned text to be rendered. Return {@link List#of()} if no text should be rendered.
+ * @implNote By minecraft's design, scaled text inexplicably moves around.
+ * It's also not anti-aliased, so it looks horribly jagged and unreadable when scaled down too much.
+ * So, limit your text to 3 characters (or roughly less than 20 width) if you want it to not look horrible.
+ */
+ @NotNull
+ List<SlotText> getText(@Nullable Slot slot, @NotNull ItemStack stack, int slotId);
+
+ @Override
+ default boolean isEnabled() {
+ return SkyblockerConfigManager.get().general.itemInfoDisplay.slotTextMode != SlotTextMode.DISABLED;
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/utils/container/TooltipAdder.java b/src/main/java/de/hysky/skyblocker/utils/container/TooltipAdder.java
new file mode 100644
index 00000000..2ff3fdf1
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/utils/container/TooltipAdder.java
@@ -0,0 +1,18 @@
+package de.hysky.skyblocker.utils.container;
+
+import net.minecraft.item.ItemStack;
+import net.minecraft.screen.slot.Slot;
+import net.minecraft.text.Text;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+public interface TooltipAdder extends ContainerMatcher {
+ /**
+ * @implNote The first element of the lines list holds the item's display name,
+ * as it's a list of all lines that will be displayed in the tooltip.
+ */
+ void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines);
+
+ int getPriority();
+}
diff --git a/src/main/java/de/hysky/skyblocker/utils/render/gui/AbstractContainerMatcher.java b/src/main/java/de/hysky/skyblocker/utils/render/gui/AbstractContainerMatcher.java
deleted file mode 100644
index bf255218..00000000
--- a/src/main/java/de/hysky/skyblocker/utils/render/gui/AbstractContainerMatcher.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package de.hysky.skyblocker.utils.render.gui;
-
-import de.hysky.skyblocker.skyblock.ChestValue;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.regex.Pattern;
-
-public abstract class AbstractContainerMatcher {
- /**
- * The title of the screen must match this pattern for this to be applied. Null means it will be applied to all screens.
- * @implNote Don't end your regex with a {@code $} as {@link ChestValue} appends text to the end of the title,
- * so the regex will stop matching if the player uses chest value.
- */
- @Nullable
- public final Pattern titlePattern;
-
- protected AbstractContainerMatcher() {
- this((Pattern) null);
- }
-
- protected AbstractContainerMatcher(@NotNull String titlePattern) {
- this(Pattern.compile(titlePattern));
- }
-
- protected AbstractContainerMatcher(@Nullable Pattern titlePattern) {
- this.titlePattern = titlePattern;
- }
-}
diff --git a/src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolver.java b/src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolver.java
deleted file mode 100644
index 9a9d0907..00000000
--- a/src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolver.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package de.hysky.skyblocker.utils.render.gui;
-
-import de.hysky.skyblocker.SkyblockerMod;
-import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
-import net.minecraft.item.ItemStack;
-import org.intellij.lang.annotations.Language;
-
-import java.util.List;
-import java.util.regex.Pattern;
-
-/**
- * Abstract class for gui solvers. Extend this class to add a new gui solver, like terminal solvers or experiment solvers.
- */
-public abstract class ContainerSolver extends AbstractContainerMatcher {
- protected ContainerSolver(@Language("RegExp") String titlePattern) {
- super(titlePattern);
- }
-
- protected abstract boolean isEnabled();
-
- public final Pattern getName() {
- return titlePattern;
- }
-
- protected void start(GenericContainerScreen screen) {
- }
-
- protected void reset() {
- }
-
- protected void markHighlightsDirty() {
- SkyblockerMod.getInstance().containerSolverManager.markDirty();
- }
-
- protected boolean onClickSlot(int slot, ItemStack stack, int screenId, String[] groups) {
- return false;
- }
-
- protected abstract List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots);
-
- protected final void trimEdges(Int2ObjectMap<ItemStack> slots, int rows) {
- for (int i = 0; i < rows; i++) {
- slots.remove(9 * i);
- slots.remove(9 * i + 8);
- }
- for (int i = 1; i < 8; i++) {
- slots.remove(i);
- slots.remove((rows - 1) * 9 + i);
- }
- }
-}
diff --git a/src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolverManager.java b/src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolverManager.java
deleted file mode 100644
index 79cc78f5..00000000
--- a/src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolverManager.java
+++ /dev/null
@@ -1,157 +0,0 @@
-package de.hysky.skyblocker.utils.render.gui;
-
-import com.mojang.blaze3d.systems.RenderSystem;
-import de.hysky.skyblocker.mixins.accessors.HandledScreenAccessor;
-import de.hysky.skyblocker.skyblock.accessories.newyearcakes.NewYearCakeBagHelper;
-import de.hysky.skyblocker.skyblock.accessories.newyearcakes.NewYearCakesHelper;
-import de.hysky.skyblocker.skyblock.bazaar.ReorderHelper;
-import de.hysky.skyblocker.skyblock.chocolatefactory.ChocolateFactorySolver;
-import de.hysky.skyblocker.skyblock.dungeon.CroesusHelper;
-import de.hysky.skyblocker.skyblock.dungeon.CroesusProfit;
-import de.hysky.skyblocker.skyblock.dungeon.terminal.ColorTerminal;
-import de.hysky.skyblocker.skyblock.dungeon.terminal.LightsOnTerminal;
-import de.hysky.skyblocker.skyblock.dungeon.terminal.OrderTerminal;
-import de.hysky.skyblocker.skyblock.dungeon.terminal.StartsWithTerminal;
-import de.hysky.skyblocker.skyblock.dwarven.CommissionHighlight;
-import de.hysky.skyblocker.skyblock.experiment.ChronomatronSolver;
-import de.hysky.skyblocker.skyblock.experiment.SuperpairsSolver;
-import de.hysky.skyblocker.skyblock.experiment.UltrasequencerSolver;
-import de.hysky.skyblocker.utils.Utils;
-import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap;
-import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
-import net.minecraft.client.gui.DrawContext;
-import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
-import net.minecraft.client.util.math.MatrixStack;
-import net.minecraft.item.ItemStack;
-import net.minecraft.screen.slot.Slot;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Manager class for {@link ContainerSolver}s like terminal solvers and experiment solvers. To add a new gui solver, extend {@link ContainerSolver} and register it in {@link #ContainerSolverManager()}.
- */
-public class ContainerSolverManager {
- private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("");
- private final ContainerSolver[] solvers;
- private ContainerSolver currentSolver = null;
- private String[] groups;
- private List<ColorHighlight> highlights;
- /**
- * Useful for keeping track of a solver's state in a Screen instance, such as if Hypixel closes & reopens a screen after every click (as they do with terminals).
- */
- private int screenId = 0;
-
- public ContainerSolverManager() {
- solvers = new ContainerSolver[]{
- new ColorTerminal(),
- new OrderTerminal(),
- new StartsWithTerminal(),
- new LightsOnTerminal(),
- new CroesusHelper(),
- new CommissionHighlight(),
- new CroesusProfit(),
- new ChronomatronSolver(),
- new SuperpairsSolver(),
- UltrasequencerSolver.INSTANCE,
- new NewYearCakeBagHelper(),
- NewYearCakesHelper.INSTANCE,
- new ChocolateFactorySolver(),
- new ReorderHelper()
- };
- }
-
- public ContainerSolver getCurrentSolver() {
- return currentSolver;
- }
-
- public void init() {
- ScreenEvents.BEFORE_INIT.register((client, screen, scaledWidth, scaledHeight) -> {
- if (Utils.isOnSkyblock() && screen instanceof GenericContainerScreen genericContainerScreen) {
- ScreenEvents.afterRender(screen).register((screen1, context, mouseX, mouseY, delta) -> {
- MatrixStack matrices = context.getMatrices();
- matrices.push();
- matrices.translate(((HandledScreenAccessor) genericContainerScreen).getX(), ((HandledScreenAccessor) genericContainerScreen).getY(), 300);
- onDraw(context, genericContainerScreen.getScreenHandler().slots.subList(0, genericContainerScreen.getScreenHandler().getRows() * 9));
- matrices.pop();
- });
- ScreenEvents.remove(screen).register(screen1 -> clearScreen());
- onSetScreen(genericContainerScreen);
- } else {
- clearScreen();
- }
- });
- }
-
- public void onSetScreen(@NotNull GenericContainerScreen screen) {
- String screenName = screen.getTitle().getString();
- Matcher matcher = PLACEHOLDER_PATTERN.matcher(screenName);
- for (ContainerSolver solver : solvers) {
- if (solver.isEnabled()) {
- matcher.usePattern(solver.getName());
- matcher.reset();
- if (matcher.matches()) {
- ++screenId;
- currentSolver = solver;
- groups = new String[matcher.groupCount()];
- for (int i = 0; i < groups.length; i++) {
- groups[i] = matcher.group(i + 1);
- }
- currentSolver.start(screen);
- markDirty();
-
- return;
- }
- }
- }
- clearScreen();
- }
-
- public void clearScreen() {
- if (currentSolver != null) {
- currentSolver.reset();
- currentSolver = null;
- }
- }
-
- public void markDirty() {
- highlights = null;
- }
-
- /**
- * @return Whether the click should be disallowed.
- */
- public boolean onSlotClick(int slot, ItemStack stack) {
- if (currentSolver != null) {
- return currentSolver.onClickSlot(slot, stack, screenId, groups);
- }
-
- return false;
- }
-
- public void onDraw(DrawContext context, List<Slot> slots) {
- if (currentSolver == null)
- return;
- if (highlights == null)
- highlights = currentSolver.getColors(groups, slotMap(slots));
- RenderSystem.enableDepthTest();
- RenderSystem.colorMask(true, true, true, false);
- for (ColorHighlight highlight : highlights) {
- Slot slot = slots.get(highlight.slot());
- int color = highlight.color();
- context.fill(slot.x, slot.y, slot.x + 16, slot.y + 16, color);
- }
- RenderSystem.colorMask(true, true, true, true);
- }
-
- private Int2ObjectMap<ItemStack> slotMap(List<Slot> slots) {
- Int2ObjectMap<ItemStack> slotMap = new Int2ObjectRBTreeMap<>();
- for (int i = 0; i < slots.size(); i++) {
- slotMap.put(i, slots.get(i).getStack());
- }
- return slotMap;
- }
-}
diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json
index 875b45dd..984ef321 100644
--- a/src/main/resources/assets/skyblocker/lang/en_us.json
+++ b/src/main/resources/assets/skyblocker/lang/en_us.json
@@ -10,6 +10,7 @@
"key.skyblocker.toggleA": "Toggle tab HUD to screen A",
"key.wikiLookup": "Wiki Lookup",
"key.itemProtection": "Protect Item",
+ "key.skyblocker.slottext": "Slot Text",
"text.skyblocker.open": "Open",
"text.skyblocker.quit_config": "Changes Not Saved",
@@ -27,6 +28,9 @@
"skyblocker.config.title": "Skyblocker Settings",
+ "skyblocker.config.shortcutToKeybindsSettings": "Edit Keybind",
+ "skyblocker.config.shortcutToKeybindsSettings.@Text": "Click... (Opens up Keybinds Options)",
+
"skyblocker.config.crimsonIsle": "Crimson Isle",
"skyblocker.config.crimsonIsle.kuudra": "Kuudra",
@@ -472,9 +476,32 @@
"skyblocker.config.mining.crystalsWaypoints": "Crystal Hollows Waypoints",
"skyblocker.config.mining.crystalsWaypoints.enabled": "Enabled Waypoints",
"skyblocker.config.mining.crystalsWaypoints.enabled.@Tooltip": "Show a waypoint (waypoint selected in general/waypoints) at important areas in the crystal hollows, e.g., Jungle Temple and Fairy Grotto. ",
+ "skyblocker.config.mining.crystalsWaypoints.textScale": "Text Scale",
+ "skyblocker.config.mining.crystalsWaypoints.textScale.@Tooltip": "Scale the size of the commission labels.",
"skyblocker.config.mining.crystalsWaypoints.findInChat": "Find Waypoints In Chat",
"skyblocker.config.mining.crystalsWaypoints.findInChat.@Tooltip": "When in crystal hollows read the chat to see if coordinates are sent and extract these to show as waypoint or on the map",
+ "skyblocker.config.mining.crystalsWaypoints.addedWaypoint": "Added waypoint for '%s' at %d %d %d.",
+ "skyblocker.config.mining.crystalsWaypoints.noActive": "You have no active waypoints to share or remove.",
+ "skyblocker.config.mining.crystalsWaypoints.allActive": "You have no more waypoints left to create.",
+ "skyblocker.config.mining.crystalsWaypoints.markLocation": "Mark (%s) as: %s",
+ "skyblocker.config.mining.crystalsWaypoints.getLocationHover.add": "Add Location",
+ "skyblocker.config.mining.crystalsWaypoints.getLocationHover.remove": "Remove Location",
+ "skyblocker.config.mining.crystalsWaypoints.getLocationHover.share": "Share Location",
"skyblocker.config.mining.crystalsWaypoints.shareFail": "Can only share waypoints you have found.",
+ "skyblocker.config.mining.crystalsWaypoints.removeSuccess": "Removed waypoint for ",
+ "skyblocker.config.mining.crystalsWaypoints.removeFail": "Can only remove waypoints you have found.",
+ "skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver": "Wishing Compass Solver",
+ "skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.@Tooltip": "Calculates and adds a waypoint at the location indicated by wishing compasses.",
+ "skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.enableTabMessage": "Enable crystals in the /tab to allow the compass to identify discovered items",
+ "skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.wishingCompassUsedMessage": "Wishing compass used. Move to another location and use a second compass to triangulate the target",
+ "skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.somethingWentWrongMessage": "The lines did not intersect (Something went wrong) please try again.",
+ "skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.targetLocationToFar": "The target location is too far away to identify the structure, possibly due to a missing structure in the lobby.",
+ "skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.foundMessage": "Wishing compass solver found ",
+ "skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.useOutsideNucleusMessage": "Use compass outside of nucleus for better results",
+ "skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.moveFurtherMessage": "Move further away from the first use before using again",
+ "skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.changingZoneMessage": "Changed zone. Restarting...",
+ "skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.waitLongerMessage": "Wait a moment before using another wishing compass",
+ "skyblocker.config.mining.crystalsWaypoints.wishingCompassSolver.couldNotDetectLastUseMessage": "Unable to detect the last use. Restarting...",
"skyblocker.config.mining.dwarvenHud": "Dwarven HUD",
"skyblocker.config.mining.dwarvenHud.enabledCommissions": "Enable Commissions",
diff --git a/src/test/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationManagerTest.java b/src/test/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationManagerTest.java
index 4ce61880..aac4a641 100644
--- a/src/test/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationManagerTest.java
+++ b/src/test/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsLocationManagerTest.java
@@ -1,12 +1,35 @@
package de.hysky.skyblocker.skyblock.dwarven;
+import de.hysky.skyblocker.utils.Constants;
import net.minecraft.util.math.BlockPos;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
-import de.hysky.skyblocker.utils.Constants;
+class CrystalsLocationManagerTest {
+ boolean matches(String text) {
+ return CrystalsLocationsManager.TEXT_CWORDS_PATTERN.matcher(text).find();
+ }
-public class CrystalsLocationManagerTest {
+ @Test
+ void testRegex() {
+ Assertions.assertTrue(matches("Player: x123 y12 z123"));
+ Assertions.assertTrue(matches("Player: x123, y12, z123"));
+ Assertions.assertTrue(matches("Player: 123 12 123"));
+ Assertions.assertTrue(matches("Player: 123 123 123"));
+ Assertions.assertTrue(matches("Player: 123, 12, 123"));
+ Assertions.assertTrue(matches("Player: 123, 123, 123"));
+ Assertions.assertTrue(matches("Player: 123,12,123"));
+ Assertions.assertTrue(matches("Player: 123,123,123"));
+
+ Assertions.assertFalse(matches("Player: 123 1234 123"));
+ Assertions.assertFalse(matches("Player: 1234 12 123"));
+ Assertions.assertFalse(matches("Player: 123 12 1234"));
+ Assertions.assertFalse(matches("Player: 12 12 123"));
+ Assertions.assertFalse(matches("Player: 123 1 123"));
+ Assertions.assertFalse(matches("Player: 123 12 12"));
+ Assertions.assertFalse(matches("Player: 12312123"));
+ Assertions.assertFalse(matches("Player: 123123123"));
+ }
@Test
void testLocationInCrystals() {
@@ -26,7 +49,7 @@ public class CrystalsLocationManagerTest {
@Test
void testSetLocationMessage() {
- Assertions.assertEquals(CrystalsLocationsManager.getSetLocationMessage("Jungle Temple", new BlockPos(10, 11, 12)).getString(), Constants.PREFIX.get().getString() + "Added waypoint for Jungle Temple at : 10 11 12.");
- Assertions.assertEquals(CrystalsLocationsManager.getSetLocationMessage("Fairy Grotto", new BlockPos(0, 0, 0)).getString(), Constants.PREFIX.get().getString() + "Added waypoint for Fairy Grotto at : 0 0 0.");
+ Assertions.assertEquals(Constants.PREFIX.get().getString() + "Added waypoint for 'Jungle Temple' at 10 11 12.", CrystalsLocationsManager.getSetLocationMessage("Jungle Temple", new BlockPos(10, 11, 12)).getString());
+ Assertions.assertEquals(Constants.PREFIX.get().getString() + "Added waypoint for 'Fairy Grotto' at 0 0 0.", CrystalsLocationsManager.getSetLocationMessage("Fairy Grotto", new BlockPos(0, 0, 0)).getString());
}
}
diff --git a/src/test/java/de/hysky/skyblocker/skyblock/dwarven/WishingCompassSolverTest.java b/src/test/java/de/hysky/skyblocker/skyblock/dwarven/WishingCompassSolverTest.java
new file mode 100644
index 00000000..8da811a5
--- /dev/null
+++ b/src/test/java/de/hysky/skyblocker/skyblock/dwarven/WishingCompassSolverTest.java
@@ -0,0 +1,43 @@
+package de.hysky.skyblocker.skyblock.dwarven;
+
+import net.minecraft.util.math.Vec3d;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Objects;
+
+public class WishingCompassSolverTest {
+
+ @Test
+ void test2dSolve() {
+ Vec3d startPosOne = new Vec3d(100, 1, 0);
+ Vec3d startPosTwo = new Vec3d(0, 1, 100);
+ Vec3d directionOne = new Vec3d(-1, 0, 0);
+ Vec3d directionTwo = new Vec3d(0, 0, -1);
+ Assertions.assertEquals(WishingCompassSolver.solve(startPosOne, startPosTwo, directionOne, directionTwo), new Vec3d(0, 1, 0));
+
+ startPosOne = new Vec3d(100, 1, 100);
+ startPosTwo = new Vec3d(50, 1, 100);
+ directionOne = new Vec3d(-1, 0, -1);
+ directionTwo = new Vec3d(-0.5, 0, -1);
+ Assertions.assertEquals(WishingCompassSolver.solve(startPosOne, startPosTwo, directionOne, directionTwo), new Vec3d(0, 1, 0));
+ }
+
+ @Test
+ void test3dSolve() {
+ Vec3d startPosOne = new Vec3d(100, 200, 0);
+ Vec3d startPosTwo = new Vec3d(0, 0, 100);
+ Vec3d directionOne = new Vec3d(-1, -1, 0);
+ Vec3d directionTwo = new Vec3d(0, 1, -1);
+ Assertions.assertTrue(Objects.requireNonNull(WishingCompassSolver.solve(startPosOne, startPosTwo, directionOne, directionTwo)).distanceTo(new Vec3d(0, 100, 0))<0.1);
+ }
+
+ @Test
+ void testParallelSolve() {
+ Vec3d startPosOne = new Vec3d(100, 0, 0);
+ Vec3d startPosTwo = new Vec3d(50, 0, 0);
+ Vec3d directionOne = new Vec3d(-1, 0, 0);
+ Vec3d directionTwo = new Vec3d(-1, 0, 0);
+ Assertions.assertNull(WishingCompassSolver.solve(startPosOne, startPosTwo, directionOne, directionTwo));
+ }
+}