aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorAaron <51387595+AzureAaron@users.noreply.github.com>2024-08-14 01:39:08 -0400
committerGitHub <noreply@github.com>2024-08-14 01:39:08 -0400
commit931898c0846fba67e231c7318438338d42c0268f (patch)
tree8828d387aa88ebc341ddf15627817242e1cf3bc4 /src/main/java
parentac08fb6514defbac92876dc70e1ba98f7504ae24 (diff)
parent57f8844f1404076dcd950c3e8473cf7746d3a8fc (diff)
downloadSkyblocker-931898c0846fba67e231c7318438338d42c0268f.tar.gz
Skyblocker-931898c0846fba67e231c7318438338d42c0268f.tar.bz2
Skyblocker-931898c0846fba67e231c7318438338d42c0268f.zip
Merge pull request #918 from Emirlol/experiments-fix
Fix SuperpairsSolver not starting properly
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/de/hysky/skyblocker/SkyblockerMod.java3
-rw-r--r--src/main/java/de/hysky/skyblocker/mixins/GenericContainerScreenHandlerMixin.java6
-rw-r--r--src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java48
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/experiment/ChronomatronSolver.java226
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/experiment/ExperimentSolver.java34
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/experiment/SuperpairsSolver.java160
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/experiment/UltrasequencerSolver.java143
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/container/ContainerSolver.java9
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/container/ContainerSolverManager.java87
9 files changed, 380 insertions, 336 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
index 405827e0..4d302ac5 100644
--- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
+++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
@@ -87,7 +87,6 @@ public class SkyblockerMod implements ClientModInitializer {
public static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
public static final Gson GSON_COMPACT = new GsonBuilder().create();
private static SkyblockerMod INSTANCE;
- public final ContainerSolverManager containerSolverManager = new ContainerSolverManager();
public final StatusBarTracker statusBarTracker = new StatusBarTracker();
/**
@@ -202,7 +201,7 @@ public class SkyblockerMod implements ClientModInitializer {
FancyStatusBars.init();
SkyblockInventoryScreen.initEquipment();
EventNotifications.init();
- containerSolverManager.init();
+ ContainerSolverManager.init();
statusBarTracker.init();
BeaconHighlighter.init();
WarpAutocomplete.init();
diff --git a/src/main/java/de/hysky/skyblocker/mixins/GenericContainerScreenHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixins/GenericContainerScreenHandlerMixin.java
index 3c3dbd52..a487dbf9 100644
--- a/src/main/java/de/hysky/skyblocker/mixins/GenericContainerScreenHandlerMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixins/GenericContainerScreenHandlerMixin.java
@@ -1,9 +1,9 @@
package de.hysky.skyblocker.mixins;
-import de.hysky.skyblocker.SkyblockerMod;
import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen;
import de.hysky.skyblocker.skyblock.item.SkyblockInventoryScreen;
import de.hysky.skyblocker.utils.Utils;
+import de.hysky.skyblocker.utils.container.ContainerSolverManager;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
@@ -25,7 +25,7 @@ public abstract class GenericContainerScreenHandlerMixin extends ScreenHandler {
@Override
public void setStackInSlot(int slot, int revision, ItemStack stack) {
super.setStackInSlot(slot, revision, stack);
- SkyblockerMod.getInstance().containerSolverManager.markDirty();
+ ContainerSolverManager.markHighlightsDirty();
Screen currentScreen = MinecraftClient.getInstance().currentScreen;
switch (currentScreen) {
@@ -47,7 +47,7 @@ public abstract class GenericContainerScreenHandlerMixin extends ScreenHandler {
@Override
public void updateSlotStacks(int revision, List<ItemStack> stacks, ItemStack cursorStack) {
super.updateSlotStacks(revision, stacks, cursorStack);
- SkyblockerMod.getInstance().containerSolverManager.markDirty();
+ ContainerSolverManager.markHighlightsDirty();
if (MinecraftClient.getInstance().currentScreen instanceof PartyFinderScreen screen) {
screen.markDirty();
}
diff --git a/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java
index 2ef599dd..01147120 100644
--- a/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java
@@ -7,7 +7,6 @@ import de.hysky.skyblocker.config.SkyblockerConfig;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.skyblock.PetCache;
import de.hysky.skyblocker.skyblock.bazaar.BazaarHelper;
-import de.hysky.skyblocker.skyblock.experiment.ChronomatronSolver;
import de.hysky.skyblocker.skyblock.experiment.ExperimentSolver;
import de.hysky.skyblocker.skyblock.experiment.SuperpairsSolver;
import de.hysky.skyblocker.skyblock.experiment.UltrasequencerSolver;
@@ -24,11 +23,11 @@ import de.hysky.skyblocker.skyblock.quicknav.QuickNavButton;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.Utils;
import de.hysky.skyblocker.utils.container.ContainerSolver;
+import de.hysky.skyblocker.utils.container.ContainerSolverManager;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.inventory.SimpleInventory;
-import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.GenericContainerScreenHandler;
import net.minecraft.screen.ScreenHandler;
@@ -50,7 +49,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
@@ -208,11 +206,19 @@ public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen
}
/**
- * Redirects getStack calls to account for different stacks in experiment solvers.
+ * Avoids getting currentSolver again when it's already in the scope for some usages of this method.
+ * @see #skyblocker$experimentSolvers$getStack(Slot, ItemStack, ContainerSolver)
*/
@Unique
private ItemStack skyblocker$experimentSolvers$getStack(Slot slot, @NotNull ItemStack stack) {
- ContainerSolver currentSolver = SkyblockerMod.getInstance().containerSolverManager.getCurrentSolver();
+ return skyblocker$experimentSolvers$getStack(slot, stack, ContainerSolverManager.getCurrentSolver());
+ }
+
+ /**
+ * Redirects getStack calls to account for different stacks in experiment solvers.
+ */
+ @Unique
+ private ItemStack skyblocker$experimentSolvers$getStack(Slot slot, @NotNull ItemStack stack, ContainerSolver currentSolver) {
if ((currentSolver instanceof SuperpairsSolver || currentSolver instanceof UltrasequencerSolver) && ((ExperimentSolver) currentSolver).getState() == ExperimentSolver.State.SHOW && slot.inventory instanceof SimpleInventory) {
ItemStack itemStack = ((ExperimentSolver) currentSolver).getSlots().get(slot.getIndex());
return itemStack == null ? stack : itemStack;
@@ -239,13 +245,13 @@ public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen
if (slot == null) return;
String title = getTitle().getString();
- ItemStack stack = skyblocker$experimentSolvers$getStack(slot, slot.getStack());
- ContainerSolver currentSolver = SkyblockerMod.getInstance().containerSolverManager.getCurrentSolver();
+ ContainerSolver currentSolver = ContainerSolverManager.getCurrentSolver();
+ ItemStack stack = skyblocker$experimentSolvers$getStack(slot, slot.getStack(), currentSolver);
// Prevent clicks on filler items
if (SkyblockerConfigManager.get().uiAndVisuals.hideEmptyTooltips && FILLER_ITEMS.contains(stack.getName().getString()) &&
// Allow clicks in Ultrasequencer and Superpairs
- (!UltrasequencerSolver.INSTANCE.getTitlePattern().matcher(title).matches() || SkyblockerConfigManager.get().helpers.experiments.enableUltrasequencerSolver)) {
+ (!UltrasequencerSolver.INSTANCE.test(title) || SkyblockerConfigManager.get().helpers.experiments.enableUltrasequencerSolver)) {
ci.cancel();
return;
}
@@ -300,34 +306,10 @@ public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen
}
if (currentSolver != null) {
- boolean disallowed = SkyblockerMod.getInstance().containerSolverManager.onSlotClick(slotId, stack);
+ boolean disallowed = ContainerSolverManager.onSlotClick(slotId, stack);
if (disallowed) ci.cancel();
}
-
- // Experiment Solvers
- if (currentSolver instanceof ExperimentSolver experimentSolver && experimentSolver.getState() == ExperimentSolver.State.SHOW && slot.inventory instanceof SimpleInventory) {
- switch (experimentSolver) {
- case ChronomatronSolver chronomatronSolver -> {
- Item item = chronomatronSolver.getChronomatronSlots().get(chronomatronSolver.getChronomatronCurrentOrdinal());
- if ((stack.isOf(item) || ChronomatronSolver.TERRACOTTA_TO_GLASS.get(stack.getItem()) == item) && chronomatronSolver.incrementChronomatronCurrentOrdinal() >= chronomatronSolver.getChronomatronSlots().size()) {
- chronomatronSolver.setState(ExperimentSolver.State.END);
- }
- }
-
- case SuperpairsSolver superpairsSolver -> {
- superpairsSolver.setSuperpairsPrevClickedSlot(slot.getIndex());
- superpairsSolver.setSuperpairsCurrentSlot(ItemStack.EMPTY);
- }
-
- case UltrasequencerSolver ultrasequencerSolver when slot.getIndex() == ultrasequencerSolver.getUltrasequencerNextSlot() -> {
- int count = ultrasequencerSolver.getSlots().get(ultrasequencerSolver.getUltrasequencerNextSlot()).getCount() + 1;
- ultrasequencerSolver.getSlots().entrySet().stream().filter(entry -> entry.getValue().getCount() == count).findAny().map(Map.Entry::getKey).ifPresentOrElse(ultrasequencerSolver::setUltrasequencerNextSlot, () -> ultrasequencerSolver.setState(ExperimentSolver.State.END));
- }
-
- default -> { /*Do Nothing*/ }
- }
- }
}
@Inject(method = "drawSlot", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawItem(Lnet/minecraft/item/ItemStack;III)V"))
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 a4d34a1b..14bd3278 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/experiment/ChronomatronSolver.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/experiment/ChronomatronSolver.java
@@ -1,128 +1,144 @@
package de.hysky.skyblocker.skyblock.experiment;
-import com.google.common.collect.ImmutableMap;
-
import de.hysky.skyblocker.config.configs.HelperConfig;
import de.hysky.skyblocker.utils.render.gui.ColorHighlight;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import net.minecraft.client.gui.screen.Screen;
+import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
+import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
+import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
-import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.List;
public final class ChronomatronSolver extends ExperimentSolver {
- public static final ImmutableMap<Item, Item> TERRACOTTA_TO_GLASS = ImmutableMap.ofEntries(
- new AbstractMap.SimpleImmutableEntry<>(Items.RED_TERRACOTTA, Items.RED_STAINED_GLASS),
- new AbstractMap.SimpleImmutableEntry<>(Items.ORANGE_TERRACOTTA, Items.ORANGE_STAINED_GLASS),
- new AbstractMap.SimpleImmutableEntry<>(Items.YELLOW_TERRACOTTA, Items.YELLOW_STAINED_GLASS),
- new AbstractMap.SimpleImmutableEntry<>(Items.LIME_TERRACOTTA, Items.LIME_STAINED_GLASS),
- new AbstractMap.SimpleImmutableEntry<>(Items.GREEN_TERRACOTTA, Items.GREEN_STAINED_GLASS),
- new AbstractMap.SimpleImmutableEntry<>(Items.CYAN_TERRACOTTA, Items.CYAN_STAINED_GLASS),
- new AbstractMap.SimpleImmutableEntry<>(Items.LIGHT_BLUE_TERRACOTTA, Items.LIGHT_BLUE_STAINED_GLASS),
- new AbstractMap.SimpleImmutableEntry<>(Items.BLUE_TERRACOTTA, Items.BLUE_STAINED_GLASS),
- new AbstractMap.SimpleImmutableEntry<>(Items.PURPLE_TERRACOTTA, Items.PURPLE_STAINED_GLASS),
- new AbstractMap.SimpleImmutableEntry<>(Items.PINK_TERRACOTTA, Items.PINK_STAINED_GLASS)
- );
-
- private final List<Item> chronomatronSlots = new ArrayList<>();
- private int chronomatronChainLengthCount;
- private int chronomatronCurrentSlot;
- private int chronomatronCurrentOrdinal;
-
- public ChronomatronSolver() {
- super("^Chronomatron \\(\\w+\\)$");
- }
+ public static final Object2ObjectMap<Item, Item> TERRACOTTA_TO_GLASS = Object2ObjectMaps.unmodifiable(
+ new Object2ObjectArrayMap<>(
+ new Item[]{
+ Items.RED_TERRACOTTA, Items.ORANGE_TERRACOTTA, Items.YELLOW_TERRACOTTA, Items.LIME_TERRACOTTA, Items.GREEN_TERRACOTTA, Items.CYAN_TERRACOTTA, Items.LIGHT_BLUE_TERRACOTTA, Items.BLUE_TERRACOTTA, Items.PURPLE_TERRACOTTA, Items.PINK_TERRACOTTA
+ },
+ new Item[]{
+ Items.RED_STAINED_GLASS, Items.ORANGE_STAINED_GLASS, Items.YELLOW_STAINED_GLASS, Items.LIME_STAINED_GLASS, Items.GREEN_STAINED_GLASS, Items.CYAN_STAINED_GLASS, Items.LIGHT_BLUE_STAINED_GLASS, Items.BLUE_STAINED_GLASS, Items.PURPLE_STAINED_GLASS, Items.PINK_STAINED_GLASS
+ }
+ )
+ );
- public List<Item> getChronomatronSlots() {
- return chronomatronSlots;
- }
+ /**
+ * The list of items to remember, in order.
+ */
+ private final List<Item> chronomatronSlots = new ArrayList<>();
+ /**
+ * The index of the current item shown in the chain, used for remembering.
+ */
+ private int chronomatronChainLengthCount;
+ /**
+ * The slot id of the current item shown, used for detecting when the experiment finishes showing the current item.
+ */
+ private int chronomatronCurrentSlot;
+ /**
+ * The next index in the chain to click.
+ */
+ private int chronomatronCurrentOrdinal;
- public int getChronomatronCurrentOrdinal() {
- return chronomatronCurrentOrdinal;
- }
+ public ChronomatronSolver() {
+ super("^Chronomatron \\(\\w+\\)$");
+ }
- public int incrementChronomatronCurrentOrdinal() {
- return ++chronomatronCurrentOrdinal;
- }
+ @Override
+ protected boolean isEnabled(HelperConfig.Experiments experimentsConfig) {
+ return experimentsConfig.enableChronomatronSolver;
+ }
- @Override
- protected boolean isEnabled(HelperConfig.Experiments experimentsConfig) {
- return experimentsConfig.enableChronomatronSolver;
- }
+ @Override
+ protected void tick(GenericContainerScreen screen) {
+ switch (getState()) {
+ case REMEMBER -> {
+ Inventory inventory = screen.getScreenHandler().getInventory();
+ // Only try to look for items with enchantment glint if there is no item being currently shown.
+ if (chronomatronCurrentSlot == 0) {
+ for (int index = 10; index < 43; index++) {
+ if (inventory.getStack(index).hasGlint()) {
+ // If the list of items is smaller than the index of the current item shown, add the item to the list and set the state to wait.
+ if (chronomatronSlots.size() <= chronomatronChainLengthCount) {
+ chronomatronSlots.add(TERRACOTTA_TO_GLASS.get(inventory.getStack(index).getItem()));
+ setState(State.WAIT);
+ } else {
+ // If the item is already in the list, increment the current item shown index.
+ chronomatronChainLengthCount++;
+ }
+ // Remember the slot shown to detect when the experiment finishes showing the current item.
+ chronomatronCurrentSlot = index;
+ return;
+ }
+ }
+ // If the current item shown no longer has enchantment glint, the experiment finished showing the current item.
+ } else if (!inventory.getStack(chronomatronCurrentSlot).hasGlint()) {
+ chronomatronCurrentSlot = 0;
+ }
+ }
+ case WAIT -> {
+ if (screen.getScreenHandler().getInventory().getStack(49).getName().getString().startsWith("Timer: ")) {
+ setState(State.SHOW);
+ }
+ }
+ case END -> {
+ String name = screen.getScreenHandler().getInventory().getStack(49).getName().getString();
+ if (!name.startsWith("Timer: ")) {
+ // Get ready for another round if the instructions say to remember the pattern.
+ if (name.equals("Remember the pattern!")) {
+ chronomatronChainLengthCount = 0;
+ chronomatronCurrentOrdinal = 0;
+ setState(State.REMEMBER);
+ } else {
+ reset();
+ }
+ }
+ }
+ }
+ }
- @Override
- protected void tick(Screen screen) {
- if (isEnabled() && screen instanceof GenericContainerScreen genericContainerScreen && genericContainerScreen.getTitle().getString().startsWith("Chronomatron (")) {
- switch (getState()) {
- case REMEMBER -> {
- Inventory inventory = genericContainerScreen.getScreenHandler().getInventory();
- if (chronomatronCurrentSlot == 0) {
- for (int index = 10; index < 43; index++) {
- if (inventory.getStack(index).hasGlint()) {
- if (chronomatronSlots.size() <= chronomatronChainLengthCount) {
- chronomatronSlots.add(TERRACOTTA_TO_GLASS.get(inventory.getStack(index).getItem()));
- setState(State.WAIT);
- } else {
- chronomatronChainLengthCount++;
- }
- chronomatronCurrentSlot = index;
- return;
- }
- }
- } else if (!inventory.getStack(chronomatronCurrentSlot).hasGlint()) {
- chronomatronCurrentSlot = 0;
- }
- }
- case WAIT -> {
- if (genericContainerScreen.getScreenHandler().getInventory().getStack(49).getName().getString().startsWith("Timer: ")) {
- setState(State.SHOW);
- }
- }
- case END -> {
- String name = genericContainerScreen.getScreenHandler().getInventory().getStack(49).getName().getString();
- if (!name.startsWith("Timer: ")) {
- if (name.equals("Remember the pattern!")) {
- chronomatronChainLengthCount = 0;
- chronomatronCurrentOrdinal = 0;
- setState(State.REMEMBER);
- } else {
- reset();
- }
- }
- }
- }
- } else {
- reset();
- }
- }
+ /**
+ * Highlights the slots that contain the item at index {@link #chronomatronCurrentOrdinal} of {@link #chronomatronSlots} in the chain.
+ */
+ @Override
+ 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()) {
+ int index = indexStack.getIntKey();
+ ItemStack stack = indexStack.getValue();
+ Item item = chronomatronSlots.get(chronomatronCurrentOrdinal);
+ if (stack.isOf(item) || TERRACOTTA_TO_GLASS.get(stack.getItem()) == item) {
+ highlights.add(ColorHighlight.green(index));
+ }
+ }
+ }
+ return highlights;
+ }
- @Override
- 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()) {
- int index = indexStack.getIntKey();
- ItemStack stack = indexStack.getValue();
- Item item = chronomatronSlots.get(chronomatronCurrentOrdinal);
- if (stack.isOf(item) || TERRACOTTA_TO_GLASS.get(stack.getItem()) == item) {
- highlights.add(ColorHighlight.green(index));
- }
- }
- }
- return highlights;
- }
+ /**
+ * Increments {@link #chronomatronCurrentOrdinal} if the item clicked matches the item at {@link #chronomatronCurrentOrdinal the current index} in the chain.
+ */
+ @Override
+ public boolean onClickSlot(int slot, ItemStack stack, int screenId) {
+ if (getState() == State.SHOW) {
+ Item item = chronomatronSlots.get(chronomatronCurrentOrdinal);
+ if ((stack.isOf(item) || ChronomatronSolver.TERRACOTTA_TO_GLASS.get(stack.getItem()) == item) && ++chronomatronCurrentOrdinal >= chronomatronSlots.size()) {
+ setState(ExperimentSolver.State.END);
+ }
+ }
+ return super.onClickSlot(slot, stack, screenId);
+ }
- @Override
- public void reset() {
- chronomatronSlots.clear();
- chronomatronChainLengthCount = 0;
- chronomatronCurrentSlot = 0;
- chronomatronCurrentOrdinal = 0;
- }
+ @Override
+ public void reset() {
+ chronomatronSlots.clear();
+ chronomatronChainLengthCount = 0;
+ chronomatronCurrentSlot = 0;
+ chronomatronCurrentOrdinal = 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 808dce2e..9172f550 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/experiment/ExperimentSolver.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/experiment/ExperimentSolver.java
@@ -3,20 +3,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.container.SimpleContainerSolver;
-import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
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;
+/**
+ * The general class for all experiment solvers, implemented with a state machine.
+ */
public abstract sealed class ExperimentSolver extends SimpleContainerSolver permits ChronomatronSolver, SuperpairsSolver, UltrasequencerSolver {
- public enum State {
- REMEMBER, WAIT, SHOW, END
- }
-
private State state = State.REMEMBER;
private final Int2ObjectMap<ItemStack> slots = new Int2ObjectOpenHashMap<>();
@@ -46,7 +44,8 @@ public abstract sealed class ExperimentSolver extends SimpleContainerSolver perm
@Override
public void start(GenericContainerScreen screen) {
state = State.REMEMBER;
- ScreenEvents.afterTick(screen).register(this::tick);
+ //No reason to use the screen lambda argument given by `register` as it narrows down the type of our screen for no reason
+ ScreenEvents.afterTick(screen).register(ignored -> tick(screen));
}
@Override
@@ -55,5 +54,24 @@ public abstract sealed class ExperimentSolver extends SimpleContainerSolver perm
slots.clear();
}
- protected abstract void tick(Screen screen);
+ protected abstract void tick(GenericContainerScreen screen);
+
+ public enum State {
+ /**
+ * The state where the player has to remember the pattern.
+ */
+ REMEMBER,
+ /**
+ * The state where the solver has remembered the pattern and is waiting for the show state.
+ */
+ WAIT,
+ /**
+ * The state where the player has to recall the pattern and where the solver shows the player the pattern.
+ */
+ SHOW,
+ /**
+ * The state where the player has finished recalling the pattern and the current round is over.
+ */
+ END
+ }
}
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 7dc76b1d..31909564 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/experiment/SuperpairsSolver.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/experiment/SuperpairsSolver.java
@@ -3,84 +3,112 @@ package de.hysky.skyblocker.skyblock.experiment;
import de.hysky.skyblocker.config.configs.HelperConfig;
import de.hysky.skyblocker.utils.render.gui.ColorHighlight;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
+import it.unimi.dsi.fastutil.ints.IntArraySet;
import it.unimi.dsi.fastutil.ints.IntSet;
-import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
public final class SuperpairsSolver extends ExperimentSolver {
- private int superpairsPrevClickedSlot;
- private ItemStack superpairsCurrentSlot;
- private final IntSet superpairsDuplicatedSlots = new IntOpenHashSet();
+ /**
+ * The slot id of the last clicked slot.
+ */
+ private int superpairsPrevClickedSlot = 0;
+ /**
+ * The item stack of the last clicked slot.
+ */
+ private ItemStack superpairsCurrentSlot = ItemStack.EMPTY;
+ /**
+ * The set of slot ids that contain duplicated items.
+ */
+ private final IntSet superpairsDuplicatedSlots = new IntArraySet(28);
- public SuperpairsSolver() {
- super("^Superpairs \\(\\w+\\)$");
- }
+ public SuperpairsSolver() {
+ super("^Superpairs \\(\\w+\\)$");
+ }
- public void setSuperpairsPrevClickedSlot(int superpairsPrevClickedSlot) {
- this.superpairsPrevClickedSlot = superpairsPrevClickedSlot;
- }
+ @Override
+ protected boolean isEnabled(HelperConfig.Experiments experimentsConfig) {
+ return experimentsConfig.enableSuperpairsSolver;
+ }
- public void setSuperpairsCurrentSlot(ItemStack superpairsCurrentSlot) {
- this.superpairsCurrentSlot = superpairsCurrentSlot;
- }
+ /**
+ * Sets the state to {@link State#SHOW} since Superpairs does not require a state machine.
+ * @param screen
+ */
+ @Override
+ public void start(GenericContainerScreen screen) {
+ super.start(screen);
+ setState(State.SHOW);
+ }
- @Override
- protected boolean isEnabled(HelperConfig.Experiments experimentsConfig) {
- return experimentsConfig.enableSuperpairsSolver;
- }
+ /**
+ * Checks the screen if the item of the last clicked slot is unknown.
+ * Adds duplicated items to the item of the last clicked slot to {@link #superpairsDuplicatedSlots},
+ * save the item of the last clicked slot to the slot map,
+ * and sets {@link #superpairsCurrentSlot} to the item of the last clicked slot.
+ */
+ @Override
+ protected void tick(GenericContainerScreen screen) {
+ if (getState() == State.SHOW && getSlots().get(superpairsPrevClickedSlot) == null) {
+ ItemStack itemStack = screen.getScreenHandler().getInventory().getStack(superpairsPrevClickedSlot);
+ if (!(itemStack.isOf(Items.CYAN_STAINED_GLASS) || itemStack.isOf(Items.BLACK_STAINED_GLASS_PANE) || itemStack.isOf(Items.AIR))) {
+ getSlots().int2ObjectEntrySet().stream()
+ .filter(entry -> ItemStack.areEqual(entry.getValue(), itemStack))
+ .findAny()
+ .ifPresent(entry -> {
+ superpairsDuplicatedSlots.add(entry.getIntKey());
+ superpairsDuplicatedSlots.add(superpairsPrevClickedSlot);
+ });
+ getSlots().put(superpairsPrevClickedSlot, itemStack);
+ superpairsCurrentSlot = itemStack;
+ }
+ }
+ }
- @Override
- public void start(GenericContainerScreen screen) {
- setState(State.SHOW);
- }
+ /**
+ * Displays a green highlight on the slot that matches {@link #superpairsCurrentSlot} and the experiment is waiting for a second click.
+ * Displays a yellow highlight on the slots that contain duplicated items.
+ * Displays a red highlight on the slots that do not match anything.
+ */
+ @Override
+ public List<ColorHighlight> getColors(Int2ObjectMap<ItemStack> displaySlots) {
+ List<ColorHighlight> highlights = new ArrayList<>();
+ if (getState() == State.SHOW) {
+ for (Int2ObjectMap.Entry<ItemStack> indexStack : displaySlots.int2ObjectEntrySet()) {
+ int index = indexStack.getIntKey();
+ ItemStack displayStack = indexStack.getValue();
+ ItemStack stack = getSlots().get(index);
+ if (stack != null && !ItemStack.areEqual(stack, displayStack)) {
+ if (ItemStack.areEqual(superpairsCurrentSlot, stack) && displayStack.getName().getString().equals("Click a second button!")) {
+ highlights.add(ColorHighlight.green(index));
+ } else if (superpairsDuplicatedSlots.contains(index)) {
+ highlights.add(ColorHighlight.yellow(index));
+ } else {
+ highlights.add(ColorHighlight.red(index));
+ }
+ }
+ }
+ }
+ return highlights;
+ }
- @Override
- public void reset() {
- superpairsPrevClickedSlot = 0;
- superpairsCurrentSlot = null;
- superpairsDuplicatedSlots.clear();
- }
+ @Override
+ public boolean onClickSlot(int slot, ItemStack stack, int screenId) {
+ if (getState() == State.SHOW) {
+ this.superpairsPrevClickedSlot = slot;
+ this.superpairsCurrentSlot = ItemStack.EMPTY;
+ }
+ return super.onClickSlot(slot, stack, screenId);
+ }
- @Override
- protected void tick(Screen screen) {
- if (isEnabled() && screen instanceof GenericContainerScreen genericContainerScreen && genericContainerScreen.getTitle().getString().startsWith("Superpairs (")) {
- if (getState() == State.SHOW && getSlots().get(superpairsPrevClickedSlot) == null) {
- ItemStack itemStack = genericContainerScreen.getScreenHandler().getInventory().getStack(superpairsPrevClickedSlot);
- if (!(itemStack.isOf(Items.CYAN_STAINED_GLASS) || itemStack.isOf(Items.BLACK_STAINED_GLASS_PANE) || itemStack.isOf(Items.AIR))) {
- getSlots().int2ObjectEntrySet().stream().filter((entry -> ItemStack.areEqual(entry.getValue(), itemStack))).findAny().ifPresent(entry -> superpairsDuplicatedSlots.add(entry.getIntKey()));
- getSlots().put(superpairsPrevClickedSlot, itemStack);
- superpairsCurrentSlot = itemStack;
- }
- }
- } else {
- reset();
- }
- }
-
- @Override
- public List<ColorHighlight> getColors(Int2ObjectMap<ItemStack> displaySlots) {
- List<ColorHighlight> highlights = new ArrayList<>();
- if (getState() == State.SHOW) {
- for (Int2ObjectMap.Entry<ItemStack> indexStack : displaySlots.int2ObjectEntrySet()) {
- int index = indexStack.getIntKey();
- ItemStack displayStack = indexStack.getValue();
- ItemStack stack = getSlots().get(index);
- if (stack != null && !ItemStack.areEqual(stack, displayStack)) {
- if (ItemStack.areEqual(superpairsCurrentSlot, stack) && displayStack.getName().getString().equals("Click a second button!")) {
- highlights.add(ColorHighlight.green(index));
- } else if (superpairsDuplicatedSlots.contains(index)) {
- highlights.add(ColorHighlight.yellow(index));
- } else {
- highlights.add(ColorHighlight.red(index));
- }
- }
- }
- }
- return highlights;
- }
+ @Override
+ public void reset() {
+ superpairsPrevClickedSlot = 0;
+ superpairsCurrentSlot = ItemStack.EMPTY;
+ superpairsDuplicatedSlots.clear();
+ }
}
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 f39c1ffe..1b731565 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/experiment/UltrasequencerSolver.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/experiment/UltrasequencerSolver.java
@@ -1,83 +1,96 @@
package de.hysky.skyblocker.skyblock.experiment;
import de.hysky.skyblocker.config.configs.HelperConfig;
+import de.hysky.skyblocker.utils.container.ContainerSolverManager;
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;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
-import java.util.ArrayList;
import java.util.List;
public final class UltrasequencerSolver extends ExperimentSolver {
- public static final UltrasequencerSolver INSTANCE = new UltrasequencerSolver();
- private int ultrasequencerNextSlot;
+ public static final UltrasequencerSolver INSTANCE = new UltrasequencerSolver();
+ /**
+ * The slot id of the next slot to click.
+ */
+ private int ultrasequencerNextSlot;
- private UltrasequencerSolver() {
- super("^Ultrasequencer \\(\\w+\\)$");
- }
+ private UltrasequencerSolver() {
+ super("^Ultrasequencer \\(\\w+\\)$");
+ }
- public int getUltrasequencerNextSlot() {
- return ultrasequencerNextSlot;
- }
+ @Override
+ protected boolean isEnabled(HelperConfig.Experiments experimentsConfig) {
+ return experimentsConfig.enableUltrasequencerSolver;
+ }
- public void setUltrasequencerNextSlot(int ultrasequencerNextSlot) {
- this.ultrasequencerNextSlot = ultrasequencerNextSlot;
- }
+ /**
+ * Saves the shown items to {@link #slots the slot map}.
+ */
+ @SuppressWarnings("JavadocReference")
+ @Override
+ protected void tick(GenericContainerScreen screen) {
+ switch (getState()) {
+ case REMEMBER -> {
+ Inventory inventory = screen.getScreenHandler().getInventory();
+ if (inventory.getStack(49).getName().getString().equals("Remember the pattern!")) {
+ for (int index = 9; index < 45; index++) {
+ ItemStack itemStack = inventory.getStack(index);
+ String name = itemStack.getName().getString();
+ // Remember the item if its name is a number
+ if (name.matches("\\d+")) {
+ // Set the next slot to click to the item with the name "1"
+ if (name.equals("1")) {
+ ultrasequencerNextSlot = index;
+ }
+ // Save the item to the slot map
+ getSlots().put(index,