diff options
Diffstat (limited to 'src/main/java/de/hysky/skyblocker/utils')
12 files changed, 392 insertions, 245 deletions
diff --git a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java index 65807886..894ef8ec 100644 --- a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java @@ -283,4 +283,24 @@ public final class ItemUtils { throw new RuntimeException(e); } } + + /** + * Utility method. + */ + public static @NotNull String getConcatenatedLore(@NotNull ItemStack item) { + return concatenateLore(getLore(item)); + } + + /** + * Concatenates the lore of an item into one string. + * This is useful in case some pattern we're looking for is split into multiple lines, which would make it harder to regex. + */ + public static @NotNull String concatenateLore(@NotNull List<Text> lore) { + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < lore.size(); i++) { + stringBuilder.append(lore.get(i).getString()); + if (i != lore.size() - 1) stringBuilder.append(" "); + } + return stringBuilder.toString(); + } } diff --git a/src/main/java/de/hysky/skyblocker/utils/Utils.java b/src/main/java/de/hysky/skyblocker/utils/Utils.java index bbeb11b5..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; @@ -158,7 +158,7 @@ public class Utils { /** * Can be used to restrict features to being active only on the Alpha network. - * + * * @return the current environment parsed from the Mod API. */ @NotNull @@ -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..b67b9edf --- /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, + 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(); + 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; - } -} |