Skip to content

Commit

Permalink
Merge pull request #728 from Emirlol/bazaar-highlight
Browse files Browse the repository at this point in the history
Bazaar Helper
  • Loading branch information
kevinthegreat1 authored Jul 14, 2024
2 parents 1c25c8d + bc46261 commit f34b2aa
Show file tree
Hide file tree
Showing 14 changed files with 246 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import de.hysky.skyblocker.config.ConfigUtils;
import de.hysky.skyblocker.config.SkyblockerConfig;
import de.hysky.skyblocker.skyblock.bazaar.BazaarHelper;
import de.hysky.skyblocker.utils.waypoint.Waypoint;
import dev.isxander.yacl3.api.ConfigCategory;
import dev.isxander.yacl3.api.Option;
Expand Down Expand Up @@ -206,6 +207,20 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig
.build())
.build())

//Bazaar
.group(OptionGroup.createBuilder()
.name(Text.translatable("skyblocker.config.helpers.bazaar"))
.collapsed(true)
.option(Option.<Boolean>createBuilder()
.name(Text.translatable("skyblocker.config.helpers.bazaar.enableBazaarHelper"))
.description(OptionDescription.of(Text.translatable("skyblocker.config.helpers.bazaar.enableBazaarHelper.@Tooltip", BazaarHelper.getExpiringIcon(), BazaarHelper.getExpiredIcon(), BazaarHelper.getFilledIcon(69), BazaarHelper.getFilledIcon(100))))
.binding(defaults.helpers.bazaar.enableBazaarHelper,
() -> config.helpers.bazaar.enableBazaarHelper,
newValue -> config.helpers.bazaar.enableBazaarHelper = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
.build())

.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ public class HelperConfig {
@SerialEntry
public ChocolateFactory chocolateFactory = new ChocolateFactory();

@SerialEntry
public Bazaar bazaar = new Bazaar();

public static class MythologicalRitual {
@SerialEntry
public boolean enableMythologicalRitualHelper = true;
Expand Down Expand Up @@ -94,4 +97,9 @@ public static class ChocolateFactory {
@SerialEntry
public boolean straySound = true;
}

public static class Bazaar {
@SerialEntry
public boolean enableBazaarHelper = true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package de.hysky.skyblocker.skyblock.bazaar;

import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.skyblock.item.slottext.SlotText;
import de.hysky.skyblocker.skyblock.item.slottext.SlotTextAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import org.apache.commons.lang3.math.NumberUtils;
import org.jetbrains.annotations.NotNull;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class BazaarHelper extends SlotTextAdder {
private static final Pattern FILLED_PATTERN = Pattern.compile("Filled: \\S+ \\(?([\\d.]+)%\\)?!?");
private static final int RED = 0xe60b1e;
private static final int YELLOW = 0xe6ba0b;
private static final int GREEN = 0x1ee60b;

public BazaarHelper() {
super("(?:Co-op|Your) Bazaar Orders");
}

@Override
public @NotNull List<SlotText> getText(Slot slot) {
if (!SkyblockerConfigManager.get().helpers.bazaar.enableBazaarHelper) return List.of();
// Skip the first row as it's always glass panes.
if (slot.id < 10) return List.of();
// Skip the last 10 items. 11 is subtracted because size is 1-based so the last slot is size - 1.
if (slot.id > slot.inventory.size() - 11) return List.of(); //Note that this also skips the slots in player's inventory (anything above 36/45/54 depending on the order count)

int column = slot.id % 9;
if (column == 0 || column == 8) return List.of(); // Skip the first and last column as those are always glass panes as well.

ItemStack item = slot.getStack();
if (item.isEmpty()) return List.of(); //We've skipped all invalid slots, so we can just check if it's not air here.

Matcher matcher = ItemUtils.getLoreLineIfMatch(item, FILLED_PATTERN);
if (matcher != null) {
List<Text> lore = ItemUtils.getLore(item);
if (!lore.isEmpty() && lore.getLast().getString().equals("Click to claim!")) { //Only show the filled icon when there are items to claim
int filled = NumberUtils.toInt(matcher.group(1));
return SlotText.topLeftList(getFilledIcon(filled));
}
}

if (ItemUtils.getLoreLineIf(item, str -> str.equals("Expired!")) != null) {
return SlotText.topLeftList(getExpiredIcon());
} else if (ItemUtils.getLoreLineIf(item, str -> str.startsWith("Expires in")) != null) {
return SlotText.topLeftList(getExpiringIcon());
}

return List.of();
}

public static @NotNull MutableText getExpiredIcon() {
return Text.literal("⏰").withColor(RED).formatted(Formatting.BOLD);
}

public static @NotNull MutableText getExpiringIcon() {
return Text.literal("⏰").withColor(YELLOW).formatted(Formatting.BOLD);
}

public static @NotNull MutableText getFilledIcon(int filled) {
if (filled < 100) return Text.literal("%").withColor(YELLOW).formatted(Formatting.BOLD);
return Text.literal("✅").withColor(GREEN).formatted(Formatting.BOLD);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package de.hysky.skyblocker.skyblock.bazaar;

import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.render.gui.ColorHighlight;
import de.hysky.skyblocker.utils.render.gui.ContainerSolver;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.util.InputUtil;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ReorderHelper extends ContainerSolver {
private static final Pattern BUY_PATTERN = Pattern.compile("([\\d,]+)x missing items\\.");
private static final Pattern SELL_PATTERN = Pattern.compile("([\\d,]+)x items\\.");

public ReorderHelper() {
super("^Order options");
}

@Override
protected boolean isEnabled() {
return true;
}

@Override
protected boolean onClickSlot(int slot, ItemStack stack, int screenId, String[] groups) {
// V This part is so that it short-circuits if not necessary
if ((slot == 11 || slot == 13) && stack.isOf(Items.GREEN_TERRACOTTA) && InputUtil.isKeyPressed(MinecraftClient.getInstance().getWindow().getHandle(), GLFW.GLFW_KEY_LEFT_CONTROL)) {
Matcher matcher;
// The terracotta is at slot 13 on sell orders and at slot 11 on buy orders
if (slot == 13) matcher = ItemUtils.getLoreLineIfContainsMatch(stack, SELL_PATTERN);
else matcher = ItemUtils.getLoreLineIfContainsMatch(stack, BUY_PATTERN);
if (matcher != null) {
MinecraftClient.getInstance().keyboard.setClipboard(matcher.group(1).replace(",", ""));
return false;
}
}
return false;
}

@Override
protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) {
return List.of();
}

public static class Tooltip extends TooltipAdder {
public Tooltip() {
super("^Order options", Integer.MIN_VALUE);
}

@Override
public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) {
if (focusedSlot == null || !stack.isOf(Items.GREEN_TERRACOTTA)) return;
switch (focusedSlot.id) {
case 11, 13 -> {
lines.add(Text.empty());
lines.add(Text.empty().append(Text.translatable("skyblocker.reorderHelper.tooltip.line1")).formatted(Formatting.DARK_GRAY, Formatting.ITALIC));
lines.add(Text.empty().append(Text.translatable("skyblocker.reorderHelper.tooltip.line2")).formatted(Formatting.DARK_GRAY, Formatting.ITALIC));
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

import de.hysky.skyblocker.utils.chat.ChatPatternListener;
import net.minecraft.text.Text;
import org.intellij.lang.annotations.Language;

import java.util.regex.Matcher;

public abstract class SimpleChatFilter extends ChatPatternListener {
public SimpleChatFilter(String pattern) {
protected SimpleChatFilter(@Language("RegExp") String pattern) {
super(pattern);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package de.hysky.skyblocker.skyblock.item.slottext;

import it.unimi.dsi.fastutil.objects.ObjectLists;
import net.minecraft.text.Text;

import java.util.List;

public record SlotText(Text text, TextPosition position) {
public static SlotText bottomLeft(Text text) {
return new SlotText(text, TextPosition.BOTTOM_LEFT);
Expand All @@ -18,4 +21,20 @@ public static SlotText topLeft(Text text) {
public static SlotText topRight(Text text) {
return new SlotText(text, TextPosition.TOP_RIGHT);
}

public static List<SlotText> topLeftList(Text text) {
return ObjectLists.singleton(topLeft(text));
}

public static List<SlotText> topRightList(Text text) {
return ObjectLists.singleton(topRight(text));
}

public static List<SlotText> bottomLeftList(Text text) {
return ObjectLists.singleton(bottomLeft(text));
}

public static List<SlotText> bottomRightList(Text text) {
return ObjectLists.singleton(bottomRight(text));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package de.hysky.skyblocker.skyblock.item.slottext;

import de.hysky.skyblocker.skyblock.bazaar.BazaarHelper;
import de.hysky.skyblocker.skyblock.item.slottext.adders.*;
import de.hysky.skyblocker.utils.Utils;
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
Expand Down Expand Up @@ -30,6 +31,7 @@ public class SlotTextManager {
new CommunityShopAdder(),
new YourEssenceAdder(),
new PowerStonesGuideAdder(),
new BazaarHelper(),
new StatsTuningAdder()
};
private static final ArrayList<SlotTextAdder> currentScreenAdders = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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;
Expand All @@ -19,7 +20,7 @@ public abstract class TooltipAdder extends AbstractContainerMatcher {
*/
public final int priority;

protected TooltipAdder(String titlePattern, int priority) {
protected TooltipAdder(@Language("RegExp") String titlePattern, int priority) {
super(titlePattern);
this.priority = priority;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.hysky.skyblocker.skyblock.item.tooltip;

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;
Expand All @@ -24,6 +25,7 @@ public class TooltipManager {
new LineSmoothener(), // Applies before anything else
new SupercraftReminder(),
new ChocolateFactorySolver.Tooltip(),
new ReorderHelper.Tooltip(),
new NpcPriceTooltip(1),
new BazaarPriceTooltip(2),
new LBinTooltip(3),
Expand Down
47 changes: 36 additions & 11 deletions src/main/java/de/hysky/skyblocker/utils/ItemUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@

import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal;

public class ItemUtils {
public final class ItemUtils {
public static final String ID = "id";
public static final String UUID = "uuid";
public static final Pattern NOT_DURABILITY = Pattern.compile("[^0-9 /]");
Expand All @@ -55,6 +55,8 @@ public class ItemUtils {
ComponentChanges.CODEC.optionalFieldOf("components", ComponentChanges.EMPTY).forGetter(ItemStack::getComponentChanges)
).apply(instance, ItemStack::new)));

private ItemUtils() {}

public static LiteralArgumentBuilder<FabricClientCommandSource> dumpHeldItemCommand() {
return literal("dumpHeldItem").executes(context -> {
context.getSource().sendFeedback(Text.literal("[Skyblocker Debug] Held Item: " + SkyblockerMod.GSON_COMPACT.toJson(ItemStack.CODEC.encodeStart(JsonOps.INSTANCE, context.getSource().getPlayer().getMainHandStack()).getOrThrow())));
Expand Down Expand Up @@ -198,9 +200,13 @@ public static IntIntPair getDurability(@NotNull ItemStack stack) {
return null;
}

/**
* Gets the first line of the lore that matches the specified predicate.
* @return The first line of the lore that matches the predicate, or {@code null} if no line matches.
*/
@Nullable
public static String getLoreLineIf(ItemStack item, Predicate<String> predicate) {
for (Text line : getLore(item)) {
public static String getLoreLineIf(ItemStack stack, Predicate<String> predicate) {
for (Text line : getLore(stack)) {
String string = line.getString();
if (predicate.test(string)) {
return string;
Expand All @@ -210,21 +216,40 @@ public static String getLoreLineIf(ItemStack item, Predicate<String> predicate)
return null;
}

/**
* Gets the first line of the lore that matches the specified pattern, using {@link Matcher#matches()}.
* @return A matcher that contains match results if the pattern was found in the lore, otherwise {@code null}.
*/
@Nullable
public static Matcher getLoreLineIfMatch(ItemStack item, Pattern pattern) {
for (Text line : getLore(item)) {
String string = line.getString();
Matcher matcher = pattern.matcher(string);
if (matcher.matches()) {
public static Matcher getLoreLineIfMatch(ItemStack stack, Pattern pattern) {
Matcher matcher = pattern.matcher("");
for (Text line : getLore(stack)) {
if (matcher.reset(line.getString()).matches()) {
return matcher;
}
}

return null;
}

public static @NotNull List<Text> getLore(ItemStack item) {
return item.getOrDefault(DataComponentTypes.LORE, LoreComponent.DEFAULT).styledLines();
/**
* Gets the first line of the lore that matches the specified pattern, using {@link Matcher#find()}.
* @param pattern the pattern to search for
* @param stack the stack to search the lore of
* @return A {@link Matcher matcher} that contains match results if the pattern was found in the lore, otherwise {@code null}.
*/
@Nullable
public static Matcher getLoreLineIfContainsMatch(ItemStack stack, Pattern pattern) {
Matcher matcher = pattern.matcher("");
for (Text line : getLore(stack)) {
if (matcher.reset(line.getString()).find()) {
return matcher;
}
}
return null;
}

public static @NotNull List<Text> getLore(ItemStack stack) {
return stack.getOrDefault(DataComponentTypes.LORE, LoreComponent.DEFAULT).styledLines();
}

public static @NotNull PropertyMap propertyMapWithTexture(String textureValue) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.hysky.skyblocker.utils.chat;

import net.minecraft.text.Text;
import org.intellij.lang.annotations.Language;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand All @@ -9,7 +10,7 @@ public abstract class ChatPatternListener implements ChatMessageListener {
protected static final String NUMBER = "-?[0-9]{1,3}(?>,[0-9]{3})*(?:\\.[1-9])?";
public final Pattern pattern;

public ChatPatternListener(String pattern) {
protected ChatPatternListener(@Language("RegExp") String pattern) {
this.pattern = Pattern.compile(pattern);
}

Expand Down
Loading

0 comments on commit f34b2aa

Please sign in to comment.