diff options
author | Rime <81419447+Emirlol@users.noreply.github.com> | 2024-05-11 14:08:59 +0300 |
---|---|---|
committer | Rime <81419447+Emirlol@users.noreply.github.com> | 2024-05-23 13:31:48 +0300 |
commit | e2f18c84ce2de2da228ff88b6b67fa5d46945255 (patch) | |
tree | 02625a4bbf8ebb72a19f9f98d43f68603f1ce4e6 /src/main/java/de | |
parent | 05a18be31a137148bcd446654c550eb2d713990c (diff) | |
download | Skyblocker-e2f18c84ce2de2da228ff88b6b67fa5d46945255.tar.gz Skyblocker-e2f18c84ce2de2da228ff88b6b67fa5d46945255.tar.bz2 Skyblocker-e2f18c84ce2de2da228ff88b6b67fa5d46945255.zip |
Add support for unemployed rabbits
- Refactored ItemUtils.getHeadTexture to use the property iterator instead of streams and return Optional<String> rather than empty string to make the results clear and easier to work with.
- Refactored regex matching logic in ChocolateFactorySolver.getCPSIncreaseFactor to a separate function
Diffstat (limited to 'src/main/java/de')
6 files changed, 68 insertions, 65 deletions
diff --git a/src/main/java/de/hysky/skyblocker/debug/Debug.java b/src/main/java/de/hysky/skyblocker/debug/Debug.java index d9ac668c..038e7a5a 100644 --- a/src/main/java/de/hysky/skyblocker/debug/Debug.java +++ b/src/main/java/de/hysky/skyblocker/debug/Debug.java @@ -83,9 +83,9 @@ public class Debug { Iterable<ItemStack> equippedItems = armorStand.getEquippedItems(); for (ItemStack stack : equippedItems) { - String texture = ItemUtils.getHeadTexture(stack); - - if (!texture.isEmpty()) context.getSource().sendFeedback(Text.of(texture)); + ItemUtils.getHeadTexture(stack).ifPresent(texture -> { + context.getSource().sendFeedback(Text.of(texture)); + }); } } 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 a59a5147..94c2b209 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -1,23 +1,15 @@ package de.hysky.skyblocker.skyblock.chocolatefactory; import de.hysky.skyblocker.config.SkyblockerConfigManager; -import de.hysky.skyblocker.skyblock.experiment.ExperimentSolver; +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.*; -import net.fabricmc.loader.impl.lib.sat4j.minisat.core.Solver; -import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; -import net.minecraft.component.DataComponentTypes; -import net.minecraft.component.type.LoreComponent; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtElement; -import net.minecraft.nbt.NbtList; import net.minecraft.text.Text; -import java.awt.*; import java.util.*; import java.util.List; import java.util.regex.Matcher; @@ -27,6 +19,7 @@ import java.util.stream.Collectors; public class ChocolateFactorySolver extends ContainerSolver { private static final Pattern CPS_PATTERN = Pattern.compile("\\+([\\d,]+) Chocolate per second"); private static final Pattern COST_PATTERN = Pattern.compile("Cost ([\\d,]+) Chocolate"); + private static final Pattern HIRE_PATTERN = Pattern.compile("(HIRE|PROMOTE) ➜ \\[\\d+] \\S+ *"); public ChocolateFactorySolver() { super("^Chocolate Factory$"); @@ -42,7 +35,6 @@ public class ChocolateFactorySolver extends ContainerSolver { markHighlightsDirty(); //Recalculate highlights when the screen is opened, which happens when upgrading rabbits } - //Todo: Handle unemployed rabbits as well. They have a different lore format. @Override protected List<ColorHighlight> getColors(String[] groups, Int2ObjectMap<ItemStack> slots) { Int2DoubleMap cpsIncreaseFactors = new Int2DoubleLinkedOpenHashMap(5); //There are only 5 rabbits on the screen. @@ -51,7 +43,7 @@ public class ChocolateFactorySolver extends ContainerSolver { ItemStack item = entry.getValue(); if (item.getItem() != Items.PLAYER_HEAD || item.isEmpty()) continue; - String lore = getLore(item); + String lore = getConcattedLore(item); if (lore.isBlank()) continue; OptionalDouble cpsIncreaseFactor = getCPSIncreaseFactor(lore); @@ -63,15 +55,13 @@ public class ChocolateFactorySolver extends ContainerSolver { return List.of(ColorHighlight.green(bestSlot.get().getIntKey())); } - private String getLore(ItemStack item) { - LoreComponent lore = item.get(DataComponentTypes.LORE); - if (lore == null || lore.lines().isEmpty()) return ""; - return lore.lines() - .stream() - .map(Text::getString) - .collect(Collectors.joining(" ")); //Join all lore lines into one string for ease of regexing -// The space is so that the regex pattern still matches even if the word is split into 2 lines, -// as normally the line end and line start contain no spaces and would not match the pattern when concatenated + private String getConcattedLore(ItemStack item) { + return ItemUtils.getLore(item) + .stream() + .map(Text::getString) + .collect(Collectors.joining(" ")); //Join all lore lines into one string for ease of regexing +// The space is so that the regex pattern still matches even if the word is split into 2 lines, +// as normally the line end and the line start contain no spaces and would not match the pattern when concatenated } /** @@ -82,15 +72,42 @@ public class ChocolateFactorySolver extends ContainerSolver { * @return The CPS increase factor of the item, or an empty optional if it couldn't be found */ private OptionalDouble getCPSIncreaseFactor(String lore) { - Matcher cpsMatcher = CPS_PATTERN.matcher(lore); - if (!cpsMatcher.find()) return OptionalDouble.empty(); - int currentCps = Integer.parseInt(cpsMatcher.group(1).replace(",", "")); - if (!cpsMatcher.find()) return OptionalDouble.empty(); //If there is no second match, we can't get the CPS increase - int nextCps = Integer.parseInt(cpsMatcher.group(1).replace(",", "")); - - Matcher costMatcher = COST_PATTERN.matcher(lore); - if (!costMatcher.find(cpsMatcher.end())) return OptionalDouble.empty(); //Cost is always at the end of the string, so we can start check from the end of the last match - int cost = Integer.parseInt(costMatcher.group(1).replace(",", "")); - return OptionalDouble.of((nextCps - currentCps) / (double) cost); + Matcher hireMatcher = HIRE_PATTERN.matcher(lore); + if (!hireMatcher.find()) return OptionalDouble.empty(); //Not a hireable/promotable rabbit. Could be a locked or maxed rabbit. + + switch (hireMatcher.group(1)) { + case "HIRE" -> { + Matcher cpsMatcher = CPS_PATTERN.matcher(lore); + OptionalInt cps = getValueFromMatcher(cpsMatcher, hireMatcher.end()); //Cps line is right after the hire line + if (cps.isEmpty()) return OptionalDouble.empty(); + + Matcher costMatcher = COST_PATTERN.matcher(lore); + OptionalInt cost = getValueFromMatcher(costMatcher, cpsMatcher.end()); //Cost comes after the cps line + if (cost.isEmpty()) return OptionalDouble.empty(); + return OptionalDouble.of(cps.getAsInt() / (double) cost.getAsInt()); + } + case "PROMOTE" -> { + Matcher cpsMatcher = CPS_PATTERN.matcher(lore); + OptionalInt currentCps = getValueFromMatcher(cpsMatcher); //Current cps is before the hire line + if (currentCps.isEmpty()) return OptionalDouble.empty(); + OptionalInt nextCps = getValueFromMatcher(cpsMatcher, hireMatcher.end()); //Next cps is right after the hire line + if (nextCps.isEmpty()) return OptionalDouble.empty(); + + Matcher costMatcher = COST_PATTERN.matcher(lore); + OptionalInt cost = getValueFromMatcher(costMatcher, cpsMatcher.end()); //Cost comes after the cps line + if (cost.isEmpty()) return OptionalDouble.empty(); + return OptionalDouble.of((nextCps.getAsInt() - currentCps.getAsInt()) / (double) cost.getAsInt()); + } + default -> { return OptionalDouble.empty(); } + } + } + + private OptionalInt getValueFromMatcher(Matcher matcher) { + return getValueFromMatcher(matcher, matcher.hasMatch() ? matcher.end() : 0); + } + + private OptionalInt getValueFromMatcher(Matcher matcher, int startingIndex) { + if (!matcher.find(startingIndex)) return OptionalInt.empty(); + return OptionalInt.of(Integer.parseInt(matcher.group(1).replace(",", ""))); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java index 7f8e9879..ee1d4aa7 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java @@ -3,6 +3,7 @@ package de.hysky.skyblocker.skyblock.chocolatefactory; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.ColorUtils; import de.hysky.skyblocker.utils.Constants; +import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.waypoint.Waypoint; import it.unimi.dsi.fastutil.objects.ObjectImmutableList; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; @@ -10,11 +11,9 @@ import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.minecraft.client.MinecraftClient; -import net.minecraft.component.DataComponentTypes; import net.minecraft.entity.Entity; import net.minecraft.entity.decoration.ArmorStandEntity; import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; import net.minecraft.text.Text; import org.apache.commons.lang3.mutable.MutableObject; import org.slf4j.Logger; @@ -46,26 +45,14 @@ public class EggFinder { if (BREAKFAST.egg.getValue() != null && DINNER.egg.getValue() != null && LUNCH.egg.getValue() != null) return; //Don't check for eggs if we already found all of them if (!(entity instanceof ArmorStandEntity armorStand) || armorStand.hasCustomName() || !armorStand.isInvisible() || !armorStand.shouldHideBasePlate()) return; for (ItemStack itemStack : armorStand.getArmorItems()) { - try { - if (!itemStack.isEmpty() || itemStack.getItem() == Items.PLAYER_HEAD) { - String texture = itemStack.getComponents() - .get(DataComponentTypes.PROFILE) - .properties() - .get("textures") - .iterator() - .next() - .value(); - - for (EggType type : EggType.entries) { - if (texture.equals(type.texture)) { - handleFoundEgg(armorStand, type); - return; - } + ItemUtils.getHeadTexture(itemStack).ifPresent(texture -> { + for (EggType type : EggType.entries) { + if (texture.equals(type.texture)) { + handleFoundEgg(armorStand, type); + return; } } - } catch (Exception e) { - //Ignored. This simply exists to make the code cleaner without a bunch of if statements to check the existence of each key. - } + }); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java index d6f9410b..df9a32c6 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/entity/MobGlow.java @@ -104,7 +104,7 @@ public class MobGlow { // eb07594e2df273921a77c101d0bfdfa1115abed5b9b2029eb496ceba9bdbb4b3 is texture id for the nukekubi head, // compare against it to exclusively find armorstands that are nukekubi heads // get the texture of the nukekubi head item itself and compare it - String texture = ItemUtils.getHeadTexture(armorItem); + String texture = ItemUtils.getHeadTexture(armorItem).orElse(""); return texture.contains("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWIwNzU5NGUyZGYyNzM5MjFhNzdjMTAxZDBiZmRmYTExMTVhYmVkNWI5YjIwMjllYjQ5NmNlYmE5YmRiYjRiMyJ9fX0="); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/garden/VisitorHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/garden/VisitorHelper.java index 682933f4..0f349a4f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/garden/VisitorHelper.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/garden/VisitorHelper.java @@ -94,9 +94,7 @@ public class VisitorHelper { } private static @Nullable String getTextureOrNull(ItemStack stack) { - String texture = ItemUtils.getHeadTexture(stack); - - return texture.isEmpty() ? null : texture; + return ItemUtils.getHeadTexture(stack).orElse(null); } private static void processLore(String visitorName, @Nullable String visitorTexture, List<Text> loreList) { diff --git a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java index 1aa77080..6b850b3b 100644 --- a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java @@ -33,6 +33,7 @@ import java.time.Instant; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAccessor; +import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Optional; @@ -202,16 +203,16 @@ public class ItemUtils { return Codecs.GAME_PROFILE_PROPERTY_MAP.parse(JsonOps.INSTANCE, JsonParser.parseString("[{\"name\":\"textures\",\"value\":\"" + textureValue + "\"}]")).getOrThrow(); } - public static String getHeadTexture(ItemStack stack) { - if (!stack.isOf(Items.PLAYER_HEAD) || !stack.contains(DataComponentTypes.PROFILE)) return ""; + public static Optional<String> getHeadTexture(ItemStack stack) { + if (!stack.isOf(Items.PLAYER_HEAD) || !stack.contains(DataComponentTypes.PROFILE)) return Optional.empty(); - ProfileComponent profile = stack.get(DataComponentTypes.PROFILE); - String texture = profile.properties().get("textures").stream() - .map(Property::value) - .findFirst() - .orElse(""); + Iterator<Property> iterator = stack.get(DataComponentTypes.PROFILE) + .properties() + .get("textures") + .iterator(); - return texture; + if (!iterator.hasNext()) return Optional.empty(); + return Optional.of(iterator.next().value()); } public static ItemStack getSkyblockerStack() { |