From a8c689dd3a0fd6823053f1580993008c84d29ae2 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Sat, 4 May 2024 15:20:10 +0300 Subject: Add chocolate factory helper Highlights the best pick based on the price and CPS gain. --- .../skyblocker/mixins/HandledScreenMixin.java | 4 + .../chocolatefactory/ChocolateFactorySolver.java | 93 ++++++++++++++++++++++ .../utils/render/gui/ContainerSolverManager.java | 4 +- 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java index f662be7c..87b1bc79 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java @@ -4,6 +4,7 @@ import com.llamalad7.mixinextras.sugar.Local; import com.mojang.blaze3d.systems.RenderSystem; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.chocolatefactory.ChocolateFactorySolver; import de.hysky.skyblocker.skyblock.experiment.ChronomatronSolver; import de.hysky.skyblocker.skyblock.experiment.ExperimentSolver; import de.hysky.skyblocker.skyblock.experiment.SuperpairsSolver; @@ -284,6 +285,9 @@ public abstract class HandledScreenMixin extends Screen default -> { /*Do Nothing*/ } } } + if (currentSolver instanceof ChocolateFactorySolver chocolateFactorySolver) { + chocolateFactorySolver.markDirty(); + } } @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/chocolatefactory/ChocolateFactorySolver.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java new file mode 100644 index 00000000..ef79cd41 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -0,0 +1,93 @@ +package de.hysky.skyblocker.skyblock.chocolatefactory; + +import de.hysky.skyblocker.skyblock.experiment.ExperimentSolver; +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.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; +import java.util.regex.Pattern; +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"); + + public ChocolateFactorySolver() { + super("^Chocolate Factory$"); + } + + @Override + protected boolean isEnabled() { + return true; //Todo: add a config option and check if it's enabled from there + } + + @Override + protected List getColors(String[] groups, Map slots) { + Int2DoubleMap cpsIncreaseFactors = new Int2DoubleLinkedOpenHashMap(5); //There are only 5 rabbits on the screen. + for (Map.Entry entry : slots.entrySet()) { + ItemStack item = entry.getValue(); + if (item.getItem() != Items.PLAYER_HEAD || !item.hasNbt() || item.isEmpty()) continue; + + String lore = getLore(item); + if (lore.isBlank()) continue; + + OptionalDouble cpsIncreaseFactor = getCPSIncreaseFactor(lore); + if (cpsIncreaseFactor.isEmpty()) continue; //Something went wrong, skip this item + cpsIncreaseFactors.put(entry.getKey().intValue(), cpsIncreaseFactor.getAsDouble()); + } + Optional bestSlot = cpsIncreaseFactors.int2DoubleEntrySet().stream().max(Map.Entry.comparingByValue()); + if (bestSlot.isEmpty()) return List.of(); //No valid slots found, somehow. This means something went wrong, despite all the checks thus far. + return List.of(ColorHighlight.green(bestSlot.get().getIntKey())); + } + + private String getLore(ItemStack item) { + NbtCompound display = item.getSubNbt(ItemStack.DISPLAY_KEY); + if (display == null || display.isEmpty() || !display.contains(ItemStack.LORE_KEY, NbtElement.LIST_TYPE)) return ""; + NbtList lore = display.getList(ItemStack.LORE_KEY, NbtElement.STRING_TYPE); + return lore.stream() + .map(NbtElement::asString) + .map(Text.Serialization::fromJson) //Serialize the nbt string into a text to get the content string + .filter(Objects::nonNull) + .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 + } + + /** + * The "CPS increase factor" here is the increase in CPS per chocolate spent. + * The highest value among the choices is the best one to pick. + * + * @param lore The lore of the item + * @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); + } + + //Publicize this method so that the HandledScreenMixin can call it, as the values change on upgrade (when clicked) and there is a need for recalculation + public void markDirty() { + super.markHighlightsDirty(); + } +} 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 index 08fb6a86..8a5d32be 100644 --- a/src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolverManager.java +++ b/src/main/java/de/hysky/skyblocker/utils/render/gui/ContainerSolverManager.java @@ -5,6 +5,7 @@ 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.chocolatefactory.ChocolateFactorySolver; import de.hysky.skyblocker.skyblock.dungeon.CroesusHelper; import de.hysky.skyblocker.skyblock.dungeon.CroesusProfit; import de.hysky.skyblocker.skyblock.dungeon.terminal.ColorTerminal; @@ -55,7 +56,8 @@ public class ContainerSolverManager { new SuperpairsSolver(), UltrasequencerSolver.INSTANCE, new NewYearCakeBagHelper(), - NewYearCakesHelper.INSTANCE + NewYearCakesHelper.INSTANCE, + new ChocolateFactorySolver() }; } -- cgit From 0ec2707b63961ea0f7acab1c38311ef696ba8003 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Sun, 5 May 2024 16:26:29 +0300 Subject: Updated for 1.20.6 PR compatibility Add EggFinderDebugUtil for finding egg locations quickly, to be removed later. Not tested. --- .../skyblocker/mixins/HandledScreenMixin.java | 4 -- .../chocolatefactory/ChocolateFactorySolver.java | 35 ++++++++-------- .../chocolatefactory/EggFinderDebugUtil.java | 48 ++++++++++++++++++++++ 3 files changed, 67 insertions(+), 20 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinderDebugUtil.java (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java index 87b1bc79..f662be7c 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenMixin.java @@ -4,7 +4,6 @@ import com.llamalad7.mixinextras.sugar.Local; import com.mojang.blaze3d.systems.RenderSystem; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfigManager; -import de.hysky.skyblocker.skyblock.chocolatefactory.ChocolateFactorySolver; import de.hysky.skyblocker.skyblock.experiment.ChronomatronSolver; import de.hysky.skyblocker.skyblock.experiment.ExperimentSolver; import de.hysky.skyblocker.skyblock.experiment.SuperpairsSolver; @@ -285,9 +284,6 @@ public abstract class HandledScreenMixin extends Screen default -> { /*Do Nothing*/ } } } - if (currentSolver instanceof ChocolateFactorySolver chocolateFactorySolver) { - chocolateFactorySolver.markDirty(); - } } @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/chocolatefactory/ChocolateFactorySolver.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java index ef79cd41..cc5ae471 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -6,6 +6,9 @@ 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; @@ -34,18 +37,26 @@ public class ChocolateFactorySolver extends ContainerSolver { } @Override - protected List getColors(String[] groups, Map slots) { + protected void start(GenericContainerScreen screen) { + 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 getColors(String[] groups, Int2ObjectMap slots) { Int2DoubleMap cpsIncreaseFactors = new Int2DoubleLinkedOpenHashMap(5); //There are only 5 rabbits on the screen. - for (Map.Entry entry : slots.entrySet()) { + for (Int2ObjectMap.Entry entry : slots.int2ObjectEntrySet()) { + if (entry.getIntKey() < 29 || entry.getIntKey() > 33) continue; //Only check the rabbit slots (29,30,31,32,33) ItemStack item = entry.getValue(); - if (item.getItem() != Items.PLAYER_HEAD || !item.hasNbt() || item.isEmpty()) continue; + if (item.getItem() != Items.PLAYER_HEAD || item.isEmpty()) continue; String lore = getLore(item); if (lore.isBlank()) continue; OptionalDouble cpsIncreaseFactor = getCPSIncreaseFactor(lore); if (cpsIncreaseFactor.isEmpty()) continue; //Something went wrong, skip this item - cpsIncreaseFactors.put(entry.getKey().intValue(), cpsIncreaseFactor.getAsDouble()); + cpsIncreaseFactors.put(entry.getIntKey(), cpsIncreaseFactor.getAsDouble()); } Optional bestSlot = cpsIncreaseFactors.int2DoubleEntrySet().stream().max(Map.Entry.comparingByValue()); if (bestSlot.isEmpty()) return List.of(); //No valid slots found, somehow. This means something went wrong, despite all the checks thus far. @@ -53,13 +64,10 @@ public class ChocolateFactorySolver extends ContainerSolver { } private String getLore(ItemStack item) { - NbtCompound display = item.getSubNbt(ItemStack.DISPLAY_KEY); - if (display == null || display.isEmpty() || !display.contains(ItemStack.LORE_KEY, NbtElement.LIST_TYPE)) return ""; - NbtList lore = display.getList(ItemStack.LORE_KEY, NbtElement.STRING_TYPE); - return lore.stream() - .map(NbtElement::asString) - .map(Text.Serialization::fromJson) //Serialize the nbt string into a text to get the content string - .filter(Objects::nonNull) + 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, @@ -85,9 +93,4 @@ public class ChocolateFactorySolver extends ContainerSolver { int cost = Integer.parseInt(costMatcher.group(1).replace(",", "")); return OptionalDouble.of((nextCps - currentCps) / (double) cost); } - - //Publicize this method so that the HandledScreenMixin can call it, as the values change on upgrade (when clicked) and there is a need for recalculation - public void markDirty() { - super.markHighlightsDirty(); - } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinderDebugUtil.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinderDebugUtil.java new file mode 100644 index 00000000..6dc7a9e4 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinderDebugUtil.java @@ -0,0 +1,48 @@ +package de.hysky.skyblocker.skyblock.chocolatefactory; + +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientEntityEvents; +import net.minecraft.client.MinecraftClient; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.text.Text; +import net.minecraft.world.World; + +public class EggFinderDebugUtil { + public static void init() { + ClientEntityEvents.ENTITY_LOAD.register(EggFinderDebugUtil::printIfEgg); + } + + public static void printIfEgg(Entity entity, World world) { + if (entity.getType() != EntityType.ARMOR_STAND) return; + ArmorStandEntity armorStand = (ArmorStandEntity) entity; + ItemStack firstItem = armorStand.getArmorItems().iterator().next(); + if (firstItem.isEmpty() || firstItem.getItem() != Items.PLAYER_HEAD) return; + String texture; + try { + texture = firstItem.get(DataComponentTypes.PROFILE) + .properties() + .get("textures") + .iterator() + .next() + .value(); + } catch (Exception ignored) { //Why bother null-checking everything when you can throw a try-catch around it? + return; + } + + if (texture.equals("ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY3MzE0OSwKICAicHJvZmlsZUlkIiA6ICJiN2I4ZTlhZjEwZGE0NjFmOTY2YTQxM2RmOWJiM2U4OCIsCiAgInByb2ZpbGVOYW1lIiA6ICJBbmFiYW5hbmFZZzciLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTQ5MzMzZDg1YjhhMzE1ZDAzMzZlYjJkZjM3ZDhhNzE0Y2EyNGM1MWI4YzYwNzRmMWI1YjkyN2RlYjUxNmMyNCIKICAgIH0KICB9Cn0") + || texture.equals("ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY0OTcwMSwKICAicHJvZmlsZUlkIiA6ICI3NGEwMzQxNWY1OTI0ZTA4YjMyMGM2MmU1NGE3ZjJhYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJNZXp6aXIiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTVlMzYxNjU4MTlmZDI4NTBmOTg1NTJlZGNkNzYzZmY5ODYzMTMxMTkyODNjMTI2YWNlMGM0Y2M0OTVlNzZhOCIKICAgIH0KICB9Cn0") + || texture.equals("ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjU2ODExMiwKICAicHJvZmlsZUlkIiA6ICI3NzUwYzFhNTM5M2Q0ZWQ0Yjc2NmQ4ZGUwOWY4MjU0NiIsCiAgInByb2ZpbGVOYW1lIiA6ICJSZWVkcmVsIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzdhZTZkMmQzMWQ4MTY3YmNhZjk1MjkzYjY4YTRhY2Q4NzJkNjZlNzUxZGI1YTM0ZjJjYmM2NzY2YTAzNTZkMGEiCiAgICB9CiAgfQp9")) { + debugLog("Egg found!"); + debugLog(entity.getBlockX() + " " + entity.getBlockY() + " " + entity.getBlockZ()); + } + entity.setGlowing(true); + } + + public static void debugLog(String message) { + MinecraftClient.getInstance().inGameHud.getChatHud().addMessage(Text.of(message)); + } +} -- cgit From 16b449cac78f61f935d8754c32317998b1b3014c Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Mon, 6 May 2024 16:51:21 +0300 Subject: Delete EggFinderDebugUtil to prepare for PR --- .../chocolatefactory/EggFinderDebugUtil.java | 48 ---------------------- 1 file changed, 48 deletions(-) delete mode 100644 src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinderDebugUtil.java (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinderDebugUtil.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinderDebugUtil.java deleted file mode 100644 index 6dc7a9e4..00000000 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinderDebugUtil.java +++ /dev/null @@ -1,48 +0,0 @@ -package de.hysky.skyblocker.skyblock.chocolatefactory; - -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientEntityEvents; -import net.minecraft.client.MinecraftClient; -import net.minecraft.component.DataComponentTypes; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.decoration.ArmorStandEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; -import net.minecraft.text.Text; -import net.minecraft.world.World; - -public class EggFinderDebugUtil { - public static void init() { - ClientEntityEvents.ENTITY_LOAD.register(EggFinderDebugUtil::printIfEgg); - } - - public static void printIfEgg(Entity entity, World world) { - if (entity.getType() != EntityType.ARMOR_STAND) return; - ArmorStandEntity armorStand = (ArmorStandEntity) entity; - ItemStack firstItem = armorStand.getArmorItems().iterator().next(); - if (firstItem.isEmpty() || firstItem.getItem() != Items.PLAYER_HEAD) return; - String texture; - try { - texture = firstItem.get(DataComponentTypes.PROFILE) - .properties() - .get("textures") - .iterator() - .next() - .value(); - } catch (Exception ignored) { //Why bother null-checking everything when you can throw a try-catch around it? - return; - } - - if (texture.equals("ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY3MzE0OSwKICAicHJvZmlsZUlkIiA6ICJiN2I4ZTlhZjEwZGE0NjFmOTY2YTQxM2RmOWJiM2U4OCIsCiAgInByb2ZpbGVOYW1lIiA6ICJBbmFiYW5hbmFZZzciLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTQ5MzMzZDg1YjhhMzE1ZDAzMzZlYjJkZjM3ZDhhNzE0Y2EyNGM1MWI4YzYwNzRmMWI1YjkyN2RlYjUxNmMyNCIKICAgIH0KICB9Cn0") - || texture.equals("ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY0OTcwMSwKICAicHJvZmlsZUlkIiA6ICI3NGEwMzQxNWY1OTI0ZTA4YjMyMGM2MmU1NGE3ZjJhYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJNZXp6aXIiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTVlMzYxNjU4MTlmZDI4NTBmOTg1NTJlZGNkNzYzZmY5ODYzMTMxMTkyODNjMTI2YWNlMGM0Y2M0OTVlNzZhOCIKICAgIH0KICB9Cn0") - || texture.equals("ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjU2ODExMiwKICAicHJvZmlsZUlkIiA6ICI3NzUwYzFhNTM5M2Q0ZWQ0Yjc2NmQ4ZGUwOWY4MjU0NiIsCiAgInByb2ZpbGVOYW1lIiA6ICJSZWVkcmVsIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzdhZTZkMmQzMWQ4MTY3YmNhZjk1MjkzYjY4YTRhY2Q4NzJkNjZlNzUxZGI1YTM0ZjJjYmM2NzY2YTAzNTZkMGEiCiAgICB9CiAgfQp9")) { - debugLog("Egg found!"); - debugLog(entity.getBlockX() + " " + entity.getBlockY() + " " + entity.getBlockZ()); - } - entity.setGlowing(true); - } - - public static void debugLog(String message) { - MinecraftClient.getInstance().inGameHud.getChatHud().addMessage(Text.of(message)); - } -} -- cgit From 9fea533e30fdb5c825a72d2cf560958187764c6f Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Thu, 9 May 2024 21:36:20 +0300 Subject: Egg Finder initial commit Current issues: - Rendered waypoints do not turn off, can't figure out why - Entity equipment is sent before the chat message for new eggs, creating situations where the "found" message is repeated twice --- .../java/de/hysky/skyblocker/SkyblockerMod.java | 2 + .../mixins/ClientPlayNetworkHandlerMixin.java | 6 + .../skyblock/chocolatefactory/EggFinder.java | 132 +++++++++++++++++++++ .../java/de/hysky/skyblocker/utils/ColorUtils.java | 16 +++ 4 files changed, 156 insertions(+) create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java create mode 100644 src/main/java/de/hysky/skyblocker/utils/ColorUtils.java (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index e6b2d25a..e0e30b3c 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -11,6 +11,7 @@ import de.hysky.skyblocker.skyblock.*; import de.hysky.skyblocker.skyblock.calculators.CalculatorCommand; import de.hysky.skyblocker.skyblock.chat.ChatRuleAnnouncementScreen; import de.hysky.skyblocker.skyblock.chat.ChatRulesHandler; +import de.hysky.skyblocker.skyblock.chocolatefactory.EggFinder; import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra; import de.hysky.skyblocker.skyblock.dungeon.*; import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen; @@ -183,6 +184,7 @@ public class SkyblockerMod implements ClientModInitializer { BeaconHighlighter.init(); WarpAutocomplete.init(); MobBoundingBoxes.init(); + EggFinder.init(); Scheduler.INSTANCE.scheduleCyclic(Utils::update, 20); Scheduler.INSTANCE.scheduleCyclic(DiscordRPCManager::updateDataAndPresence, 200); diff --git a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java index 2c2c1376..34e8264d 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java @@ -6,6 +6,7 @@ import com.llamalad7.mixinextras.sugar.Local; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.CompactDamage; import de.hysky.skyblocker.skyblock.FishingHelper; +import de.hysky.skyblocker.skyblock.chocolatefactory.EggFinder; import de.hysky.skyblocker.skyblock.dungeon.DungeonScore; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; import de.hysky.skyblocker.skyblock.end.BeaconHighlighter; @@ -118,4 +119,9 @@ public abstract class ClientPlayNetworkHandlerMixin { LOGGER.error("[Skyblocker Compact Damage] Failed to compact damage number", e); } } + + @Inject(method = "onEntityEquipmentUpdate", at = @At(value = "TAIL")) + private void skyblocker$onEntityEquip(EntityEquipmentUpdateS2CPacket packet, CallbackInfo ci, @Local Entity entity) { + EggFinder.checkIfEgg(entity); + } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java new file mode 100644 index 00000000..d5e1a540 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java @@ -0,0 +1,132 @@ +package de.hysky.skyblocker.skyblock.chocolatefactory; + +import de.hysky.skyblocker.utils.ColorUtils; +import de.hysky.skyblocker.utils.Constants; +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; +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; +import org.slf4j.LoggerFactory; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class EggFinder { + private static final Pattern eggFoundPattern = Pattern.compile("^(?:HOPPITY'S HUNT You found a Chocolate|You have already collected this Chocolate) (Breakfast|Lunch|Dinner)"); + private static final Pattern newEggPattern = Pattern.compile("^HOPPITY'S HUNT A Chocolate (Breakfast|Lunch|Dinner) Egg has appeared!$"); + private static final MutableObject breakfastEgg = new MutableObject<>(null); + private static final MutableObject lunchEgg = new MutableObject<>(null); + private static final MutableObject dinnerEgg = new MutableObject<>(null); + private static final Logger logger = LoggerFactory.getLogger("Skyblocker Egg Finder"); + + private EggFinder() { + } + + public static void init() { + ClientPlayConnectionEvents.JOIN.register((ignored, ignored2, ignored3) -> { + breakfastEgg.setValue(null); + lunchEgg.setValue(null); + dinnerEgg.setValue(null); + }); + ClientReceiveMessageEvents.GAME.register(EggFinder::onChatMessage); + WorldRenderEvents.AFTER_TRANSLUCENT.register(EggFinder::renderWaypoints); + } + + public static void checkIfEgg(Entity entity) { + if (breakfastEgg.getValue() != null && dinnerEgg.getValue() != null && lunchEgg.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(); + + //Don't turn this into a switch statement, it's unreadable + if (texture.equals("ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY3MzE0OSwKICAicHJvZmlsZUlkIiA6ICJiN2I4ZTlhZjEwZGE0NjFmOTY2YTQxM2RmOWJiM2U4OCIsCiAgInByb2ZpbGVOYW1lIiA6ICJBbmFiYW5hbmFZZzciLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTQ5MzMzZDg1YjhhMzE1ZDAzMzZlYjJkZjM3ZDhhNzE0Y2EyNGM1MWI4YzYwNzRmMWI1YjkyN2RlYjUxNmMyNCIKICAgIH0KICB9Cn0")) { + handleFoundEgg(armorStand, EggType.BREAKFAST); + } else if (texture.equals("ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY0OTcwMSwKICAicHJvZmlsZUlkIiA6ICI3NGEwMzQxNWY1OTI0ZTA4YjMyMGM2MmU1NGE3ZjJhYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJNZXp6aXIiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTVlMzYxNjU4MTlmZDI4NTBmOTg1NTJlZGNkNzYzZmY5ODYzMTMxMTkyODNjMTI2YWNlMGM0Y2M0OTVlNzZhOCIKICAgIH0KICB9Cn0")) { + handleFoundEgg(armorStand, EggType.DINNER); + } else if (texture.equals("ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjU2ODExMiwKICAicHJvZmlsZUlkIiA6ICI3NzUwYzFhNTM5M2Q0ZWQ0Yjc2NmQ4ZGUwOWY4MjU0NiIsCiAgInByb2ZpbGVOYW1lIiA6ICJSZWVkcmVsIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzdhZTZkMmQzMWQ4MTY3YmNhZjk1MjkzYjY4YTRhY2Q4NzJkNjZlNzUxZGI1YTM0ZjJjYmM2NzY2YTAzNTZkMGEiCiAgICB9CiAgfQp9")) { + handleFoundEgg(armorStand, EggType.LUNCH); + } + } + } 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. + } + } + } + + private static void handleFoundEgg(ArmorStandEntity entity, EggType eggType) { + eggType.egg.setValue(new Egg(entity, new Waypoint(entity.getBlockPos().up(2), () -> Waypoint.Type.WAYPOINT, ColorUtils.getFloatComponents(eggType.color)))); + MinecraftClient.getInstance().player.sendMessage(Constants.PREFIX.get().append("Found a ").append(Text.literal("Chocolate " + eggType + " Egg").withColor(eggType.color)).append(" at " + entity.getBlockPos().up(2).toShortString() + "!")); + } + + private static void renderWaypoints(WorldRenderContext context) { + if (breakfastEgg.getValue() != null && breakfastEgg.getValue().waypoint.shouldRender()) breakfastEgg.getValue().waypoint.render(context); + if (lunchEgg.getValue() != null && lunchEgg.getValue().waypoint.shouldRender()) lunchEgg.getValue().waypoint.render(context); + if (dinnerEgg.getValue() != null && dinnerEgg.getValue().waypoint.shouldRender()) dinnerEgg.getValue().waypoint.render(context); + } + + private static void onChatMessage(Text text, boolean overlay) { + if (overlay) return; + Matcher matcher = eggFoundPattern.matcher(text.getString()); + if (matcher.matches()) { + try { + Egg egg = EggType.valueOf(matcher.group(1).toUpperCase()).egg.getValue(); + if (egg != null) egg.waypoint.setFound(); + } catch (IllegalArgumentException e) { + logger.error("Failed to find egg type for egg found message. Tried to match against: " + matcher.group(0), e); + } + } + + //There's only one egg of the same type at any given time, so we can set the changed egg to null + matcher = newEggPattern.matcher(text.getString()); + if (matcher.matches()) { + try { + EggType.valueOf(matcher.group(1).toUpperCase()).egg.setValue(null); + } catch (IllegalArgumentException e) { + logger.error("Failed to find egg type for egg spawn message. Tried to match against: " + matcher.group(0), e); + } + } + } + + private record Egg(ArmorStandEntity entity, Waypoint waypoint) { } + + private enum EggType { + LUNCH(lunchEgg, 0x5555FF), + DINNER(dinnerEgg, 0x55FF55), + BREAKFAST(breakfastEgg, 0xFFAA00); + + public final MutableObject egg; + public final int color; + + EggType(MutableObject egg, int color) { + this.egg = egg; + this.color = color; + } + + @Override + public String toString() { + return switch (this) { + case LUNCH -> "Lunch"; + case DINNER -> "Dinner"; + case BREAKFAST -> "Breakfast"; + }; + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/ColorUtils.java b/src/main/java/de/hysky/skyblocker/utils/ColorUtils.java new file mode 100644 index 00000000..0196edf2 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/ColorUtils.java @@ -0,0 +1,16 @@ +package de.hysky.skyblocker.utils; + +public class ColorUtils { + /** + * Takes an RGB color as an integer and returns an array of the color's components as floats, in RGB format. + * @param color The color to get the components of. + * @return An array of the color's components as floats. + */ + public static float[] getFloatComponents(int color) { + return new float[] { + ((color >> 16) & 0xFF) / 255f, + ((color >> 8) & 0xFF) / 255f, + (color & 0xFF) / 255f + }; + } +} -- cgit From 05a18be31a137148bcd446654c550eb2d713990c Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Fri, 10 May 2024 21:00:00 +0300 Subject: Add configs and minor code refactor --- .../config/categories/HelperCategory.java | 42 +++++++++++++ .../skyblocker/config/configs/HelperConfig.java | 18 ++++++ .../chocolatefactory/ChocolateFactorySolver.java | 8 +-- .../skyblock/chocolatefactory/EggFinder.java | 72 +++++++++++++--------- .../resources/assets/skyblocker/lang/en_us.json | 10 +++ 5 files changed, 117 insertions(+), 33 deletions(-) (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/config/categories/HelperCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/HelperCategory.java index 1528f853..d9824a23 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/HelperCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/HelperCategory.java @@ -2,11 +2,14 @@ package de.hysky.skyblocker.config.categories; import de.hysky.skyblocker.config.ConfigUtils; import de.hysky.skyblocker.config.SkyblockerConfig; +import de.hysky.skyblocker.utils.waypoint.Waypoint; import dev.isxander.yacl3.api.*; import dev.isxander.yacl3.api.ConfigCategory; import dev.isxander.yacl3.api.Option; import dev.isxander.yacl3.api.OptionDescription; import dev.isxander.yacl3.api.controller.FloatFieldControllerBuilder; +import dev.isxander.yacl3.api.controller.TickBoxControllerBuilder; +import dev.isxander.yacl3.config.v2.api.autogen.TickBox; import net.minecraft.text.Text; public class HelperCategory { @@ -137,6 +140,45 @@ public class HelperCategory { .build()) .build()) + //Chocolate Factory + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.helpers.chocolateFactory")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.helpers.chocolateFactory.enableChocolateFactoryHelper")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.helpers.chocolateFactory.enableChocolateFactoryHelper.@Tooltip"))) + .binding(defaults.helpers.chocolateFactory.enableChocolateFactoryHelper, + () -> config.helpers.chocolateFactory.enableChocolateFactoryHelper, + newValue -> config.helpers.chocolateFactory.enableChocolateFactoryHelper = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.helpers.chocolateFactory.enableEggFinder")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.helpers.chocolateFactory.enableEggFinder.@Tooltip"))) + .binding(defaults.helpers.chocolateFactory.enableEggFinder, + () -> config.helpers.chocolateFactory.enableEggFinder, + newValue -> config.helpers.chocolateFactory.enableEggFinder = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.helpers.chocolateFactory.sendEggFoundMessages")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.helpers.chocolateFactory.sendEggFoundMessages.@Tooltip"))) + .binding(defaults.helpers.chocolateFactory.sendEggFoundMessages, + () -> config.helpers.chocolateFactory.sendEggFoundMessages, + newValue -> config.helpers.chocolateFactory.sendEggFoundMessages = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.helpers.chocolateFactory.waypointType")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.helpers.chocolateFactory.waypointType.@Tooltip"))) + .binding(defaults.helpers.chocolateFactory.waypointType, + () -> config.helpers.chocolateFactory.waypointType, + newValue -> config.helpers.chocolateFactory.waypointType = newValue) + .controller(ConfigUtils::createEnumCyclingListController) + .build()) + + .build()) + .build(); } } diff --git a/src/main/java/de/hysky/skyblocker/config/configs/HelperConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/HelperConfig.java index 2abff6ac..8721e35c 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/HelperConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/HelperConfig.java @@ -1,5 +1,6 @@ package de.hysky.skyblocker.config.configs; +import de.hysky.skyblocker.utils.waypoint.Waypoint; import dev.isxander.yacl3.config.v2.api.SerialEntry; public class HelperConfig { @@ -19,6 +20,9 @@ public class HelperConfig { @SerialEntry public FairySouls fairySouls = new FairySouls(); + @SerialEntry + public ChocolateFactory chocolateFactory = new ChocolateFactory(); + public static class MythologicalRitual { @SerialEntry public boolean enableMythologicalRitualHelper = true; @@ -62,4 +66,18 @@ public class HelperConfig { @SerialEntry public boolean highlightOnlyNearbySouls = false; } + + public static class ChocolateFactory { + @SerialEntry + public boolean enableChocolateFactoryHelper = true; + + @SerialEntry + public boolean enableEggFinder = true; + + @SerialEntry + public boolean sendEggFoundMessages = true; + + @SerialEntry + public Waypoint.Type waypointType = Waypoint.Type.WAYPOINT; + } } 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 cc5ae471..a59a5147 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -1,5 +1,6 @@ package de.hysky.skyblocker.skyblock.chocolatefactory; +import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.experiment.ExperimentSolver; import de.hysky.skyblocker.utils.render.gui.ColorHighlight; import de.hysky.skyblocker.utils.render.gui.ContainerSolver; @@ -33,7 +34,7 @@ public class ChocolateFactorySolver extends ContainerSolver { @Override protected boolean isEnabled() { - return true; //Todo: add a config option and check if it's enabled from there + return SkyblockerConfigManager.get().helpers.chocolateFactory.enableChocolateFactoryHelper; } @Override @@ -41,7 +42,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 getColors(String[] groups, Int2ObjectMap slots) { @@ -70,8 +70,8 @@ public class ChocolateFactorySolver extends ContainerSolver { .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 +// 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 } /** 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 d5e1a540..7f8e9879 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java @@ -1,8 +1,10 @@ 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.waypoint.Waypoint; +import it.unimi.dsi.fastutil.objects.ObjectImmutableList; 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; @@ -21,29 +23,27 @@ import org.slf4j.LoggerFactory; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static de.hysky.skyblocker.skyblock.chocolatefactory.EggFinder.EggType.BREAKFAST; +import static de.hysky.skyblocker.skyblock.chocolatefactory.EggFinder.EggType.DINNER; +import static de.hysky.skyblocker.skyblock.chocolatefactory.EggFinder.EggType.LUNCH; + public class EggFinder { private static final Pattern eggFoundPattern = Pattern.compile("^(?:HOPPITY'S HUNT You found a Chocolate|You have already collected this Chocolate) (Breakfast|Lunch|Dinner)"); private static final Pattern newEggPattern = Pattern.compile("^HOPPITY'S HUNT A Chocolate (Breakfast|Lunch|Dinner) Egg has appeared!$"); - private static final MutableObject breakfastEgg = new MutableObject<>(null); - private static final MutableObject lunchEgg = new MutableObject<>(null); - private static final MutableObject dinnerEgg = new MutableObject<>(null); private static final Logger logger = LoggerFactory.getLogger("Skyblocker Egg Finder"); private EggFinder() { } public static void init() { - ClientPlayConnectionEvents.JOIN.register((ignored, ignored2, ignored3) -> { - breakfastEgg.setValue(null); - lunchEgg.setValue(null); - dinnerEgg.setValue(null); - }); + ClientPlayConnectionEvents.JOIN.register((ignored, ignored2, ignored3) -> clearEggs()); ClientReceiveMessageEvents.GAME.register(EggFinder::onChatMessage); WorldRenderEvents.AFTER_TRANSLUCENT.register(EggFinder::renderWaypoints); } public static void checkIfEgg(Entity entity) { - if (breakfastEgg.getValue() != null && dinnerEgg.getValue() != null && lunchEgg.getValue() != null) return; //Don't check for eggs if we already found all of them + if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableEggFinder) return; + 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 { @@ -56,13 +56,11 @@ public class EggFinder { .next() .value(); - //Don't turn this into a switch statement, it's unreadable - if (texture.equals("ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY3MzE0OSwKICAicHJvZmlsZUlkIiA6ICJiN2I4ZTlhZjEwZGE0NjFmOTY2YTQxM2RmOWJiM2U4OCIsCiAgInByb2ZpbGVOYW1lIiA6ICJBbmFiYW5hbmFZZzciLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTQ5MzMzZDg1YjhhMzE1ZDAzMzZlYjJkZjM3ZDhhNzE0Y2EyNGM1MWI4YzYwNzRmMWI1YjkyN2RlYjUxNmMyNCIKICAgIH0KICB9Cn0")) { - handleFoundEgg(armorStand, EggType.BREAKFAST); - } else if (texture.equals("ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY0OTcwMSwKICAicHJvZmlsZUlkIiA6ICI3NGEwMzQxNWY1OTI0ZTA4YjMyMGM2MmU1NGE3ZjJhYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJNZXp6aXIiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTVlMzYxNjU4MTlmZDI4NTBmOTg1NTJlZGNkNzYzZmY5ODYzMTMxMTkyODNjMTI2YWNlMGM0Y2M0OTVlNzZhOCIKICAgIH0KICB9Cn0")) { - handleFoundEgg(armorStand, EggType.DINNER); - } else if (texture.equals("ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjU2ODExMiwKICAicHJvZmlsZUlkIiA6ICI3NzUwYzFhNTM5M2Q0ZWQ0Yjc2NmQ4ZGUwOWY4MjU0NiIsCiAgInByb2ZpbGVOYW1lIiA6ICJSZWVkcmVsIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzdhZTZkMmQzMWQ4MTY3YmNhZjk1MjkzYjY4YTRhY2Q4NzJkNjZlNzUxZGI1YTM0ZjJjYmM2NzY2YTAzNTZkMGEiCiAgICB9CiAgfQp9")) { - handleFoundEgg(armorStand, EggType.LUNCH); + for (EggType type : EggType.entries) { + if (texture.equals(type.texture)) { + handleFoundEgg(armorStand, type); + return; + } } } } catch (Exception e) { @@ -71,26 +69,37 @@ public class EggFinder { } } + private static void clearEggs() { + if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableEggFinder) return; + for (EggType type : EggType.entries) { + type.egg.setValue(null); + } + } + private static void handleFoundEgg(ArmorStandEntity entity, EggType eggType) { - eggType.egg.setValue(new Egg(entity, new Waypoint(entity.getBlockPos().up(2), () -> Waypoint.Type.WAYPOINT, ColorUtils.getFloatComponents(eggType.color)))); + eggType.egg.setValue(new Egg(entity, new Waypoint(entity.getBlockPos().up(2), SkyblockerConfigManager.get().helpers.chocolateFactory.waypointType, ColorUtils.getFloatComponents(eggType.color)))); + + if (!SkyblockerConfigManager.get().helpers.chocolateFactory.sendEggFoundMessages) return; MinecraftClient.getInstance().player.sendMessage(Constants.PREFIX.get().append("Found a ").append(Text.literal("Chocolate " + eggType + " Egg").withColor(eggType.color)).append(" at " + entity.getBlockPos().up(2).toShortString() + "!")); } private static void renderWaypoints(WorldRenderContext context) { - if (breakfastEgg.getValue() != null && breakfastEgg.getValue().waypoint.shouldRender()) breakfastEgg.getValue().waypoint.render(context); - if (lunchEgg.getValue() != null && lunchEgg.getValue().waypoint.shouldRender()) lunchEgg.getValue().waypoint.render(context); - if (dinnerEgg.getValue() != null && dinnerEgg.getValue().waypoint.shouldRender()) dinnerEgg.getValue().waypoint.render(context); + if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableEggFinder) return; + for (EggType type : EggType.entries) { + Egg egg = type.egg.getValue(); + if (egg != null && egg.waypoint.shouldRender()) egg.waypoint.render(context); + } } private static void onChatMessage(Text text, boolean overlay) { - if (overlay) return; + if (overlay || !SkyblockerConfigManager.get().helpers.chocolateFactory.enableEggFinder) return; Matcher matcher = eggFoundPattern.matcher(text.getString()); if (matcher.matches()) { try { Egg egg = EggType.valueOf(matcher.group(1).toUpperCase()).egg.getValue(); if (egg != null) egg.waypoint.setFound(); } catch (IllegalArgumentException e) { - logger.error("Failed to find egg type for egg found message. Tried to match against: " + matcher.group(0), e); + logger.error("[Skyblocker Egg Finder] Failed to find egg type for egg found message. Tried to match against: " + matcher.group(0), e); } } @@ -100,24 +109,29 @@ public class EggFinder { try { EggType.valueOf(matcher.group(1).toUpperCase()).egg.setValue(null); } catch (IllegalArgumentException e) { - logger.error("Failed to find egg type for egg spawn message. Tried to match against: " + matcher.group(0), e); + logger.error("[Skyblocker Egg Finder] Failed to find egg type for egg spawn message. Tried to match against: " + matcher.group(0), e); } } } - private record Egg(ArmorStandEntity entity, Waypoint waypoint) { } + record Egg(ArmorStandEntity entity, Waypoint waypoint) { } - private enum EggType { - LUNCH(lunchEgg, 0x5555FF), - DINNER(dinnerEgg, 0x55FF55), - BREAKFAST(breakfastEgg, 0xFFAA00); + enum EggType { + LUNCH(new MutableObject<>(), 0x5555FF, "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY3MzE0OSwKICAicHJvZmlsZUlkIiA6ICJiN2I4ZTlhZjEwZGE0NjFmOTY2YTQxM2RmOWJiM2U4OCIsCiAgInByb2ZpbGVOYW1lIiA6ICJBbmFiYW5hbmFZZzciLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTQ5MzMzZDg1YjhhMzE1ZDAzMzZlYjJkZjM3ZDhhNzE0Y2EyNGM1MWI4YzYwNzRmMWI1YjkyN2RlYjUxNmMyNCIKICAgIH0KICB9Cn0"), + DINNER(new MutableObject<>(), 0x55FF55, "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY0OTcwMSwKICAicHJvZmlsZUlkIiA6ICI3NGEwMzQxNWY1OTI0ZTA4YjMyMGM2MmU1NGE3ZjJhYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJNZXp6aXIiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTVlMzYxNjU4MTlmZDI4NTBmOTg1NTJlZGNkNzYzZmY5ODYzMTMxMTkyODNjMTI2YWNlMGM0Y2M0OTVlNzZhOCIKICAgIH0KICB9Cn0"), + BREAKFAST(new MutableObject<>(), 0xFFAA00, "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjU2ODExMiwKICAicHJvZmlsZUlkIiA6ICI3NzUwYzFhNTM5M2Q0ZWQ0Yjc2NmQ4ZGUwOWY4MjU0NiIsCiAgInByb2ZpbGVOYW1lIiA6ICJSZWVkcmVsIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzdhZTZkMmQzMWQ4MTY3YmNhZjk1MjkzYjY4YTRhY2Q4NzJkNjZlNzUxZGI1YTM0ZjJjYmM2NzY2YTAzNTZkMGEiCiAgICB9CiAgfQp9"); public final MutableObject egg; public final int color; + public final String texture; + + //This is to not create an array each time we iterate over the values + public static final ObjectImmutableList entries = ObjectImmutableList.of(BREAKFAST, DINNER); - EggType(MutableObject egg, int color) { + EggType(MutableObject egg, int color, String texture) { this.egg = egg; this.color = color; + this.texture = texture; } @Override diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 4304ff3d..6cdf5fa1 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -273,6 +273,16 @@ "skyblocker.config.helpers": "Helpers", + "skyblocker.config.helpers.chocolateFactory": "Chocolate Factory", + "skyblocker.config.helpers.chocolateFactory.enableChocolateFactoryHelper": "Enable Chocolate Factory Helper", + "skyblocker.config.helpers.chocolateFactory.enableChocolateFactoryHelper.@Tooltip": "Highlights the best upgrade when enabled.", + "skyblocker.config.helpers.chocolateFactory.enableEggFinder": "Enable Egg Finder", + "skyblocker.config.helpers.chocolateFactory.enableEggFinder.@Tooltip": "Highlights eggs from Hoppity's Hunt.", + "skyblocker.config.helpers.chocolateFactory.sendEggFoundMessages": "Send Egg Found Messages", + "skyblocker.config.helpers.chocolateFactory.sendEggFoundMessages.@Tooltip": "Sends a message in chat when an egg is found in the current island.", + "skyblocker.config.helpers.chocolateFactory.waypointType": "Egg Waypoint Type", + "skyblocker.config.helpers.chocolateFactory.waypointType.@Tooltip": "Waypoint: Displays a highlight and a beacon beam.\n\nOutlined Waypoint: Displays both a waypoint and an outline.\n\nHighlight: Only displays a highlight.\n\nOutlined Highlight: Displays both a highlight and an outline.\n\nOutline: Only displays an outline.", + "skyblocker.config.helpers.enableNewYearCakesHelper": "Enable New Year Cakes Helper", "skyblocker.config.helpers.enableNewYearCakesHelper.@Tooltip": "Highlights the missing new year cakes green and the cakes you have already red.\n\nRequires you to open your cake bag at least once to work.", -- cgit From e2f18c84ce2de2da228ff88b6b67fa5d46945255 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Sat, 11 May 2024 14:08:59 +0300 Subject: Add support for unemployed rabbits - Refactored ItemUtils.getHeadTexture to use the property iterator instead of streams and return Optional 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 --- src/main/java/de/hysky/skyblocker/debug/Debug.java | 6 +- .../chocolatefactory/ChocolateFactorySolver.java | 77 +++++++++++++--------- .../skyblock/chocolatefactory/EggFinder.java | 27 ++------ .../hysky/skyblocker/skyblock/entity/MobGlow.java | 2 +- .../skyblocker/skyblock/garden/VisitorHelper.java | 4 +- .../java/de/hysky/skyblocker/utils/ItemUtils.java | 17 ++--- 6 files changed, 68 insertions(+), 65 deletions(-) (limited to 'src/main/java/de/hysky') 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 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 getColors(String[] groups, Int2ObjectMap 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 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 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 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() { -- cgit From 45643ed032a239381d8b9009241a8d3002e4402c Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 14 May 2024 00:46:33 +0300 Subject: Fix incorrect textures for EggFinder.EggType --- .../java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/de/hysky') 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 ee1d4aa7..e796717f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java @@ -104,9 +104,9 @@ public class EggFinder { record Egg(ArmorStandEntity entity, Waypoint waypoint) { } enum EggType { - LUNCH(new MutableObject<>(), 0x5555FF, "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY3MzE0OSwKICAicHJvZmlsZUlkIiA6ICJiN2I4ZTlhZjEwZGE0NjFmOTY2YTQxM2RmOWJiM2U4OCIsCiAgInByb2ZpbGVOYW1lIiA6ICJBbmFiYW5hbmFZZzciLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTQ5MzMzZDg1YjhhMzE1ZDAzMzZlYjJkZjM3ZDhhNzE0Y2EyNGM1MWI4YzYwNzRmMWI1YjkyN2RlYjUxNmMyNCIKICAgIH0KICB9Cn0"), + LUNCH(new MutableObject<>(), 0x5555FF, "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjU2ODExMiwKICAicHJvZmlsZUlkIiA6ICI3NzUwYzFhNTM5M2Q0ZWQ0Yjc2NmQ4ZGUwOWY4MjU0NiIsCiAgInByb2ZpbGVOYW1lIiA6ICJSZWVkcmVsIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzdhZTZkMmQzMWQ4MTY3YmNhZjk1MjkzYjY4YTRhY2Q4NzJkNjZlNzUxZGI1YTM0ZjJjYmM2NzY2YTAzNTZkMGEiCiAgICB9CiAgfQp9"), DINNER(new MutableObject<>(), 0x55FF55, "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY0OTcwMSwKICAicHJvZmlsZUlkIiA6ICI3NGEwMzQxNWY1OTI0ZTA4YjMyMGM2MmU1NGE3ZjJhYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJNZXp6aXIiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTVlMzYxNjU4MTlmZDI4NTBmOTg1NTJlZGNkNzYzZmY5ODYzMTMxMTkyODNjMTI2YWNlMGM0Y2M0OTVlNzZhOCIKICAgIH0KICB9Cn0"), - BREAKFAST(new MutableObject<>(), 0xFFAA00, "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjU2ODExMiwKICAicHJvZmlsZUlkIiA6ICI3NzUwYzFhNTM5M2Q0ZWQ0Yjc2NmQ4ZGUwOWY4MjU0NiIsCiAgInByb2ZpbGVOYW1lIiA6ICJSZWVkcmVsIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzdhZTZkMmQzMWQ4MTY3YmNhZjk1MjkzYjY4YTRhY2Q4NzJkNjZlNzUxZGI1YTM0ZjJjYmM2NzY2YTAzNTZkMGEiCiAgICB9CiAgfQp9"); + BREAKFAST(new MutableObject<>(), 0xFFAA00, "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY3MzE0OSwKICAicHJvZmlsZUlkIiA6ICJiN2I4ZTlhZjEwZGE0NjFmOTY2YTQxM2RmOWJiM2U4OCIsCiAgInByb2ZpbGVOYW1lIiA6ICJBbmFiYW5hbmFZZzciLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTQ5MzMzZDg1YjhhMzE1ZDAzMzZlYjJkZjM3ZDhhNzE0Y2EyNGM1MWI4YzYwNzRmMWI1YjkyN2RlYjUxNmMyNCIKICAgIH0KICB9Cn0"); public final MutableObject egg; public final int color; -- cgit From 07c352c2ad7be9c4160ba479016000d83f71f64c Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 14 May 2024 00:47:12 +0300 Subject: Refactor null handling in EggFinder.checkIfEgg --- .../de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src/main/java/de/hysky') 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 e796717f..91aa39db 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java @@ -22,10 +22,6 @@ import org.slf4j.LoggerFactory; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static de.hysky.skyblocker.skyblock.chocolatefactory.EggFinder.EggType.BREAKFAST; -import static de.hysky.skyblocker.skyblock.chocolatefactory.EggFinder.EggType.DINNER; -import static de.hysky.skyblocker.skyblock.chocolatefactory.EggFinder.EggType.LUNCH; - public class EggFinder { private static final Pattern eggFoundPattern = Pattern.compile("^(?:HOPPITY'S HUNT You found a Chocolate|You have already collected this Chocolate) (Breakfast|Lunch|Dinner)"); private static final Pattern newEggPattern = Pattern.compile("^HOPPITY'S HUNT A Chocolate (Breakfast|Lunch|Dinner) Egg has appeared!$"); @@ -42,12 +38,11 @@ public class EggFinder { public static void checkIfEgg(Entity entity) { if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableEggFinder) return; - 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()) { ItemUtils.getHeadTexture(itemStack).ifPresent(texture -> { for (EggType type : EggType.entries) { - if (texture.equals(type.texture)) { + if (texture.equals(type.texture) && type.egg.getValue() == null) { handleFoundEgg(armorStand, type); return; } -- cgit From e0327e3a8e15fab7afcf446f48f4b12f1a01d7f3 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 14 May 2024 01:03:05 +0300 Subject: Fix waypoint rendering not turning off --- .../java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/de/hysky') 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 91aa39db..abb9af25 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java @@ -76,7 +76,7 @@ public class EggFinder { private static void onChatMessage(Text text, boolean overlay) { if (overlay || !SkyblockerConfigManager.get().helpers.chocolateFactory.enableEggFinder) return; Matcher matcher = eggFoundPattern.matcher(text.getString()); - if (matcher.matches()) { + if (matcher.find()) { try { Egg egg = EggType.valueOf(matcher.group(1).toUpperCase()).egg.getValue(); if (egg != null) egg.waypoint.setFound(); @@ -87,7 +87,7 @@ public class EggFinder { //There's only one egg of the same type at any given time, so we can set the changed egg to null matcher = newEggPattern.matcher(text.getString()); - if (matcher.matches()) { + if (matcher.find()) { try { EggType.valueOf(matcher.group(1).toUpperCase()).egg.setValue(null); } catch (IllegalArgumentException e) { -- cgit From 589692ac8df2173faa54f20fc97cfa7d4308b4b4 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 14 May 2024 01:03:40 +0300 Subject: Code formatting --- .../de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/main/java/de/hysky') 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 abb9af25..c467dc53 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java @@ -62,7 +62,11 @@ public class EggFinder { eggType.egg.setValue(new Egg(entity, new Waypoint(entity.getBlockPos().up(2), SkyblockerConfigManager.get().helpers.chocolateFactory.waypointType, ColorUtils.getFloatComponents(eggType.color)))); if (!SkyblockerConfigManager.get().helpers.chocolateFactory.sendEggFoundMessages) return; - MinecraftClient.getInstance().player.sendMessage(Constants.PREFIX.get().append("Found a ").append(Text.literal("Chocolate " + eggType + " Egg").withColor(eggType.color)).append(" at " + entity.getBlockPos().up(2).toShortString() + "!")); + MinecraftClient.getInstance().player.sendMessage(Constants.PREFIX.get() + .append("Found a ") + .append(Text.literal("Chocolate " + eggType + " Egg") + .withColor(eggType.color)) + .append(" at " + entity.getBlockPos().up(2).toShortString() + "!")); } private static void renderWaypoints(WorldRenderContext context) { -- cgit From 1d6969a7c513c1830b7360f12d2492cd36a62bf0 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 14 May 2024 01:36:40 +0300 Subject: Add missing LUNCH EggType to EggType.entries --- .../java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/de/hysky') 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 c467dc53..11d9339f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java @@ -112,7 +112,7 @@ public class EggFinder { public final String texture; //This is to not create an array each time we iterate over the values - public static final ObjectImmutableList entries = ObjectImmutableList.of(BREAKFAST, DINNER); + public static final ObjectImmutableList entries = ObjectImmutableList.of(BREAKFAST, LUNCH, DINNER); EggType(MutableObject egg, int color, String texture) { this.egg = egg; -- cgit From 4a0284f96148f2b0d3d4d8ce07bc1aa8a92b53a9 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 14 May 2024 02:10:27 +0300 Subject: Add Time Tower Reminder --- .../java/de/hysky/skyblocker/SkyblockerMod.java | 2 + .../config/categories/HelperCategory.java | 8 +++ .../skyblocker/config/configs/HelperConfig.java | 3 + .../chocolatefactory/TimeTowerReminder.java | 71 ++++++++++++++++++++++ .../resources/assets/skyblocker/lang/en_us.json | 2 + 5 files changed, 86 insertions(+) create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index e0e30b3c..37f6d2a8 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -12,6 +12,7 @@ import de.hysky.skyblocker.skyblock.calculators.CalculatorCommand; import de.hysky.skyblocker.skyblock.chat.ChatRuleAnnouncementScreen; import de.hysky.skyblocker.skyblock.chat.ChatRulesHandler; import de.hysky.skyblocker.skyblock.chocolatefactory.EggFinder; +import de.hysky.skyblocker.skyblock.chocolatefactory.TimeTowerReminder; import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra; import de.hysky.skyblocker.skyblock.dungeon.*; import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen; @@ -185,6 +186,7 @@ public class SkyblockerMod implements ClientModInitializer { WarpAutocomplete.init(); MobBoundingBoxes.init(); EggFinder.init(); + TimeTowerReminder.init(); Scheduler.INSTANCE.scheduleCyclic(Utils::update, 20); Scheduler.INSTANCE.scheduleCyclic(DiscordRPCManager::updateDataAndPresence, 200); diff --git a/src/main/java/de/hysky/skyblocker/config/categories/HelperCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/HelperCategory.java index d9824a23..79bd0d65 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/HelperCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/HelperCategory.java @@ -176,6 +176,14 @@ public class HelperCategory { newValue -> config.helpers.chocolateFactory.waypointType = newValue) .controller(ConfigUtils::createEnumCyclingListController) .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.helpers.chocolateFactory.enableTimeTowerReminder")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.helpers.chocolateFactory.enableTimeTowerReminder.@Tooltip"))) + .binding(defaults.helpers.chocolateFactory.enableTimeTowerReminder, + () -> config.helpers.chocolateFactory.enableTimeTowerReminder, + newValue -> config.helpers.chocolateFactory.enableTimeTowerReminder = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) .build()) diff --git a/src/main/java/de/hysky/skyblocker/config/configs/HelperConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/HelperConfig.java index 8721e35c..c0314924 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/HelperConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/HelperConfig.java @@ -79,5 +79,8 @@ public class HelperConfig { @SerialEntry public Waypoint.Type waypointType = Waypoint.Type.WAYPOINT; + + @SerialEntry + public boolean enableTimeTowerReminder = true; } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java new file mode 100644 index 00000000..3b7fa3bc --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java @@ -0,0 +1,71 @@ +package de.hysky.skyblocker.skyblock.chocolatefactory; + +import com.mojang.brigadier.Message; +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.events.SkyblockEvents; +import de.hysky.skyblocker.utils.Constants; +import de.hysky.skyblocker.utils.scheduler.Scheduler; +import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; +import net.minecraft.client.MinecraftClient; +import net.minecraft.text.Text; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.time.Instant; +import java.util.regex.Pattern; + +public class TimeTowerReminder { + private static final String TIME_TOWER_FILE = "time_tower.txt"; + private static final Pattern TIME_TOWER_PATTERN = Pattern.compile("^TIME TOWER! Your Chocolate Factory production has increased"); + private static final Logger LOGGER = LoggerFactory.getLogger("Skyblocker Time Tower Reminder"); + + private TimeTowerReminder() { + } + + public static void init() { + SkyblockEvents.JOIN.register(TimeTowerReminder::checkTempFile); + ClientReceiveMessageEvents.GAME.register(TimeTowerReminder::checkIfTimeTower); + } + + public static void checkIfTimeTower(Message message, boolean overlay) { + if (!TIME_TOWER_PATTERN.matcher(message.getString()).matches()) return; + Scheduler.INSTANCE.schedule(TimeTowerReminder::sendMessage, 60*60*20); // 1 hour + + File tempFile = SkyblockerMod.CONFIG_DIR.resolve(TIME_TOWER_FILE).toFile(); + if (!tempFile.exists() && !tempFile.mkdir()) { + LOGGER.error("[Skyblocker Time Tower Reminder] Failed to create temp file for Time Tower Reminder!"); + return; + } + + try (FileWriter writer = new FileWriter(tempFile)) { + writer.write(Instant.now().toString()); + } catch (IOException e) { + LOGGER.error("[Skyblocker Time Tower Reminder] Failed to write to temp file for Time Tower Reminder!", e); + } + } + + private static void sendMessage() { + if (MinecraftClient.getInstance().player == null) return; + MinecraftClient.getInstance().player.sendMessage(Constants.PREFIX.get().append(Text.literal("Your Chocolate Factory's Time Tower has deactivated!").withColor(0xFF5555))); + + File tempFile = SkyblockerMod.CONFIG_DIR.resolve(TIME_TOWER_FILE).toFile(); + try { + if (tempFile.exists()) Files.delete(tempFile.toPath()); + } catch (Exception e) { + LOGGER.error("[Skyblocker Time Tower Reminder] Failed to delete temp file for Time Tower Reminder!", e); + } + } + + private static void checkTempFile() { + File tempFile = SkyblockerMod.CONFIG_DIR.resolve(TIME_TOWER_FILE).toFile(); + if (!tempFile.exists()) return; + + long time = tempFile.lastModified(); + if (System.currentTimeMillis() - time >= 60*60*1000) sendMessage(); + else Scheduler.INSTANCE.schedule(TimeTowerReminder::sendMessage, 60*60*20 - (int) ((System.currentTimeMillis() - time) / 50)); // 50 milliseconds is 1 tick + } +} diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 6cdf5fa1..6b309d39 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -282,6 +282,8 @@ "skyblocker.config.helpers.chocolateFactory.sendEggFoundMessages.@Tooltip": "Sends a message in chat when an egg is found in the current island.", "skyblocker.config.helpers.chocolateFactory.waypointType": "Egg Waypoint Type", "skyblocker.config.helpers.chocolateFactory.waypointType.@Tooltip": "Waypoint: Displays a highlight and a beacon beam.\n\nOutlined Waypoint: Displays both a waypoint and an outline.\n\nHighlight: Only displays a highlight.\n\nOutlined Highlight: Displays both a highlight and an outline.\n\nOutline: Only displays an outline.", + "skyblocker.config.helpers.chocolateFactory.enableTimeTowerReminder": "Enable Time Tower Reminder", + "skyblocker.config.helpers.chocolateFactory.enableTimeTowerReminder.@Tooltip": "Sends a message in chat when your Time Tower deactivates.", "skyblocker.config.helpers.enableNewYearCakesHelper": "Enable New Year Cakes Helper", "skyblocker.config.helpers.enableNewYearCakesHelper.@Tooltip": "Highlights the missing new year cakes green and the cakes you have already red.\n\nRequires you to open your cake bag at least once to work.", -- cgit From 9e0f4272c6f7864a45d43163799075661f40b9bf Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 14 May 2024 02:11:40 +0300 Subject: Add coach cps calculation to the ChocolateFactorySolver --- .../chocolatefactory/ChocolateFactorySolver.java | 100 +++++++++++++++------ 1 file changed, 75 insertions(+), 25 deletions(-) (limited to 'src/main/java/de/hysky') 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 94c2b209..5c809a98 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -14,12 +14,14 @@ import java.util.*; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -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 CPS_PATTERN = Pattern.compile("([\\d,.]+) Chocolate per second"); + private static final Pattern CPS_INCREASE_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+ *"); + private static final Pattern TOTAL_MULTIPLIER_PATTERN = Pattern.compile("Total Multiplier: ([\\d.]+)x"); + private static final Pattern MULTIPLIER_INCREASE_PATTERN = Pattern.compile("\\+([\\d.]+)x Chocolate per second"); public ChocolateFactorySolver() { super("^Chocolate Factory$"); @@ -37,31 +39,70 @@ public class ChocolateFactorySolver extends ContainerSolver { @Override protected List getColors(String[] groups, Int2ObjectMap slots) { - Int2DoubleMap cpsIncreaseFactors = new Int2DoubleLinkedOpenHashMap(5); //There are only 5 rabbits on the screen. - for (Int2ObjectMap.Entry entry : slots.int2ObjectEntrySet()) { - if (entry.getIntKey() < 29 || entry.getIntKey() > 33) continue; //Only check the rabbit slots (29,30,31,32,33) - ItemStack item = entry.getValue(); + final Int2DoubleMap cpsIncreaseFactors = new Int2DoubleLinkedOpenHashMap(6); //There are only 5 rabbits on the screen + 1 for the coach + for (int i = 29; i <= 33; i++) { // The 5 rabbits slots are in 29, 30, 31, 32 and 33. + ItemStack item = slots.get(i); if (item.getItem() != Items.PLAYER_HEAD || item.isEmpty()) continue; String lore = getConcattedLore(item); if (lore.isBlank()) continue; - OptionalDouble cpsIncreaseFactor = getCPSIncreaseFactor(lore); + OptionalDouble cpsIncreaseFactor = getRabbitCPSIncreaseFactor(lore); // The 5 usual rabbits if (cpsIncreaseFactor.isEmpty()) continue; //Something went wrong, skip this item - cpsIncreaseFactors.put(entry.getIntKey(), cpsIncreaseFactor.getAsDouble()); + cpsIncreaseFactors.put(i, cpsIncreaseFactor.getAsDouble()); } + OptionalDouble coachCpsIncreaseFactor = getCoachCPSIncreaseFactor(slots.get(45), slots.get(42)); // The coach + + if (!coachCpsIncreaseFactor.isEmpty()) cpsIncreaseFactors.put(42, coachCpsIncreaseFactor.getAsDouble()); + Optional bestSlot = cpsIncreaseFactors.int2DoubleEntrySet().stream().max(Map.Entry.comparingByValue()); if (bestSlot.isEmpty()) return List.of(); //No valid slots found, somehow. This means something went wrong, despite all the checks thus far. return List.of(ColorHighlight.green(bestSlot.get().getIntKey())); } + /** + * Utility method. + */ 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 + return concatenateLore(ItemUtils.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. + */ + private String concatenateLore(List 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(); + } + + private OptionalDouble getCoachCPSIncreaseFactor(ItemStack cpsItem, ItemStack coachItem) { + String cpsItemLore = getConcattedLore(cpsItem); + + Matcher cpsMatcher = CPS_PATTERN.matcher(cpsItemLore); + OptionalDouble currentCps = getDoubleFromMatcher(cpsMatcher); + if (currentCps.isEmpty()) return OptionalDouble.empty(); + + Matcher multiplierMatcher = TOTAL_MULTIPLIER_PATTERN.matcher(cpsItemLore); + OptionalDouble totalMultiplier = getDoubleFromMatcher(multiplierMatcher, cpsMatcher.end()); + if (totalMultiplier.isEmpty()) return OptionalDouble.empty(); + + String coachLore = getConcattedLore(coachItem); + + Matcher multiplierIncreaseMatcher = MULTIPLIER_INCREASE_PATTERN.matcher(coachLore); + OptionalDouble currentCpsMultiplier = getDoubleFromMatcher(multiplierIncreaseMatcher); + if (currentCpsMultiplier.isEmpty()) return OptionalDouble.empty(); + OptionalDouble nextCpsMultiplier = getDoubleFromMatcher(multiplierIncreaseMatcher); + if (nextCpsMultiplier.isEmpty()) { //This means that the coach isn't hired yet. + nextCpsMultiplier = currentCpsMultiplier; //So the first instance of the multiplier is actually the amount we'll get upon upgrading. + currentCpsMultiplier = OptionalDouble.of(0.0); //And so, we can re-assign values to the variables to make the calculation more readable. + } + + return OptionalDouble.of((currentCps.getAsDouble()/totalMultiplier.getAsDouble()) * (nextCpsMultiplier.getAsDouble() - currentCpsMultiplier.getAsDouble())); } /** @@ -71,30 +112,30 @@ public class ChocolateFactorySolver extends ContainerSolver { * @param lore The lore of the item * @return The CPS increase factor of the item, or an empty optional if it couldn't be found */ - private OptionalDouble getCPSIncreaseFactor(String lore) { + private OptionalDouble getRabbitCPSIncreaseFactor(String lore) { 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 + Matcher cpsMatcher = CPS_INCREASE_PATTERN.matcher(lore); + OptionalInt cps = getIntFromMatcher(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 + OptionalInt cost = getIntFromMatcher(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 + Matcher cpsMatcher = CPS_INCREASE_PATTERN.matcher(lore); + OptionalInt currentCps = getIntFromMatcher(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 + OptionalInt nextCps = getIntFromMatcher(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 + OptionalInt cost = getIntFromMatcher(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()); } @@ -102,12 +143,21 @@ public class ChocolateFactorySolver extends ContainerSolver { } } - private OptionalInt getValueFromMatcher(Matcher matcher) { - return getValueFromMatcher(matcher, matcher.hasMatch() ? matcher.end() : 0); + private OptionalInt getIntFromMatcher(Matcher matcher) { + return getIntFromMatcher(matcher, matcher.hasMatch() ? matcher.end() : 0); } - private OptionalInt getValueFromMatcher(Matcher matcher, int startingIndex) { + private OptionalInt getIntFromMatcher(Matcher matcher, int startingIndex) { if (!matcher.find(startingIndex)) return OptionalInt.empty(); return OptionalInt.of(Integer.parseInt(matcher.group(1).replace(",", ""))); } + + private OptionalDouble getDoubleFromMatcher(Matcher matcher) { + return getDoubleFromMatcher(matcher, matcher.hasMatch() ? matcher.end() : 0); + } + + private OptionalDouble getDoubleFromMatcher(Matcher matcher, int startingIndex) { + if (!matcher.find(startingIndex)) return OptionalDouble.empty(); + return OptionalDouble.of(Double.parseDouble(matcher.group(1).replace(",", ""))); + } } -- cgit From bb2d694dc3ec376d790dabf4db3797ec1531a3cd Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 14 May 2024 02:22:46 +0300 Subject: Improve TIME_TOWER_PATTERN regex in case of failure with the use of Matcher#matches --- .../hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java index 3b7fa3bc..89e1de74 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java @@ -20,7 +20,7 @@ import java.util.regex.Pattern; public class TimeTowerReminder { private static final String TIME_TOWER_FILE = "time_tower.txt"; - private static final Pattern TIME_TOWER_PATTERN = Pattern.compile("^TIME TOWER! Your Chocolate Factory production has increased"); + private static final Pattern TIME_TOWER_PATTERN = Pattern.compile("^TIME TOWER! Your Chocolate Factory production has increased by \\+[\\d.]+x for \\dh!$"); private static final Logger LOGGER = LoggerFactory.getLogger("Skyblocker Time Tower Reminder"); private TimeTowerReminder() { -- cgit From bf20bed1576eed02e14dede96a70bc9e6f41387e Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 14 May 2024 02:44:51 +0300 Subject: Change uses of raw integers to colors from Formatting --- .../de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java | 7 ++++--- .../skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'src/main/java/de/hysky') 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 11d9339f..031db52e 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java @@ -15,6 +15,7 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.decoration.ArmorStandEntity; import net.minecraft.item.ItemStack; import net.minecraft.text.Text; +import net.minecraft.util.Formatting; import org.apache.commons.lang3.mutable.MutableObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -103,9 +104,9 @@ public class EggFinder { record Egg(ArmorStandEntity entity, Waypoint waypoint) { } enum EggType { - LUNCH(new MutableObject<>(), 0x5555FF, "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjU2ODExMiwKICAicHJvZmlsZUlkIiA6ICI3NzUwYzFhNTM5M2Q0ZWQ0Yjc2NmQ4ZGUwOWY4MjU0NiIsCiAgInByb2ZpbGVOYW1lIiA6ICJSZWVkcmVsIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzdhZTZkMmQzMWQ4MTY3YmNhZjk1MjkzYjY4YTRhY2Q4NzJkNjZlNzUxZGI1YTM0ZjJjYmM2NzY2YTAzNTZkMGEiCiAgICB9CiAgfQp9"), - DINNER(new MutableObject<>(), 0x55FF55, "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY0OTcwMSwKICAicHJvZmlsZUlkIiA6ICI3NGEwMzQxNWY1OTI0ZTA4YjMyMGM2MmU1NGE3ZjJhYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJNZXp6aXIiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTVlMzYxNjU4MTlmZDI4NTBmOTg1NTJlZGNkNzYzZmY5ODYzMTMxMTkyODNjMTI2YWNlMGM0Y2M0OTVlNzZhOCIKICAgIH0KICB9Cn0"), - BREAKFAST(new MutableObject<>(), 0xFFAA00, "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY3MzE0OSwKICAicHJvZmlsZUlkIiA6ICJiN2I4ZTlhZjEwZGE0NjFmOTY2YTQxM2RmOWJiM2U4OCIsCiAgInByb2ZpbGVOYW1lIiA6ICJBbmFiYW5hbmFZZzciLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTQ5MzMzZDg1YjhhMzE1ZDAzMzZlYjJkZjM3ZDhhNzE0Y2EyNGM1MWI4YzYwNzRmMWI1YjkyN2RlYjUxNmMyNCIKICAgIH0KICB9Cn0"); + LUNCH(new MutableObject<>(), Formatting.BLUE.getColorValue(), "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjU2ODExMiwKICAicHJvZmlsZUlkIiA6ICI3NzUwYzFhNTM5M2Q0ZWQ0Yjc2NmQ4ZGUwOWY4MjU0NiIsCiAgInByb2ZpbGVOYW1lIiA6ICJSZWVkcmVsIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzdhZTZkMmQzMWQ4MTY3YmNhZjk1MjkzYjY4YTRhY2Q4NzJkNjZlNzUxZGI1YTM0ZjJjYmM2NzY2YTAzNTZkMGEiCiAgICB9CiAgfQp9"), + DINNER(new MutableObject<>(), Formatting.GREEN.getColorValue(), "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY0OTcwMSwKICAicHJvZmlsZUlkIiA6ICI3NGEwMzQxNWY1OTI0ZTA4YjMyMGM2MmU1NGE3ZjJhYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJNZXp6aXIiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTVlMzYxNjU4MTlmZDI4NTBmOTg1NTJlZGNkNzYzZmY5ODYzMTMxMTkyODNjMTI2YWNlMGM0Y2M0OTVlNzZhOCIKICAgIH0KICB9Cn0"), + BREAKFAST(new MutableObject<>(), Formatting.GOLD.getColorValue(), "ewogICJ0aW1lc3RhbXAiIDogMTcxMTQ2MjY3MzE0OSwKICAicHJvZmlsZUlkIiA6ICJiN2I4ZTlhZjEwZGE0NjFmOTY2YTQxM2RmOWJiM2U4OCIsCiAgInByb2ZpbGVOYW1lIiA6ICJBbmFiYW5hbmFZZzciLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTQ5MzMzZDg1YjhhMzE1ZDAzMzZlYjJkZjM3ZDhhNzE0Y2EyNGM1MWI4YzYwNzRmMWI1YjkyN2RlYjUxNmMyNCIKICAgIH0KICB9Cn0"); public final MutableObject egg; public final int color; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java index 89e1de74..aa3a49d8 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java @@ -8,6 +8,7 @@ import de.hysky.skyblocker.utils.scheduler.Scheduler; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; import net.minecraft.client.MinecraftClient; import net.minecraft.text.Text; +import net.minecraft.util.Formatting; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,7 +51,7 @@ public class TimeTowerReminder { private static void sendMessage() { if (MinecraftClient.getInstance().player == null) return; - MinecraftClient.getInstance().player.sendMessage(Constants.PREFIX.get().append(Text.literal("Your Chocolate Factory's Time Tower has deactivated!").withColor(0xFF5555))); + MinecraftClient.getInstance().player.sendMessage(Constants.PREFIX.get().append(Text.literal("Your Chocolate Factory's Time Tower has deactivated!").formatted(Formatting.RED))); File tempFile = SkyblockerMod.CONFIG_DIR.resolve(TIME_TOWER_FILE).toFile(); try { -- cgit From ba5047d708858ed863bbc207de20afcd42337451 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 14 May 2024 03:50:00 +0300 Subject: Mixin into ClientPlayNetworkHandler.onEntityTrackerUpdate to check for egg spawns --- .../de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java index 34e8264d..9ff1fc84 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java @@ -124,4 +124,9 @@ public abstract class ClientPlayNetworkHandlerMixin { private void skyblocker$onEntityEquip(EntityEquipmentUpdateS2CPacket packet, CallbackInfo ci, @Local Entity entity) { EggFinder.checkIfEgg(entity); } + + @Inject(method = "onEntityTrackerUpdate", at = @At(value = "TAIL")) + private void skyblocker$onEntityTrackerUpdate(EntityTrackerUpdateS2CPacket packet, CallbackInfo ci, @Local Entity entity) { + EggFinder.checkIfEgg(entity); + } } -- cgit From eee4ee696a4c4263c7e00af54c6faac40fe93ed0 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 14 May 2024 08:04:10 +0300 Subject: Time tower fix attempt --- .../chocolatefactory/TimeTowerReminder.java | 29 +++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java index aa3a49d8..f1458b59 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java @@ -16,8 +16,8 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.nio.file.Files; -import java.time.Instant; import java.util.regex.Pattern; +import java.util.stream.Stream; public class TimeTowerReminder { private static final String TIME_TOWER_FILE = "time_tower.txt"; @@ -34,16 +34,20 @@ public class TimeTowerReminder { public static void checkIfTimeTower(Message message, boolean overlay) { if (!TIME_TOWER_PATTERN.matcher(message.getString()).matches()) return; - Scheduler.INSTANCE.schedule(TimeTowerReminder::sendMessage, 60*60*20); // 1 hour + Scheduler.INSTANCE.schedule(TimeTowerReminder::sendMessage, 60 * 60 * 20); // 1 hour File tempFile = SkyblockerMod.CONFIG_DIR.resolve(TIME_TOWER_FILE).toFile(); - if (!tempFile.exists() && !tempFile.mkdir()) { - LOGGER.error("[Skyblocker Time Tower Reminder] Failed to create temp file for Time Tower Reminder!"); - return; + if (!tempFile.exists()) { + try { + tempFile.createNewFile(); + } catch (IOException e) { + LOGGER.error("[Skyblocker Time Tower Reminder] Failed to create temp file for Time Tower Reminder!", e); + return; + } } try (FileWriter writer = new FileWriter(tempFile)) { - writer.write(Instant.now().toString()); + writer.write(String.valueOf(System.currentTimeMillis())); } catch (IOException e) { LOGGER.error("[Skyblocker Time Tower Reminder] Failed to write to temp file for Time Tower Reminder!", e); } @@ -65,8 +69,15 @@ public class TimeTowerReminder { File tempFile = SkyblockerMod.CONFIG_DIR.resolve(TIME_TOWER_FILE).toFile(); if (!tempFile.exists()) return; - long time = tempFile.lastModified(); - if (System.currentTimeMillis() - time >= 60*60*1000) sendMessage(); - else Scheduler.INSTANCE.schedule(TimeTowerReminder::sendMessage, 60*60*20 - (int) ((System.currentTimeMillis() - time) / 50)); // 50 milliseconds is 1 tick + long time; + try (Stream file = Files.lines(tempFile.toPath())) { + time = Long.parseLong(file.findFirst().orElseThrow()); + } catch (Exception e) { + LOGGER.error("[Skyblocker Time Tower Reminder] Failed to read temp file for Time Tower Reminder!", e); + return; + } + + if (System.currentTimeMillis() - time >= 60 * 60 * 1000) sendMessage(); + else Scheduler.INSTANCE.schedule(TimeTowerReminder::sendMessage, 60 * 60 * 20 - (int) ((System.currentTimeMillis() - time) / 50)); // 50 milliseconds is 1 tick } } -- cgit From e8d5f6f8380ad0baca3f43b26298e852643127b1 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 14 May 2024 09:35:43 +0300 Subject: Add SkyblockTime Not sure if the AtomicReferences are helping with anything, just followed copilot. --- .../java/de/hysky/skyblocker/SkyblockerMod.java | 6 +-- .../de/hysky/skyblocker/utils/SkyblockTime.java | 61 ++++++++++++++++++++++ 2 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index 37f6d2a8..79f241b8 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -47,10 +47,7 @@ import de.hysky.skyblocker.skyblock.waypoint.FairySouls; import de.hysky.skyblocker.skyblock.waypoint.MythologicalRitual; import de.hysky.skyblocker.skyblock.waypoint.OrderedWaypoints; import de.hysky.skyblocker.skyblock.waypoint.Relics; -import de.hysky.skyblocker.utils.ApiUtils; -import de.hysky.skyblocker.utils.NEURepoManager; -import de.hysky.skyblocker.utils.ProfileUtils; -import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.*; import de.hysky.skyblocker.utils.chat.ChatMessageListener; import de.hysky.skyblocker.utils.discord.DiscordRPCManager; import de.hysky.skyblocker.utils.render.RenderHelper; @@ -187,6 +184,7 @@ public class SkyblockerMod implements ClientModInitializer { MobBoundingBoxes.init(); EggFinder.init(); TimeTowerReminder.init(); + SkyblockTime.init(); Scheduler.INSTANCE.scheduleCyclic(Utils::update, 20); Scheduler.INSTANCE.scheduleCyclic(DiscordRPCManager::updateDataAndPresence, 200); diff --git a/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java b/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java new file mode 100644 index 00000000..36db4ef3 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java @@ -0,0 +1,61 @@ +package de.hysky.skyblocker.utils; + +import de.hysky.skyblocker.utils.scheduler.Scheduler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +public class SkyblockTime { + private static final long SKYBLOCK_POCH = 1560275700000L; + public static final AtomicInteger skyblockYear = new AtomicInteger(0); + public static final AtomicReference skyblockSeason = new AtomicReference<>(Season.SPRING); + public static final AtomicReference skyblockMonth = new AtomicReference<>(Month.EARLY_SPRING); + public static final AtomicInteger skyblockDay = new AtomicInteger(0); + private static final Logger LOGGER = LoggerFactory.getLogger("Skyblocker Time"); + + private SkyblockTime() { + } + + public static void init() { + updateTime(); + //ScheduleCyclic already runs the task upon scheduling, so there's no need to call updateTime() here + Scheduler.INSTANCE.schedule(() -> Scheduler.INSTANCE.scheduleCyclic(SkyblockTime::updateTime, 1200 * 24), (int) (1200000 - (getSkyblockMillis() % 1200000)) / 50); + } + + private static long getSkyblockMillis() { + return System.currentTimeMillis() - SKYBLOCK_POCH; + } + + private static int getSkyblockYear() { + return (int) (Math.floor(getSkyblockMillis() / 446400000.0) + 1); + } + + private static int getSkyblockMonth() { + return (int) (Math.floor(getSkyblockMillis() / 37200000.0) % 12); + } + + private static int getSkyblockDay() { + return (int) (Math.floor(getSkyblockMillis() / 1200000.0) % 31 + 1); + } + + private static void updateTime() { + skyblockYear.set(getSkyblockYear()); + skyblockSeason.set(Season.values()[getSkyblockMonth() / 3]); + skyblockMonth.set(Month.values()[getSkyblockMonth()]); + skyblockDay.set(getSkyblockDay()); + LOGGER.info("[Skyblocker Time] Skyblock time updated to Year {}, Season {}, Month {}, Day {}",skyblockYear.get(), skyblockSeason.get(), skyblockMonth.get(), skyblockDay.get()); + } + + public enum Season { + SPRING, SUMMER, FALL, WINTER; + } + + public enum Month { + EARLY_SPRING, SPRING, LATE_SPRING, + EARLY_SUMMER, SUMMER, LATE_SUMMER, + EARLY_FALL, FALL, LATE_FALL, + EARLY_WINTER, WINTER, LATE_WINTER; + } +} -- cgit From 87c382b7ea32467d99f919ed8bdcbd2e7355e437 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 14 May 2024 09:37:01 +0300 Subject: Add season check to EggFinder --- .../java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/main/java/de/hysky') 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 031db52e..0e887fd2 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java @@ -4,6 +4,7 @@ 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.SkyblockTime; import de.hysky.skyblocker.utils.waypoint.Waypoint; import it.unimi.dsi.fastutil.objects.ObjectImmutableList; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; @@ -39,6 +40,7 @@ public class EggFinder { public static void checkIfEgg(Entity entity) { if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableEggFinder) return; + if (SkyblockTime.skyblockSeason.get() != SkyblockTime.Season.SPRING) return; if (!(entity instanceof ArmorStandEntity armorStand) || armorStand.hasCustomName() || !armorStand.isInvisible() || !armorStand.shouldHideBasePlate()) return; for (ItemStack itemStack : armorStand.getArmorItems()) { ItemUtils.getHeadTexture(itemStack).ifPresent(texture -> { -- cgit From 5ea7ccf01559a12f79bb06f4cf8f762895620038 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 14 May 2024 10:08:16 +0300 Subject: Refactor code, fix coach calculation and attempt to highlight the best affordable pick I tried to make the best pick still have yellow highlight while keeping the best affordable pick green but it's not working for some reason and I have no idea what's causing it'. --- .../chocolatefactory/ChocolateFactorySolver.java | 120 +++++++++++---------- 1 file changed, 61 insertions(+), 59 deletions(-) (limited to 'src/main/java/de/hysky') 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 5c809a98..ed4d0f5e 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -5,23 +5,25 @@ 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.minecraft.client.gui.screen.ingame.GenericContainerScreen; +import net.minecraft.client.MinecraftClient; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.text.Text; +import org.apache.commons.math3.analysis.function.Min; import java.util.*; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +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 CPS_INCREASE_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+ *"); private static final Pattern TOTAL_MULTIPLIER_PATTERN = Pattern.compile("Total Multiplier: ([\\d.]+)x"); private static final Pattern MULTIPLIER_INCREASE_PATTERN = Pattern.compile("\\+([\\d.]+)x Chocolate per second"); + private static final Pattern TOTAL_CHOCOLATE_PATTERN = Pattern.compile("([\\d,]+) Chocolate"); public ChocolateFactorySolver() { super("^Chocolate Factory$"); @@ -32,32 +34,37 @@ public class ChocolateFactorySolver extends ContainerSolver { return SkyblockerConfigManager.get().helpers.chocolateFactory.enableChocolateFactoryHelper; } - @Override - protected void start(GenericContainerScreen screen) { - markHighlightsDirty(); //Recalculate highlights when the screen is opened, which happens when upgrading rabbits - } - @Override protected List getColors(String[] groups, Int2ObjectMap slots) { - final Int2DoubleMap cpsIncreaseFactors = new Int2DoubleLinkedOpenHashMap(6); //There are only 5 rabbits on the screen + 1 for the coach + final Int2ObjectMap cpsIncreaseFactors = new Int2ObjectLinkedOpenHashMap<>(6); for (int i = 29; i <= 33; i++) { // The 5 rabbits slots are in 29, 30, 31, 32 and 33. ItemStack item = slots.get(i); if (item.getItem() != Items.PLAYER_HEAD || item.isEmpty()) continue; - String lore = getConcattedLore(item); - if (lore.isBlank()) continue; - - OptionalDouble cpsIncreaseFactor = getRabbitCPSIncreaseFactor(lore); // The 5 usual rabbits - if (cpsIncreaseFactor.isEmpty()) continue; //Something went wrong, skip this item - cpsIncreaseFactors.put(i, cpsIncreaseFactor.getAsDouble()); + int finalI = i; //Java, pfft. + getRabbit(item).ifPresent(rabbit -> cpsIncreaseFactors.put(finalI, rabbit)); } - OptionalDouble coachCpsIncreaseFactor = getCoachCPSIncreaseFactor(slots.get(45), slots.get(42)); // The coach - if (!coachCpsIncreaseFactor.isEmpty()) cpsIncreaseFactors.put(42, coachCpsIncreaseFactor.getAsDouble()); + //Coach is in slot 42 while the factory info item is in slot 45. + getCoach(slots.get(45), slots.get(42)).ifPresent(coach -> cpsIncreaseFactors.put(42, coach)); + if (cpsIncreaseFactors.isEmpty()) return List.of(); //Something went wrong. + + OptionalLong totalChocolate = getTotalChocolate(slots.get(13)); - Optional bestSlot = cpsIncreaseFactors.int2DoubleEntrySet().stream().max(Map.Entry.comparingByValue()); - if (bestSlot.isEmpty()) return List.of(); //No valid slots found, somehow. This means something went wrong, despite all the checks thus far. - return List.of(ColorHighlight.green(bestSlot.get().getIntKey())); + List> sorted = cpsIncreaseFactors.int2ObjectEntrySet() + .stream() //Compare cost/cpsIncrease rather than cpsIncrease/cost to avoid getting close to 0 and losing precision. + .sorted(Comparator.comparingDouble(entry -> entry.getValue().cost() / entry.getValue().cpsIncrease())) //Ascending order, lower = better + .dropWhile(entry -> entry.getValue().cost == 0) + .collect(Collectors.toCollection(LinkedList::new)); + + Int2ObjectMap.Entry bestEntry = sorted.removeFirst(); + if (totalChocolate.isEmpty() || bestEntry.getValue().cost < totalChocolate.getAsLong()) return List.of(ColorHighlight.green(bestEntry.getIntKey())); + + for (Int2ObjectMap.Entry entry : sorted) { + if (entry.getValue().cost > totalChocolate.getAsLong()) continue; + return List.of(ColorHighlight.green(entry.getIntKey()), ColorHighlight.yellow(bestEntry.getIntKey())); + } + return List.of(ColorHighlight.green(bestEntry.getIntKey())); } /** @@ -80,67 +87,59 @@ public class ChocolateFactorySolver extends ContainerSolver { return stringBuilder.toString(); } - private OptionalDouble getCoachCPSIncreaseFactor(ItemStack cpsItem, ItemStack coachItem) { + private Optional getCoach(ItemStack cpsItem, ItemStack coachItem) { + if (coachItem.isEmpty() || cpsItem.isEmpty() || coachItem.getItem() != Items.PLAYER_HEAD || cpsItem.getItem() != Items.COCOA_BEANS) return Optional.empty(); String cpsItemLore = getConcattedLore(cpsItem); Matcher cpsMatcher = CPS_PATTERN.matcher(cpsItemLore); OptionalDouble currentCps = getDoubleFromMatcher(cpsMatcher); - if (currentCps.isEmpty()) return OptionalDouble.empty(); + if (currentCps.isEmpty()) return Optional.empty(); Matcher multiplierMatcher = TOTAL_MULTIPLIER_PATTERN.matcher(cpsItemLore); OptionalDouble totalMultiplier = getDoubleFromMatcher(multiplierMatcher, cpsMatcher.end()); - if (totalMultiplier.isEmpty()) return OptionalDouble.empty(); + if (totalMultiplier.isEmpty()) return Optional.empty(); String coachLore = getConcattedLore(coachItem); Matcher multiplierIncreaseMatcher = MULTIPLIER_INCREASE_PATTERN.matcher(coachLore); OptionalDouble currentCpsMultiplier = getDoubleFromMatcher(multiplierIncreaseMatcher); - if (currentCpsMultiplier.isEmpty()) return OptionalDouble.empty(); + if (currentCpsMultiplier.isEmpty()) return Optional.empty(); + OptionalDouble nextCpsMultiplier = getDoubleFromMatcher(multiplierIncreaseMatcher); if (nextCpsMultiplier.isEmpty()) { //This means that the coach isn't hired yet. nextCpsMultiplier = currentCpsMultiplier; //So the first instance of the multiplier is actually the amount we'll get upon upgrading. currentCpsMultiplier = OptionalDouble.of(0.0); //And so, we can re-assign values to the variables to make the calculation more readable. } - return OptionalDouble.of((currentCps.getAsDouble()/totalMultiplier.getAsDouble()) * (nextCpsMultiplier.getAsDouble() - currentCpsMultiplier.getAsDouble())); + Matcher costMatcher = COST_PATTERN.matcher(coachLore); + OptionalInt cost = getIntFromMatcher(costMatcher, multiplierIncreaseMatcher.end()); //Cost comes after the multiplier line + if (cost.isEmpty()) return Optional.empty(); + + return Optional.of(new Rabbit(currentCps.getAsDouble() / totalMultiplier.getAsDouble() * (nextCpsMultiplier.getAsDouble() - currentCpsMultiplier.getAsDouble()), cost.getAsInt())); } - /** - * The "CPS increase factor" here is the increase in CPS per chocolate spent. - * The highest value among the choices is the best one to pick. - * - * @param lore The lore of the item - * @return The CPS increase factor of the item, or an empty optional if it couldn't be found - */ - private OptionalDouble getRabbitCPSIncreaseFactor(String lore) { - 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_INCREASE_PATTERN.matcher(lore); - OptionalInt cps = getIntFromMatcher(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 = getIntFromMatcher(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_INCREASE_PATTERN.matcher(lore); - OptionalInt currentCps = getIntFromMatcher(cpsMatcher); //Current cps is before the hire line - if (currentCps.isEmpty()) return OptionalDouble.empty(); - OptionalInt nextCps = getIntFromMatcher(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 = getIntFromMatcher(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 Optional getRabbit(ItemStack item) { + String lore = getConcattedLore(item); + Matcher cpsMatcher = CPS_INCREASE_PATTERN.matcher(lore); + OptionalInt currentCps = getIntFromMatcher(cpsMatcher); + if (currentCps.isEmpty()) return Optional.empty(); + OptionalInt nextCps = getIntFromMatcher(cpsMatcher); + if (nextCps.isEmpty()) { + nextCps = currentCps; //This means that the rabbit isn't hired yet. + currentCps = OptionalInt.of(0); //So the first instance of the cps is actually the amount we'll get upon hiring. } + + Matcher costMatcher = COST_PATTERN.matcher(lore); + OptionalInt cost = getIntFromMatcher(costMatcher, cpsMatcher.end()); //Cost comes after the cps line + if (cost.isEmpty()) return Optional.empty(); + return Optional.of(new Rabbit(nextCps.getAsInt() - currentCps.getAsInt(), cost.getAsInt())); + } + + private OptionalLong getTotalChocolate(ItemStack item) { + if (item.isEmpty() || item.getItem() != Items.PLAYER_HEAD) return OptionalLong.empty(); + Matcher matcher = TOTAL_CHOCOLATE_PATTERN.matcher(item.getName().getString()); + if (!matcher.find()) return OptionalLong.empty(); + return OptionalLong.of(Long.parseLong(matcher.group(1).replace(",", ""))); } private OptionalInt getIntFromMatcher(Matcher matcher) { @@ -160,4 +159,7 @@ public class ChocolateFactorySolver extends ContainerSolver { if (!matcher.find(startingIndex)) return OptionalDouble.empty(); return OptionalDouble.of(Double.parseDouble(matcher.group(1).replace(",", ""))); } + + private record Rabbit(double cpsIncrease, int cost) { + } } -- cgit From 5b7c40ea4cf6495dad5c935eb566f851d9062e57 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Wed, 15 May 2024 01:21:00 +0300 Subject: Refactor EggFinder for CompactDamage compatibility --- .../mixins/ClientPlayNetworkHandlerMixin.java | 183 ++++++++++----------- .../hysky/skyblocker/skyblock/CompactDamage.java | 1 + .../skyblock/chocolatefactory/EggFinder.java | 6 +- 3 files changed, 96 insertions(+), 94 deletions(-) (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java index 9ff1fc84..3ca68df3 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java @@ -35,98 +35,95 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(ClientPlayNetworkHandler.class) public abstract class ClientPlayNetworkHandlerMixin { - @Shadow - private ClientWorld world; - - @Shadow - @Final - private static Logger LOGGER; - - @Inject(method = "onBlockUpdate", at = @At("RETURN")) - private void skyblocker$onBlockUpdate(BlockUpdateS2CPacket packet, CallbackInfo ci) { - if (Utils.isInTheEnd() && SlayerUtils.isInSlayer()) { - BeaconHighlighter.beaconPositions.remove(packet.getPos()); - if (packet.getState().isOf(Blocks.BEACON)) { - BeaconHighlighter.beaconPositions.add(packet.getPos()); - } - } - } - - @Inject(method = "method_37472", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientWorld;removeEntity(ILnet/minecraft/entity/Entity$RemovalReason;)V")) - private void skyblocker$onItemDestroy(int entityId, CallbackInfo ci) { - if (world.getEntityById(entityId) instanceof ItemEntity itemEntity) { - DungeonManager.onItemPickup(itemEntity); - } - } - - @ModifyVariable(method = "onItemPickupAnimation", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientWorld;removeEntity(ILnet/minecraft/entity/Entity$RemovalReason;)V", ordinal = 0)) - private ItemEntity skyblocker$onItemPickup(ItemEntity itemEntity) { - DungeonManager.onItemPickup(itemEntity); - return itemEntity; - } - - @WrapWithCondition(method = "onEntityPassengersSet", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;)V", remap = false)) - private boolean skyblocker$cancelEntityPassengersWarning(Logger instance, String msg) { - return !Utils.isOnHypixel(); - } - - @WrapWithCondition(method = "onPlayerList", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V", remap = false)) - private boolean skyblocker$cancelPlayerListWarning(Logger instance, String format, Object arg1, Object arg2) { - return !Utils.isOnHypixel(); - } - - @Inject(method = "onPlaySound", at = @At("RETURN")) - private void skyblocker$onPlaySound(PlaySoundS2CPacket packet, CallbackInfo ci) { - FishingHelper.onSound(packet); - } - - @WrapWithCondition(method = "warnOnUnknownPayload", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V", remap = false)) - private boolean skyblocker$dropBadlionPacketWarnings(Logger instance, String message, Object identifier) { - return !(Utils.isOnHypixel() && ((Identifier) identifier).getNamespace().equals("badlion")); - } - - @WrapWithCondition(method = { "onScoreboardScoreUpdate", "onScoreboardScoreReset" }, at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V", remap = false)) - private boolean skyblocker$cancelUnknownScoreboardObjectiveWarnings(Logger instance, String message, Object objectiveName) { - return !Utils.isOnHypixel(); - } - - @WrapWithCondition(method = "onTeam", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;[Ljava/lang/Object;)V", remap = false)) - private boolean skyblocker$cancelTeamWarning(Logger instance, String format, Object... arg) { - return !Utils.isOnHypixel(); - } - - @Inject(method = "onParticle", at = @At("RETURN")) - private void skyblocker$onParticle(ParticleS2CPacket packet, CallbackInfo ci) { - MythologicalRitual.onParticle(packet); - EnderNodes.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;")) - private Entity skyblocker$onEntityDeath(Entity entity, @Local(argsOnly = true) EntityStatusS2CPacket packet) { - if (packet.getStatus() == EntityStatuses.PLAY_DEATH_SOUND_OR_ADD_PROJECTILE_HIT_PARTICLES) { - DungeonScore.handleEntityDeath(entity); - TheEnd.onEntityDeath(entity); - } - return entity; - } - - @Inject(method = "onEntityTrackerUpdate", at = @At("TAIL")) - private void skyblocker$onEntityTrackerUpdate(EntityTrackerUpdateS2CPacket packet, CallbackInfo ci, @Local Entity entity) { - if (!SkyblockerConfigManager.get().uiAndVisuals.compactDamage.enabled || !(entity instanceof ArmorStandEntity armorStandEntity)) return; - try { //Prevent packet handling fails if something goes wrong so that entity trackers still update, just without compact damage numbers + @Shadow + private ClientWorld world; + + @Shadow + @Final + private static Logger LOGGER; + + @Inject(method = "onBlockUpdate", at = @At("RETURN")) + private void skyblocker$onBlockUpdate(BlockUpdateS2CPacket packet, CallbackInfo ci) { + if (Utils.isInTheEnd() && SlayerUtils.isInSlayer()) { + BeaconHighlighter.beaconPositions.remove(packet.getPos()); + if (packet.getState().isOf(Blocks.BEACON)) { + BeaconHighlighter.beaconPositions.add(packet.getPos()); + } + } + } + + @Inject(method = "method_37472", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientWorld;removeEntity(ILnet/minecraft/entity/Entity$RemovalReason;)V")) + private void skyblocker$onItemDestroy(int entityId, CallbackInfo ci) { + if (world.getEntityById(entityId) instanceof ItemEntity itemEntity) { + DungeonManager.onItemPickup(itemEntity); + } + } + + @ModifyVariable(method = "onItemPickupAnimation", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientWorld;removeEntity(ILnet/minecraft/entity/Entity$RemovalReason;)V", ordinal = 0)) + private ItemEntity skyblocker$onItemPickup(ItemEntity itemEntity) { + DungeonManager.onItemPickup(itemEntity); + return itemEntity; + } + + @WrapWithCondition(method = "onEntityPassengersSet", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;)V", remap = false)) + private boolean skyblocker$cancelEntityPassengersWarning(Logger instance, String msg) { + return !Utils.isOnHypixel(); + } + + @WrapWithCondition(method = "onPlayerList", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V", remap = false)) + private boolean skyblocker$cancelPlayerListWarning(Logger instance, String format, Object arg1, Object arg2) { + return !Utils.isOnHypixel(); + } + + @Inject(method = "onPlaySound", at = @At("RETURN")) + private void skyblocker$onPlaySound(PlaySoundS2CPacket packet, CallbackInfo ci) { + FishingHelper.onSound(packet); + } + + @WrapWithCondition(method = "warnOnUnknownPayload", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V", remap = false)) + private boolean skyblocker$dropBadlionPacketWarnings(Logger instance, String message, Object identifier) { + return !(Utils.isOnHypixel() && ((Identifier) identifier).getNamespace().equals("badlion")); + } + + @WrapWithCondition(method = {"onScoreboardScoreUpdate", "onScoreboardScoreReset"}, at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V", remap = false)) + private boolean skyblocker$cancelUnknownScoreboardObjectiveWarnings(Logger instance, String message, Object objectiveName) { + return !Utils.isOnHypixel(); + } + + @WrapWithCondition(method = "onTeam", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;[Ljava/lang/Object;)V", remap = false)) + private boolean skyblocker$cancelTeamWarning(Logger instance, String format, Object... arg) { + return !Utils.isOnHypixel(); + } + + @Inject(method = "onParticle", at = @At("RETURN")) + private void skyblocker$onParticle(ParticleS2CPacket packet, CallbackInfo ci) { + MythologicalRitual.onParticle(packet); + EnderNodes.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;")) + private Entity skyblocker$onEntityDeath(Entity entity, @Local(argsOnly = true) EntityStatusS2CPacket packet) { + if (packet.getStatus() == EntityStatuses.PLAY_DEATH_SOUND_OR_ADD_PROJECTILE_HIT_PARTICLES) { + DungeonScore.handleEntityDeath(entity); + TheEnd.onEntityDeath(entity); + } + return entity; + } + + @Inject(method = "onEntityTrackerUpdate", at = @At("TAIL")) + private void skyblocker$onEntityTrackerUpdate(EntityTrackerUpdateS2CPacket packet, CallbackInfo ci, @Local Entity entity) { + if (!(entity instanceof ArmorStandEntity armorStandEntity)) return; + + EggFinder.checkIfEgg(armorStandEntity); + try { //Prevent packet handling fails if something goes wrong so that entity trackers still update, just without compact damage numbers CompactDamage.compactDamage(armorStandEntity); - } catch (Exception e) { - LOGGER.error("[Skyblocker Compact Damage] Failed to compact damage number", e); - } - } - - @Inject(method = "onEntityEquipmentUpdate", at = @At(value = "TAIL")) - private void skyblocker$onEntityEquip(EntityEquipmentUpdateS2CPacket packet, CallbackInfo ci, @Local Entity entity) { - EggFinder.checkIfEgg(entity); - } - - @Inject(method = "onEntityTrackerUpdate", at = @At(value = "TAIL")) - private void skyblocker$onEntityTrackerUpdate(EntityTrackerUpdateS2CPacket packet, CallbackInfo ci, @Local Entity entity) { - EggFinder.checkIfEgg(entity); - } + } catch (Exception e) { + LOGGER.error("[Skyblocker Compact Damage] Failed to compact damage number", e); + } + } + + @Inject(method = "onEntityEquipmentUpdate", at = @At(value = "TAIL")) + private void skyblocker$onEntityEquip(EntityEquipmentUpdateS2CPacket packet, CallbackInfo ci, @Local Entity entity) { + EggFinder.checkIfEgg(entity); + } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/CompactDamage.java b/src/main/java/de/hysky/skyblocker/skyblock/CompactDamage.java index 2837364b..8285a823 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/CompactDamage.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/CompactDamage.java @@ -19,6 +19,7 @@ public class CompactDamage { } public static void compactDamage(ArmorStandEntity entity) { + if (!SkyblockerConfigManager.get().uiAndVisuals.compactDamage.enabled) return; if (!entity.isInvisible() || !entity.hasCustomName() || !entity.isCustomNameVisible()) return; Text customName = entity.getCustomName(); String customNameStringified = customName.getString(); 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 0e887fd2..ee16abd9 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java @@ -39,9 +39,13 @@ public class EggFinder { } public static void checkIfEgg(Entity entity) { + if (entity instanceof ArmorStandEntity armorStand) checkIfEgg(armorStand); + } + + public static void checkIfEgg(ArmorStandEntity armorStand) { if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableEggFinder) return; if (SkyblockTime.skyblockSeason.get() != SkyblockTime.Season.SPRING) return; - if (!(entity instanceof ArmorStandEntity armorStand) || armorStand.hasCustomName() || !armorStand.isInvisible() || !armorStand.shouldHideBasePlate()) return; + if (armorStand.hasCustomName() || !armorStand.isInvisible() || !armorStand.shouldHideBasePlate()) return; for (ItemStack itemStack : armorStand.getArmorItems()) { ItemUtils.getHeadTexture(itemStack).ifPresent(texture -> { for (EggType type : EggType.entries) { -- cgit From 2a1321b8038e44770f9d0dbd6a876079a50f7159 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Wed, 15 May 2024 01:22:00 +0300 Subject: Update src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java Co-authored-by: Julienraptor01 --- .../skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/de/hysky') 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 ed4d0f5e..52704fe1 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -88,7 +88,7 @@ public class ChocolateFactorySolver extends ContainerSolver { } private Optional getCoach(ItemStack cpsItem, ItemStack coachItem) { - if (coachItem.isEmpty() || cpsItem.isEmpty() || coachItem.getItem() != Items.PLAYER_HEAD || cpsItem.getItem() != Items.COCOA_BEANS) return Optional.empty(); + if (!coachItem.isOf(Items.PLAYER_HEAD) || !cpsItem.isOf(Items.COCOA_BEANS)) return Optional.empty(); String cpsItemLore = getConcattedLore(cpsItem); Matcher cpsMatcher = CPS_PATTERN.matcher(cpsItemLore); -- cgit From fc3c1c00f4621511be3e4ed5bc47f1a138501fe5 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Wed, 15 May 2024 01:22:19 +0300 Subject: Update src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java Co-authored-by: Julienraptor01 --- .../skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/de/hysky') 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 52704fe1..2ba1a7e1 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -136,7 +136,7 @@ public class ChocolateFactorySolver extends ContainerSolver { } private OptionalLong getTotalChocolate(ItemStack item) { - if (item.isEmpty() || item.getItem() != Items.PLAYER_HEAD) return OptionalLong.empty(); + if (!item.isOf(Items.PLAYER_HEAD)) return OptionalLong.empty(); Matcher matcher = TOTAL_CHOCOLATE_PATTERN.matcher(item.getName().getString()); if (!matcher.find()) return OptionalLong.empty(); return OptionalLong.of(Long.parseLong(matcher.group(1).replace(",", ""))); -- cgit From c12dab27809e528161fe7090c4000f2b4db49942 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Wed, 15 May 2024 01:22:57 +0300 Subject: Update src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java Co-authored-by: Julienraptor01 --- .../skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java | 1 - 1 file changed, 1 deletion(-) (limited to 'src/main/java/de/hysky') 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 2ba1a7e1..148956db 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -5,7 +5,6 @@ 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.minecraft.client.MinecraftClient; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.text.Text; -- cgit From cb4964c45a89983a889f0b32f72a3868d061a2d1 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Wed, 15 May 2024 01:23:07 +0300 Subject: Update src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java Co-authored-by: Julienraptor01 --- .../skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java | 1 - 1 file changed, 1 deletion(-) (limited to 'src/main/java/de/hysky') 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 148956db..e989ee28 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -8,7 +8,6 @@ import it.unimi.dsi.fastutil.ints.*; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.text.Text; -import org.apache.commons.math3.analysis.function.Min; import java.util.*; import java.util.List; -- cgit From 4ba6a0f1fe89032152c8103b821c8451cfd52242 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Wed, 15 May 2024 01:23:24 +0300 Subject: Update src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java Co-authored-by: Julienraptor01 --- .../skyblock/chocolatefactory/ChocolateFactorySolver.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/main/java/de/hysky') 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 e989ee28..7c4bbbd6 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -37,10 +37,10 @@ public class ChocolateFactorySolver extends ContainerSolver { final Int2ObjectMap cpsIncreaseFactors = new Int2ObjectLinkedOpenHashMap<>(6); for (int i = 29; i <= 33; i++) { // The 5 rabbits slots are in 29, 30, 31, 32 and 33. ItemStack item = slots.get(i); - if (item.getItem() != Items.PLAYER_HEAD || item.isEmpty()) continue; - - int finalI = i; //Java, pfft. - getRabbit(item).ifPresent(rabbit -> cpsIncreaseFactors.put(finalI, rabbit)); + if (item.isOf(Items.PLAYER_HEAD)) { + int finalI = i; //Java, pfft. + getRabbit(item).ifPresent(rabbit -> cpsIncreaseFactors.put(finalI, rabbit)); + } } //Coach is in slot 42 while the factory info item is in slot 45. -- cgit From fff992ae9f09bc086fb128327790266f5f917446 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Wed, 15 May 2024 01:23:56 +0300 Subject: Update src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java Co-authored-by: Julienraptor01 --- .../skyblock/chocolatefactory/ChocolateFactorySolver.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/main/java/de/hysky') 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 7c4bbbd6..bceee649 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -56,13 +56,13 @@ public class ChocolateFactorySolver extends ContainerSolver { .collect(Collectors.toCollection(LinkedList::new)); Int2ObjectMap.Entry bestEntry = sorted.removeFirst(); - if (totalChocolate.isEmpty() || bestEntry.getValue().cost < totalChocolate.getAsLong()) return List.of(ColorHighlight.green(bestEntry.getIntKey())); + if (totalChocolate.isEmpty()) return List.of(ColorHighlight.yellow(bestEntry.getIntKey())); - for (Int2ObjectMap.Entry entry : sorted) { - if (entry.getValue().cost > totalChocolate.getAsLong()) continue; - return List.of(ColorHighlight.green(entry.getIntKey()), ColorHighlight.yellow(bestEntry.getIntKey())); - } - return List.of(ColorHighlight.green(bestEntry.getIntKey())); + if (bestEntry.getValue().cost <= totalChocolate.getAsLong()) return List.of(ColorHighlight.green(bestEntry.getIntKey())); + + for (Int2ObjectMap.Entry entry : sorted) if (entry.getValue().cost <= totalChocolate.getAsLong()) return List.of(ColorHighlight.green(entry.getIntKey()), ColorHighlight.yellow(bestEntry.getIntKey())); + + return List.of(ColorHighlight.yellow(bestEntry.getIntKey())); } /** -- cgit From 58f2e28cd3cc8d83caf19167c14edd58ef81238d Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Wed, 15 May 2024 03:00:49 +0300 Subject: Refactor ChocolateFactorySolver in preparation of tooltips --- .../chocolatefactory/ChocolateFactorySolver.java | 57 ++++++++++++---------- 1 file changed, 31 insertions(+), 26 deletions(-) (limited to 'src/main/java/de/hysky') 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 bceee649..2a6ad6b7 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -5,6 +5,7 @@ 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 it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.text.Text; @@ -13,7 +14,6 @@ import java.util.*; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; public class ChocolateFactorySolver extends ContainerSolver { private static final Pattern CPS_PATTERN = Pattern.compile("([\\d,.]+) Chocolate per second"); @@ -22,6 +22,8 @@ public class ChocolateFactorySolver extends ContainerSolver { private static final Pattern TOTAL_MULTIPLIER_PATTERN = Pattern.compile("Total Multiplier: ([\\d.]+)x"); private static final Pattern MULTIPLIER_INCREASE_PATTERN = Pattern.compile("\\+([\\d.]+)x Chocolate per second"); private static final Pattern TOTAL_CHOCOLATE_PATTERN = Pattern.compile("([\\d,]+) Chocolate"); + private static final ObjectArrayList cpsIncreaseFactors = new ObjectArrayList<>(6); + private static long totalChocolate = -1L; public ChocolateFactorySolver() { super("^Chocolate Factory$"); @@ -34,35 +36,38 @@ public class ChocolateFactorySolver extends ContainerSolver { @Override protected List getColors(String[] groups, Int2ObjectMap slots) { - final Int2ObjectMap cpsIncreaseFactors = new Int2ObjectLinkedOpenHashMap<>(6); + updateFactoryInfo(slots); + + if (totalChocolate <= 0 || cpsIncreaseFactors.isEmpty()) return List.of(); //Something went wrong or there's nothing we can afford. + Rabbit bestRabbit = cpsIncreaseFactors.getFirst(); + + if (bestRabbit.cost <= totalChocolate) return List.of(ColorHighlight.green(bestRabbit.slot)); + + for (Rabbit rabbit : cpsIncreaseFactors.subList(1, cpsIncreaseFactors.size())) { + if (rabbit.cost <= totalChocolate) { + return List.of(ColorHighlight.green(rabbit.slot), ColorHighlight.yellow(bestRabbit.slot)); + } + } + + return List.of(ColorHighlight.yellow(bestRabbit.slot)); + } + + private void updateFactoryInfo(Int2ObjectMap slots) { + cpsIncreaseFactors.clear(); + for (int i = 29; i <= 33; i++) { // The 5 rabbits slots are in 29, 30, 31, 32 and 33. ItemStack item = slots.get(i); if (item.isOf(Items.PLAYER_HEAD)) { - int finalI = i; //Java, pfft. - getRabbit(item).ifPresent(rabbit -> cpsIncreaseFactors.put(finalI, rabbit)); + getRabbit(item, i).ifPresent(cpsIncreaseFactors::add); } } //Coach is in slot 42 while the factory info item is in slot 45. - getCoach(slots.get(45), slots.get(42)).ifPresent(coach -> cpsIncreaseFactors.put(42, coach)); - if (cpsIncreaseFactors.isEmpty()) return List.of(); //Something went wrong. - - OptionalLong totalChocolate = getTotalChocolate(slots.get(13)); - - List> sorted = cpsIncreaseFactors.int2ObjectEntrySet() - .stream() //Compare cost/cpsIncrease rather than cpsIncrease/cost to avoid getting close to 0 and losing precision. - .sorted(Comparator.comparingDouble(entry -> entry.getValue().cost() / entry.getValue().cpsIncrease())) //Ascending order, lower = better - .dropWhile(entry -> entry.getValue().cost == 0) - .collect(Collectors.toCollection(LinkedList::new)); - - Int2ObjectMap.Entry bestEntry = sorted.removeFirst(); - if (totalChocolate.isEmpty()) return List.of(ColorHighlight.yellow(bestEntry.getIntKey())); - - if (bestEntry.getValue().cost <= totalChocolate.getAsLong()) return List.of(ColorHighlight.green(bestEntry.getIntKey())); - - for (Int2ObjectMap.Entry entry : sorted) if (entry.getValue().cost <= totalChocolate.getAsLong()) return List.of(ColorHighlight.green(entry.getIntKey()), ColorHighlight.yellow(bestEntry.getIntKey())); + getCoach(slots.get(45), slots.get(42)).ifPresent(cpsIncreaseFactors::add); + getTotalChocolate(slots.get(13)).ifPresent(l -> totalChocolate = l); - return List.of(ColorHighlight.yellow(bestEntry.getIntKey())); + //Compare cost/cpsIncrease rather than cpsIncrease/cost to avoid getting close to 0 and losing precision. + cpsIncreaseFactors.sort(Comparator.comparingDouble(rabbit -> rabbit.cost() / rabbit.cpsIncrease())); //Ascending order, lower = better } /** @@ -113,10 +118,10 @@ public class ChocolateFactorySolver extends ContainerSolver { OptionalInt cost = getIntFromMatcher(costMatcher, multiplierIncreaseMatcher.end()); //Cost comes after the multiplier line if (cost.isEmpty()) return Optional.empty(); - return Optional.of(new Rabbit(currentCps.getAsDouble() / totalMultiplier.getAsDouble() * (nextCpsMultiplier.getAsDouble() - currentCpsMultiplier.getAsDouble()), cost.getAsInt())); + return Optional.of(new Rabbit(currentCps.getAsDouble() / totalMultiplier.getAsDouble() * (nextCpsMultiplier.getAsDouble() - currentCpsMultiplier.getAsDouble()), cost.getAsInt(), 42)); } - private Optional getRabbit(ItemStack item) { + private Optional getRabbit(ItemStack item, int slot) { String lore = getConcattedLore(item); Matcher cpsMatcher = CPS_INCREASE_PATTERN.matcher(lore); OptionalInt currentCps = getIntFromMatcher(cpsMatcher); @@ -130,7 +135,7 @@ public class ChocolateFactorySolver extends ContainerSolver { Matcher costMatcher = COST_PATTERN.matcher(lore); OptionalInt cost = getIntFromMatcher(costMatcher, cpsMatcher.end()); //Cost comes after the cps line if (cost.isEmpty()) return Optional.empty(); - return Optional.of(new Rabbit(nextCps.getAsInt() - currentCps.getAsInt(), cost.getAsInt())); + return Optional.of(new Rabbit(nextCps.getAsInt() - currentCps.getAsInt(), cost.getAsInt(), slot)); } private OptionalLong getTotalChocolate(ItemStack item) { @@ -158,6 +163,6 @@ public class ChocolateFactorySolver extends ContainerSolver { return OptionalDouble.of(Double.parseDouble(matcher.group(1).replace(",", ""))); } - private record Rabbit(double cpsIncrease, int cost) { + private record Rabbit(double cpsIncrease, int cost, int slot) { } } -- cgit From 5fd12a306d35cebbf990015b05668ddee95b08e4 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Wed, 15 May 2024 03:45:38 +0300 Subject: Fix unemployed rabbits crashing the game --- .../skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/de/hysky') 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 2a6ad6b7..6606f69c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -115,7 +115,7 @@ public class ChocolateFactorySolver extends ContainerSolver { } Matcher costMatcher = COST_PATTERN.matcher(coachLore); - OptionalInt cost = getIntFromMatcher(costMatcher, multiplierIncreaseMatcher.end()); //Cost comes after the multiplier line + OptionalInt cost = getIntFromMatcher(costMatcher, multiplierIncreaseMatcher.hasMatch() ? multiplierIncreaseMatcher.end() : 0); //Cost comes after the multiplier line if (cost.isEmpty()) return Optional.empty(); return Optional.of(new Rabbit(currentCps.getAsDouble() / totalMultiplier.getAsDouble() * (nextCpsMultiplier.getAsDouble() - currentCpsMultiplier.getAsDouble()), cost.getAsInt(), 42)); @@ -133,7 +133,7 @@ public class ChocolateFactorySolver extends ContainerSolver { } Matcher costMatcher = COST_PATTERN.matcher(lore); - OptionalInt cost = getIntFromMatcher(costMatcher, cpsMatcher.end()); //Cost comes after the cps line + OptionalInt cost = getIntFromMatcher(costMatcher, cpsMatcher.hasMatch() ? cpsMatcher.end() : 0); //Cost comes after the cps line if (cost.isEmpty()) return Optional.empty(); return Optional.of(new Rabbit(nextCps.getAsInt() - currentCps.getAsInt(), cost.getAsInt(), slot)); } -- cgit From 30ecf3e856d4d10a4dfe1b0050ec71e70e4647a9 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Wed, 15 May 2024 05:21:13 +0300 Subject: Add tooltips for the chocolate factory Also fix unemployed coach crashing the game --- .../chocolatefactory/ChocolateFactorySolver.java | 165 ++++++++++++++------- .../skyblock/item/tooltip/ItemTooltip.java | 6 +- .../java/de/hysky/skyblocker/utils/RegexUtils.java | 55 +++++++ 3 files changed, 170 insertions(+), 56 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/utils/RegexUtils.java (limited to 'src/main/java/de/hysky') 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 6606f69c..b0bf3a56 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -1,15 +1,25 @@ package de.hysky.skyblocker.skyblock.chocolatefactory; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; import de.hysky.skyblocker.utils.ItemUtils; +import de.hysky.skyblocker.utils.RegexUtils; import de.hysky.skyblocker.utils.render.gui.ColorHighlight; import de.hysky.skyblocker.utils.render.gui.ContainerSolver; import it.unimi.dsi.fastutil.ints.*; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; +import net.minecraft.client.item.TooltipType; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; +import net.minecraft.text.MutableText; import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import java.text.DecimalFormat; import java.util.*; import java.util.List; import java.util.regex.Matcher; @@ -21,12 +31,18 @@ public class ChocolateFactorySolver extends ContainerSolver { private static final Pattern COST_PATTERN = Pattern.compile("Cost ([\\d,]+) Chocolate"); private static final Pattern TOTAL_MULTIPLIER_PATTERN = Pattern.compile("Total Multiplier: ([\\d.]+)x"); private static final Pattern MULTIPLIER_INCREASE_PATTERN = Pattern.compile("\\+([\\d.]+)x Chocolate per second"); - private static final Pattern TOTAL_CHOCOLATE_PATTERN = Pattern.compile("([\\d,]+) Chocolate"); + private static final Pattern CHOCOLATE_PATTERN = Pattern.compile("^([\\d,]+) Chocolate$"); private static final ObjectArrayList cpsIncreaseFactors = new ObjectArrayList<>(6); private static long totalChocolate = -1L; + private static double totalCps = -1.0; + private static double totalCpsMultiplier = -1.0; + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.#"); + private static ItemStack bestUpgrade = null; + private static ItemStack bestAffordableUpgrade = null; public ChocolateFactorySolver() { super("^Chocolate Factory$"); + ItemTooltipCallback.EVENT.register(ChocolateFactorySolver::handleTooltip); } @Override @@ -40,11 +56,12 @@ public class ChocolateFactorySolver extends ContainerSolver { if (totalChocolate <= 0 || cpsIncreaseFactors.isEmpty()) return List.of(); //Something went wrong or there's nothing we can afford. Rabbit bestRabbit = cpsIncreaseFactors.getFirst(); - + bestUpgrade = bestRabbit.itemStack; if (bestRabbit.cost <= totalChocolate) return List.of(ColorHighlight.green(bestRabbit.slot)); for (Rabbit rabbit : cpsIncreaseFactors.subList(1, cpsIncreaseFactors.size())) { if (rabbit.cost <= totalChocolate) { + bestAffordableUpgrade = rabbit.itemStack; return List.of(ColorHighlight.green(rabbit.slot), ColorHighlight.yellow(bestRabbit.slot)); } } @@ -52,7 +69,7 @@ public class ChocolateFactorySolver extends ContainerSolver { return List.of(ColorHighlight.yellow(bestRabbit.slot)); } - private void updateFactoryInfo(Int2ObjectMap slots) { + private static void updateFactoryInfo(Int2ObjectMap slots) { cpsIncreaseFactors.clear(); for (int i = 29; i <= 33; i++) { // The 5 rabbits slots are in 29, 30, 31, 32 and 33. @@ -62,18 +79,89 @@ public class ChocolateFactorySolver extends ContainerSolver { } } - //Coach is in slot 42 while the factory info item is in slot 45. - getCoach(slots.get(45), slots.get(42)).ifPresent(cpsIncreaseFactors::add); - getTotalChocolate(slots.get(13)).ifPresent(l -> totalChocolate = l); + //Coach is in slot 42 + getCoach(slots.get(42)).ifPresent(cpsIncreaseFactors::add); + RegexUtils.getLongFromMatcher(CHOCOLATE_PATTERN.matcher(slots.get(13).getName().getString())).ifPresent(l -> totalChocolate = l); + + //Cps item (cocoa bean) is in slot 45 + String cpsItemLore = getConcatenatedLore(slots.get(45)); + Matcher cpsMatcher = CPS_PATTERN.matcher(cpsItemLore); + RegexUtils.getDoubleFromMatcher(cpsMatcher).ifPresent(d -> totalCps = d); + + Matcher multiplierMatcher = TOTAL_MULTIPLIER_PATTERN.matcher(cpsItemLore); + RegexUtils.getDoubleFromMatcher(multiplierMatcher, cpsMatcher.hasMatch() ? cpsMatcher.end() : 0).ifPresent(d -> totalCpsMultiplier = d); //Compare cost/cpsIncrease rather than cpsIncrease/cost to avoid getting close to 0 and losing precision. cpsIncreaseFactors.sort(Comparator.comparingDouble(rabbit -> rabbit.cost() / rabbit.cpsIncrease())); //Ascending order, lower = better } + private static void handleTooltip(ItemStack stack, Item.TooltipContext tooltipContext, TooltipType tooltipType, List lines) { + if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableChocolateFactoryHelper) return; + if (!(MinecraftClient.getInstance().currentScreen instanceof GenericContainerScreen screen) || !screen.getTitle().getString().equals("Chocolate Factory") ) return; + + String lore = concatenateLore(lines); + Matcher costMatcher = COST_PATTERN.matcher(lore); + OptionalLong cost = RegexUtils.getLongFromMatcher(costMatcher); + if (cost.isEmpty() || totalChocolate == -1L || totalCps == -1.0) return; + + lines.add(ItemTooltip.createSmoothLine()); + + lines.add(Text.literal("") + .append(Text.literal("Time until upgrade: ").formatted(Formatting.GRAY)) + .append(formatTime((cost.getAsLong() - totalChocolate) / totalCps))); + + if (cpsIncreaseFactors.isEmpty()) return; + + for (int j = 0; j < cpsIncreaseFactors.size(); j++) { + Rabbit rabbit = cpsIncreaseFactors.get(j); + if (rabbit.itemStack != stack) continue; + + lines.add(Text.literal("") + .append(Text.literal("CPS Increase: ").formatted(Formatting.GRAY)) + .append(Text.literal(DECIMAL_FORMAT.format(rabbit.cpsIncrease)).formatted(Formatting.GOLD))); + + lines.add(Text.literal("") + .append(Text.literal("Cost per CPS: ").formatted(Formatting.GRAY)) + .append(Text.literal(DECIMAL_FORMAT.format(rabbit.cost / rabbit.cpsIncrease)).formatted(Formatting.GOLD))); + + if (rabbit.itemStack == bestUpgrade) { + if (cost.getAsLong() <= 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.itemStack == bestAffordableUpgrade && cost.getAsLong() <= totalChocolate) { + lines.add(Text.literal("Best upgrade you can afford").formatted(Formatting.GREEN)); + } + } + } + + private static MutableText formatTime(double 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); + } + /** * Utility method. */ - private String getConcattedLore(ItemStack item) { + private static String getConcatenatedLore(ItemStack item) { return concatenateLore(ItemUtils.getLore(item)); } @@ -81,7 +169,7 @@ public class ChocolateFactorySolver extends ContainerSolver { * 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. */ - private String concatenateLore(List lore) { + private static String concatenateLore(List lore) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < lore.size(); i++) { stringBuilder.append(lore.get(i).getString()); @@ -90,25 +178,17 @@ public class ChocolateFactorySolver extends ContainerSolver { return stringBuilder.toString(); } - private Optional getCoach(ItemStack cpsItem, ItemStack coachItem) { - if (!coachItem.isOf(Items.PLAYER_HEAD) || !cpsItem.isOf(Items.COCOA_BEANS)) return Optional.empty(); - String cpsItemLore = getConcattedLore(cpsItem); - - Matcher cpsMatcher = CPS_PATTERN.matcher(cpsItemLore); - OptionalDouble currentCps = getDoubleFromMatcher(cpsMatcher); - if (currentCps.isEmpty()) return Optional.empty(); - - Matcher multiplierMatcher = TOTAL_MULTIPLIER_PATTERN.matcher(cpsItemLore); - OptionalDouble totalMultiplier = getDoubleFromMatcher(multiplierMatcher, cpsMatcher.end()); - if (totalMultiplier.isEmpty()) return Optional.empty(); + private static Optional getCoach(ItemStack coachItem) { + if (!coachItem.isOf(Items.PLAYER_HEAD)) return Optional.empty(); + String coachLore = getConcatenatedLore(coachItem); - String coachLore = getConcattedLore(coachItem); + if (totalCpsMultiplier == -1.0) return Optional.empty(); //We need the total multiplier to calculate the increase in cps. Matcher multiplierIncreaseMatcher = MULTIPLIER_INCREASE_PATTERN.matcher(coachLore); - OptionalDouble currentCpsMultiplier = getDoubleFromMatcher(multiplierIncreaseMatcher); + OptionalDouble currentCpsMultiplier = RegexUtils.getDoubleFromMatcher(multiplierIncreaseMatcher); if (currentCpsMultiplier.isEmpty()) return Optional.empty(); - OptionalDouble nextCpsMultiplier = getDoubleFromMatcher(multiplierIncreaseMatcher); + OptionalDouble nextCpsMultiplier = RegexUtils.getDoubleFromMatcher(multiplierIncreaseMatcher); if (nextCpsMultiplier.isEmpty()) { //This means that the coach isn't hired yet. nextCpsMultiplier = currentCpsMultiplier; //So the first instance of the multiplier is actually the amount we'll get upon upgrading. currentCpsMultiplier = OptionalDouble.of(0.0); //And so, we can re-assign values to the variables to make the calculation more readable. @@ -118,51 +198,26 @@ public class ChocolateFactorySolver extends ContainerSolver { OptionalInt cost = getIntFromMatcher(costMatcher, multiplierIncreaseMatcher.hasMatch() ? multiplierIncreaseMatcher.end() : 0); //Cost comes after the multiplier line if (cost.isEmpty()) return Optional.empty(); - return Optional.of(new Rabbit(currentCps.getAsDouble() / totalMultiplier.getAsDouble() * (nextCpsMultiplier.getAsDouble() - currentCpsMultiplier.getAsDouble()), cost.getAsInt(), 42)); + return Optional.of(new Rabbit(totalCps / totalCpsMultiplier * (nextCpsMultiplier.getAsDouble() - currentCpsMultiplier.getAsDouble()), cost.getAsInt(), 42, coachItem)); } - private Optional getRabbit(ItemStack item, int slot) { - String lore = getConcattedLore(item); + private static Optional getRabbit(ItemStack item, int slot) { + String lore = getConcatenatedLore(item); Matcher cpsMatcher = CPS_INCREASE_PATTERN.matcher(lore); - OptionalInt currentCps = getIntFromMatcher(cpsMatcher); + OptionalInt currentCps = RegexUtils.getIntFromMatcher(cpsMatcher); if (currentCps.isEmpty()) return Optional.empty(); - OptionalInt nextCps = getIntFromMatcher(cpsMatcher); + OptionalInt nextCps = RegexUtils.getIntFromMatcher(cpsMatcher); if (nextCps.isEmpty()) { nextCps = currentCps; //This means that the rabbit isn't hired yet. currentCps = OptionalInt.of(0); //So the first instance of the cps is actually the amount we'll get upon hiring. } Matcher costMatcher = COST_PATTERN.matcher(lore); - OptionalInt cost = getIntFromMatcher(costMatcher, cpsMatcher.hasMatch() ? cpsMatcher.end() : 0); //Cost comes after the cps line + OptionalInt cost = RegexUtils.getIntFromMatcher(costMatcher, cpsMatcher.hasMatch() ? cpsMatcher.end() : 0); //Cost comes after the cps line if (cost.isEmpty()) return Optional.empty(); - return Optional.of(new Rabbit(nextCps.getAsInt() - currentCps.getAsInt(), cost.getAsInt(), slot)); - } - - private OptionalLong getTotalChocolate(ItemStack item) { - if (!item.isOf(Items.PLAYER_HEAD)) return OptionalLong.empty(); - Matcher matcher = TOTAL_CHOCOLATE_PATTERN.matcher(item.getName().getString()); - if (!matcher.find()) return OptionalLong.empty(); - return OptionalLong.of(Long.parseLong(matcher.group(1).replace(",", ""))); - } - - private OptionalInt getIntFromMatcher(Matcher matcher) { - return getIntFromMatcher(matcher, matcher.hasMatch() ? matcher.end() : 0); - } - - private OptionalInt getIntFromMatcher(Matcher matcher, int startingIndex) { - if (!matcher.find(startingIndex)) return OptionalInt.empty(); - return OptionalInt.of(Integer.parseInt(matcher.group(1).replace(",", ""))); - } - - private OptionalDouble getDoubleFromMatcher(Matcher matcher) { - return getDoubleFromMatcher(matcher, matcher.hasMatch() ? matcher.end() : 0); - } - - private OptionalDouble getDoubleFromMatcher(Matcher matcher, int startingIndex) { - if (!matcher.find(startingIndex)) return OptionalDouble.empty(); - return OptionalDouble.of(Double.parseDouble(matcher.group(1).replace(",", ""))); + return Optional.of(new Rabbit(nextCps.getAsInt() - currentCps.getAsInt(), cost.getAsInt(), slot, item)); } - private record Rabbit(double cpsIncrease, int cost, int slot) { + private record Rabbit(double cpsIncrease, int cost, int slot, ItemStack itemStack) { } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java index c6caaf41..6e269790 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java @@ -398,11 +398,15 @@ public class ItemTooltip { for (int i = 0; i < lines.size(); i++) { Text line = lines.get(i); if (line.getString().equals("-----------------")) { - lines.set(i, Text.literal(" ").formatted(Formatting.DARK_GRAY, Formatting.STRIKETHROUGH, Formatting.BOLD)); + lines.set(i, createSmoothLine()); } } } + public static Text createSmoothLine() { + return Text.literal(" ").formatted(Formatting.DARK_GRAY, Formatting.STRIKETHROUGH, Formatting.BOLD); + } + // If these options is true beforehand, the client will get first data of these options while loading. // After then, it will only fetch the data if it is on Skyblock. public static int minute = 0; diff --git a/src/main/java/de/hysky/skyblocker/utils/RegexUtils.java b/src/main/java/de/hysky/skyblocker/utils/RegexUtils.java new file mode 100644 index 00000000..5b91a80b --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/RegexUtils.java @@ -0,0 +1,55 @@ +package de.hysky.skyblocker.utils; + +import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.OptionalLong; +import java.util.regex.Matcher; + +public class RegexUtils { + /** + * @return An OptionalLong of the first group in the matcher, or an empty OptionalLong if the matcher doesn't find anything. + */ + public static OptionalLong getLongFromMatcher(Matcher matcher) { + return getLongFromMatcher(matcher, matcher.hasMatch() ? matcher.end() : 0); + } + + /** + * @return An OptionalLong of the first group in the matcher, or an empty OptionalLong if the matcher doesn't find anything. + */ + public static OptionalLong getLongFromMatcher(Matcher matcher, int startingIndex) { + if (!matcher.find(startingIndex)) return OptionalLong.empty(); + return OptionalLong.of(Long.parseLong(matcher.group(1).replace(",", ""))); + } + + /** + * @return An OptionalInt of the first group in the matcher, or an empty OptionalInt if the matcher doesn't find anything. + */ + public static OptionalInt getIntFromMatcher(Matcher matcher) { + return getIntFromMatcher(matcher, matcher.hasMatch() ? matcher.end() : 0); + } + + /** + * @return An OptionalInt of the first group in the matcher, or an empty OptionalInt if the matcher doesn't find anything. + */ + public static OptionalInt getIntFromMatcher(Matcher matcher, int startingIndex) { + if (!matcher.find(startingIndex)) return OptionalInt.empty(); + return OptionalInt.of(Integer.parseInt(matcher.group(1).replace(",", ""))); + } + + /** + * @return An OptionalDouble of the first group in the matcher, or an empty OptionalDouble if the matcher doesn't find anything. + * @implNote Assumes the decimal separator is `.` + */ + public static OptionalDouble getDoubleFromMatcher(Matcher matcher) { + return getDoubleFromMatcher(matcher, matcher.hasMatch() ? matcher.end() : 0); + } + + /** + * @return An OptionalDouble of the first group in the matcher, or an empty OptionalDouble if the matcher doesn't find anything. + * @implNote Assumes the decimal separator is `.` + */ + public static OptionalDouble getDoubleFromMatcher(Matcher matcher, int startingIndex) { + if (!matcher.find(startingIndex)) return OptionalDouble.empty(); + return OptionalDouble.of(Double.parseDouble(matcher.group(1).replace(",", ""))); + } +} -- cgit From 710680242b375b8835d4550af4ec021225dde362 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Wed, 15 May 2024 05:24:41 +0300 Subject: Fix missing `RegexUtils.` --- .../skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/de/hysky') 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 b0bf3a56..fb7d4b88 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -195,7 +195,7 @@ public class ChocolateFactorySolver extends ContainerSolver { } Matcher costMatcher = COST_PATTERN.matcher(coachLore); - OptionalInt cost = getIntFromMatcher(costMatcher, multiplierIncreaseMatcher.hasMatch() ? multiplierIncreaseMatcher.end() : 0); //Cost comes after the multiplier line + OptionalInt cost = RegexUtils.getIntFromMatcher(costMatcher, multiplierIncreaseMatcher.hasMatch() ? multiplierIncreaseMatcher.end() : 0); //Cost comes after the multiplier line if (cost.isEmpty()) return Optional.empty(); return Optional.of(new Rabbit(totalCps / totalCpsMultiplier * (nextCpsMultiplier.getAsDouble() - currentCpsMultiplier.getAsDouble()), cost.getAsInt(), 42, coachItem)); -- cgit From 40096023d7c8cd80597d7aa27c2c601f8365c7d5 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Wed, 15 May 2024 18:42:01 +0300 Subject: Add thousand separators to the CPS format --- .../skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/main/java/de/hysky') 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 fb7d4b88..6defcab4 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -36,7 +36,7 @@ public class ChocolateFactorySolver extends ContainerSolver { private static long totalChocolate = -1L; private static double totalCps = -1.0; private static double totalCpsMultiplier = -1.0; - private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.#"); + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#,###.#"); private static ItemStack bestUpgrade = null; private static ItemStack bestAffordableUpgrade = null; @@ -112,8 +112,7 @@ public class ChocolateFactorySolver extends ContainerSolver { if (cpsIncreaseFactors.isEmpty()) return; - for (int j = 0; j < cpsIncreaseFactors.size(); j++) { - Rabbit rabbit = cpsIncreaseFactors.get(j); + for (Rabbit rabbit : cpsIncreaseFactors) { if (rabbit.itemStack != stack) continue; lines.add(Text.literal("") -- cgit From 4b477d0efdbb54460c3e58e515450565c350042a Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Thu, 16 May 2024 14:18:10 +0300 Subject: Revert ItemUtils.getHeadTexture change and add ItemUtils.getHeadTextureOptional instead --- src/main/java/de/hysky/skyblocker/debug/Debug.java | 4 +--- .../skyblocker/skyblock/chocolatefactory/EggFinder.java | 2 +- .../java/de/hysky/skyblocker/skyblock/entity/MobGlow.java | 2 +- .../de/hysky/skyblocker/skyblock/garden/VisitorHelper.java | 4 +++- src/main/java/de/hysky/skyblocker/utils/ItemUtils.java | 14 ++++++++++---- 5 files changed, 16 insertions(+), 10 deletions(-) (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/debug/Debug.java b/src/main/java/de/hysky/skyblocker/debug/Debug.java index 038e7a5a..d642ca5b 100644 --- a/src/main/java/de/hysky/skyblocker/debug/Debug.java +++ b/src/main/java/de/hysky/skyblocker/debug/Debug.java @@ -83,9 +83,7 @@ public class Debug { Iterable equippedItems = armorStand.getEquippedItems(); for (ItemStack stack : equippedItems) { - ItemUtils.getHeadTexture(stack).ifPresent(texture -> { - context.getSource().sendFeedback(Text.of(texture)); - }); + ItemUtils.getHeadTextureOptional(stack).ifPresent(texture -> context.getSource().sendFeedback(Text.of(texture))); } } 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 ee16abd9..2f027f81 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java @@ -47,7 +47,7 @@ public class EggFinder { if (SkyblockTime.skyblockSeason.get() != SkyblockTime.Season.SPRING) return; if (armorStand.hasCustomName() || !armorStand.isInvisible() || !armorStand.shouldHideBasePlate()) return; for (ItemStack itemStack : armorStand.getArmorItems()) { - ItemUtils.getHeadTexture(itemStack).ifPresent(texture -> { + ItemUtils.getHeadTextureOptional(itemStack).ifPresent(texture -> { for (EggType type : EggType.entries) { if (texture.equals(type.texture) && type.egg.getValue() == null) { handleFoundEgg(armorStand, type); 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 df9a32c6..d6f9410b 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).orElse(""); + String texture = ItemUtils.getHeadTexture(armorItem); 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 0f349a4f..682933f4 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/garden/VisitorHelper.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/garden/VisitorHelper.java @@ -94,7 +94,9 @@ public class VisitorHelper { } private static @Nullable String getTextureOrNull(ItemStack stack) { - return ItemUtils.getHeadTexture(stack).orElse(null); + String texture = ItemUtils.getHeadTexture(stack); + + return texture.isEmpty() ? null : texture; } private static void processLore(String visitorName, @Nullable String visitorTexture, List loreList) { diff --git a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java index 6b850b3b..6f98efa6 100644 --- a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java @@ -203,16 +203,22 @@ public class ItemUtils { return Codecs.GAME_PROFILE_PROPERTY_MAP.parse(JsonOps.INSTANCE, JsonParser.parseString("[{\"name\":\"textures\",\"value\":\"" + textureValue + "\"}]")).getOrThrow(); } - public static Optional getHeadTexture(ItemStack stack) { - if (!stack.isOf(Items.PLAYER_HEAD) || !stack.contains(DataComponentTypes.PROFILE)) return Optional.empty(); + public static String getHeadTexture(ItemStack stack) { + if (!stack.isOf(Items.PLAYER_HEAD) || !stack.contains(DataComponentTypes.PROFILE)) return ""; Iterator iterator = stack.get(DataComponentTypes.PROFILE) .properties() .get("textures") .iterator(); - if (!iterator.hasNext()) return Optional.empty(); - return Optional.of(iterator.next().value()); + if (!iterator.hasNext()) return ""; + return iterator.next().value(); + } + + public static Optional getHeadTextureOptional(ItemStack stack) { + String texture = getHeadTexture(stack); + if (texture == null) return Optional.empty(); + return Optional.of(texture); } public static ItemStack getSkyblockerStack() { -- cgit From fa371138fc588256bba0751d2f76e5b8b57940f2 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Thu, 16 May 2024 14:45:36 +0300 Subject: Attempt to fix decimal format depending on the user's locale --- .../skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/main/java/de/hysky') 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 6defcab4..0e8918de 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -20,6 +20,7 @@ import net.minecraft.text.Text; import net.minecraft.util.Formatting; import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; import java.util.*; import java.util.List; import java.util.regex.Matcher; @@ -36,7 +37,7 @@ public class ChocolateFactorySolver extends ContainerSolver { private static long totalChocolate = -1L; private static double totalCps = -1.0; private static double totalCpsMultiplier = -1.0; - private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#,###.#"); + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#,###.#", DecimalFormatSymbols.getInstance(Locale.ENGLISH)); private static ItemStack bestUpgrade = null; private static ItemStack bestAffordableUpgrade = null; -- cgit From 8fed85f6a02054eaecbdcbb8e596632a899c1cae Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Fri, 17 May 2024 06:32:54 +0300 Subject: Do a bunch of things that I can't split into separate commits - Added prestige highlight, time tower and prestige tooltips - Refactored handleTooltip to be more modular. --- .../chocolatefactory/ChocolateFactorySolver.java | 151 ++++++++++++++++++--- 1 file changed, 135 insertions(+), 16 deletions(-) (limited to 'src/main/java/de/hysky') 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 0e8918de..a6ec144e 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -18,6 +18,8 @@ import net.minecraft.item.Items; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Formatting; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; @@ -33,10 +35,14 @@ public class ChocolateFactorySolver extends ContainerSolver { private static final Pattern TOTAL_MULTIPLIER_PATTERN = Pattern.compile("Total Multiplier: ([\\d.]+)x"); private static final Pattern MULTIPLIER_INCREASE_PATTERN = Pattern.compile("\\+([\\d.]+)x Chocolate per second"); private static final Pattern CHOCOLATE_PATTERN = Pattern.compile("^([\\d,]+) Chocolate$"); + private static final Pattern PRESTIGE_REQUIREMENT_PATTERN = Pattern.compile("Chocolate this Prestige: ([\\d,]+) +Requires (\\S+) Chocolate this Prestige!"); private static final ObjectArrayList cpsIncreaseFactors = new ObjectArrayList<>(6); private static long totalChocolate = -1L; private static double totalCps = -1.0; private static double totalCpsMultiplier = -1.0; + private static long requiredUntilNextPrestige = -1L; + private static double timeTowerMultiplier = -1.0; + private static boolean isTimeTowerActive = false; private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#,###.#", DecimalFormatSymbols.getInstance(Locale.ENGLISH)); private static ItemStack bestUpgrade = null; private static ItemStack bestAffordableUpgrade = null; @@ -54,20 +60,28 @@ public class ChocolateFactorySolver extends ContainerSolver { @Override protected List getColors(String[] groups, Int2ObjectMap slots) { updateFactoryInfo(slots); + List highlights = new ArrayList<>(); - if (totalChocolate <= 0 || cpsIncreaseFactors.isEmpty()) return List.of(); //Something went wrong or there's nothing we can afford. + getPrestigeHighlight(slots.get(28)).ifPresent(highlights::add); + + if (totalChocolate <= 0 || cpsIncreaseFactors.isEmpty()) return highlights; //Something went wrong or there's nothing we can afford. Rabbit bestRabbit = cpsIncreaseFactors.getFirst(); bestUpgrade = bestRabbit.itemStack; - if (bestRabbit.cost <= totalChocolate) return List.of(ColorHighlight.green(bestRabbit.slot)); + if (bestRabbit.cost <= totalChocolate) { + highlights.add(ColorHighlight.green(bestRabbit.slot)); + return highlights; + } + highlights.add(ColorHighlight.yellow(bestRabbit.slot)); for (Rabbit rabbit : cpsIncreaseFactors.subList(1, cpsIncreaseFactors.size())) { if (rabbit.cost <= totalChocolate) { bestAffordableUpgrade = rabbit.itemStack; - return List.of(ColorHighlight.green(rabbit.slot), ColorHighlight.yellow(bestRabbit.slot)); + highlights.add(ColorHighlight.green(rabbit.slot)); + break; } } - return List.of(ColorHighlight.yellow(bestRabbit.slot)); + return highlights; } private static void updateFactoryInfo(Int2ObjectMap slots) { @@ -82,58 +96,132 @@ public class ChocolateFactorySolver extends ContainerSolver { //Coach is in slot 42 getCoach(slots.get(42)).ifPresent(cpsIncreaseFactors::add); + + //The clickable chocolate is in slot 13, holds the total chocolate RegexUtils.getLongFromMatcher(CHOCOLATE_PATTERN.matcher(slots.get(13).getName().getString())).ifPresent(l -> totalChocolate = l); //Cps item (cocoa bean) is in slot 45 String cpsItemLore = getConcatenatedLore(slots.get(45)); Matcher cpsMatcher = CPS_PATTERN.matcher(cpsItemLore); RegexUtils.getDoubleFromMatcher(cpsMatcher).ifPresent(d -> totalCps = d); - Matcher multiplierMatcher = TOTAL_MULTIPLIER_PATTERN.matcher(cpsItemLore); RegexUtils.getDoubleFromMatcher(multiplierMatcher, cpsMatcher.hasMatch() ? cpsMatcher.end() : 0).ifPresent(d -> totalCpsMultiplier = d); + //Prestige item is in slot 28 + Matcher matcher = PRESTIGE_REQUIREMENT_PATTERN.matcher(getConcatenatedLore(slots.get(28))); + OptionalLong currentChocolate = RegexUtils.getLongFromMatcher(matcher); + if (currentChocolate.isPresent()) { + String requirement = matcher.group(2); //If the first one matched, we can assume the 2nd one is also matched since it's one whole regex + //Since the last character is either M or B we can just try to replace both characters. Only the correct one will actually replace anything. + String amountString = requirement.replace("M", "000000").replace("B", "000000000"); + if (NumberUtils.isParsable(amountString)) { + requiredUntilNextPrestige = Long.parseLong(amountString) - currentChocolate.getAsLong(); + } + } + + //Time Tower is in slot 39 + timeTowerMultiplier = romanToDecimal(StringUtils.substringAfterLast(slots.get(39).getName().getString(), ' ')) / 10.0; //The name holds the level, which is multiplier * 10 in roman numerals + isTimeTowerActive = ItemUtils.getLore(slots.get(39)).getLast().getString().equals("The Time Tower is active!"); + //Compare cost/cpsIncrease rather than cpsIncrease/cost to avoid getting close to 0 and losing precision. cpsIncreaseFactors.sort(Comparator.comparingDouble(rabbit -> rabbit.cost() / rabbit.cpsIncrease())); //Ascending order, lower = better } private static void handleTooltip(ItemStack stack, Item.TooltipContext tooltipContext, TooltipType tooltipType, List lines) { if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableChocolateFactoryHelper) return; - if (!(MinecraftClient.getInstance().currentScreen instanceof GenericContainerScreen screen) || !screen.getTitle().getString().equals("Chocolate Factory") ) return; + if (!(MinecraftClient.getInstance().currentScreen instanceof GenericContainerScreen screen) || !screen.getTitle().getString().equals("Chocolate Factory")) return; + + int lineIndex = lines.size(); + boolean shouldAddLine = false; String lore = concatenateLore(lines); Matcher costMatcher = COST_PATTERN.matcher(lore); OptionalLong cost = RegexUtils.getLongFromMatcher(costMatcher); - if (cost.isEmpty() || totalChocolate == -1L || totalCps == -1.0) return; + //Available on all items with a chocolate cost + if (cost.isPresent()) shouldAddLine = addUpgradeTimerToLore(lines, cost.getAsLong()); + + //Prestige item + if (stack.isOf(Items.DROPPER) && requiredUntilNextPrestige != -1L) { + shouldAddLine = addPrestigeTimerToLore(lines) || shouldAddLine; + } + //Time tower + else if (stack.isOf(Items.CLOCK)) { + shouldAddLine = addTimeTowerStatsToLore(lines) || shouldAddLine; + } + //Rabbits + else if (stack.isOf(Items.PLAYER_HEAD)) { + shouldAddLine = addRabbitStatsToLore(lines, stack) || shouldAddLine ; + } - lines.add(ItemTooltip.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, ItemTooltip.createSmoothLine()); + } - lines.add(Text.literal("") + private static boolean addUpgradeTimerToLore(List lines, long cost) { + if (totalChocolate == -1L || totalCps == -1.0) return false; + lines.add(Text.empty() .append(Text.literal("Time until upgrade: ").formatted(Formatting.GRAY)) - .append(formatTime((cost.getAsLong() - totalChocolate) / totalCps))); + .append(formatTime((cost - totalChocolate) / totalCps))); + return true; + } - if (cpsIncreaseFactors.isEmpty()) return; + private static boolean addPrestigeTimerToLore(List lines) { + if (requiredUntilNextPrestige == -1L || totalCps == -1.0) return false; + 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() + .append(Text.literal("Time until next prestige: ").formatted(Formatting.GRAY)) + .append(formatTime(requiredUntilNextPrestige / totalCps))); + return true; + } + private static boolean addTimeTowerStatsToLore(List lines) { + if (totalCps == -1.0 || totalCpsMultiplier == -1.0 || timeTowerMultiplier == -1.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 (timeTowerMultiplier < 1.5) { + 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; + } + + private static boolean addRabbitStatsToLore(List lines, ItemStack stack) { + if (cpsIncreaseFactors.isEmpty()) return false; + boolean changed = false; for (Rabbit rabbit : cpsIncreaseFactors) { if (rabbit.itemStack != stack) continue; - - lines.add(Text.literal("") + changed = true; + 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.literal("") + 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.itemStack == bestUpgrade) { - if (cost.getAsLong() <= totalChocolate) { + 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.itemStack == bestAffordableUpgrade && cost.getAsLong() <= totalChocolate) { + } else if (rabbit.itemStack == bestAffordableUpgrade && rabbit.cost <= totalChocolate) { lines.add(Text.literal("Best upgrade you can afford").formatted(Formatting.GREEN)); } } + return changed; } private static MutableText formatTime(double seconds) { @@ -218,6 +306,37 @@ public class ChocolateFactorySolver extends ContainerSolver { return Optional.of(new Rabbit(nextCps.getAsInt() - currentCps.getAsInt(), cost.getAsInt(), slot, item)); } + private static Optional getPrestigeHighlight(ItemStack item) { + List loreList = ItemUtils.getLore(item); + if (loreList.isEmpty()) return Optional.empty(); + + String lore = loreList.getLast().getString(); //The last line holds the text we're looking for + if (lore.equals("Click to prestige!")) return Optional.of(ColorHighlight.green(28)); + return Optional.of(ColorHighlight.red(28)); + } + private record Rabbit(double cpsIncrease, int cost, int slot, ItemStack itemStack) { } + + //Perhaps the part below can go to a separate file later on, but I couldn't find a proper name for the class, so they're staying here. + private static final Map romanMap = Map.of( + 'I', 1, + 'V', 5, + 'X', 10, + 'L', 50, + 'C', 100, + 'D', 500, + 'M', 1000 + ); + + public static int romanToDecimal(String romanNumeral) { + int decimal = 0; + int lastNumber = 0; + for (int i = romanNumeral.length() - 1; i >= 0; i--) { + char ch = romanNumeral.charAt(i); + decimal = romanMap.get(ch) >= lastNumber ? decimal + romanMap.get(ch) : decimal - romanMap.get(ch); + lastNumber = romanMap.get(ch); + } + return decimal; + } } -- cgit From 5de131909a2e8461c2c19329aa8e9c4d34672e4b Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Fri, 17 May 2024 06:33:14 +0300 Subject: Remove unused import --- .../java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java | 1 - 1 file changed, 1 deletion(-) (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java index 3ca68df3..bc555e6b 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java @@ -3,7 +3,6 @@ package de.hysky.skyblocker.mixins; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.injector.v2.WrapWithCondition; import com.llamalad7.mixinextras.sugar.Local; -import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.CompactDamage; import de.hysky.skyblocker.skyblock.FishingHelper; import de.hysky.skyblocker.skyblock.chocolatefactory.EggFinder; -- cgit From 8ad266d53a4a7316eabd5150fda434dfc5bf2109 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Fri, 17 May 2024 06:33:52 +0300 Subject: Add location detection to EggFinder --- .../skyblock/chocolatefactory/EggFinder.java | 41 ++++++++++++++++++---- 1 file changed, 35 insertions(+), 6 deletions(-) (limited to 'src/main/java/de/hysky') 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 2f027f81..a38a7396 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java @@ -1,10 +1,8 @@ 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.SkyblockTime; +import de.hysky.skyblocker.events.SkyblockEvents; +import de.hysky.skyblocker.utils.*; import de.hysky.skyblocker.utils.waypoint.Waypoint; import it.unimi.dsi.fastutil.objects.ObjectImmutableList; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; @@ -21,6 +19,7 @@ import org.apache.commons.lang3.mutable.MutableObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.LinkedList; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -28,16 +27,37 @@ public class EggFinder { private static final Pattern eggFoundPattern = Pattern.compile("^(?:HOPPITY'S HUNT You found a Chocolate|You have already collected this Chocolate) (Breakfast|Lunch|Dinner)"); private static final Pattern newEggPattern = Pattern.compile("^HOPPITY'S HUNT A Chocolate (Breakfast|Lunch|Dinner) Egg has appeared!$"); private static final Logger logger = LoggerFactory.getLogger("Skyblocker Egg Finder"); + private static final LinkedList armorStandQueue = new LinkedList<>(); + private static final Location[] possibleLocations = {Location.CRIMSON_ISLE, Location.CRYSTAL_HOLLOWS, Location.DUNGEON_HUB, Location.DWARVEN_MINES, Location.HUB, Location.THE_END, Location.THE_PARK, Location.GOLD_MINE}; + private static boolean isLocationCorrect = false; private EggFinder() { } public static void init() { - ClientPlayConnectionEvents.JOIN.register((ignored, ignored2, ignored3) -> clearEggs()); + ClientPlayConnectionEvents.JOIN.register((ignored, ignored2, ignored3) -> invalidateState()); + SkyblockEvents.LOCATION_CHANGE.register(EggFinder::handleLocationChange); ClientReceiveMessageEvents.GAME.register(EggFinder::onChatMessage); WorldRenderEvents.AFTER_TRANSLUCENT.register(EggFinder::renderWaypoints); } + private static void handleLocationChange(Location location) { + for (Location possibleLocation : possibleLocations) { + if (location == possibleLocation) { + isLocationCorrect = true; + break; + } + } + if (!isLocationCorrect) { + armorStandQueue.clear(); + return; + } + + while (!armorStandQueue.isEmpty()) { + handleArmorStand(armorStandQueue.poll()); + } + } + public static void checkIfEgg(Entity entity) { if (entity instanceof ArmorStandEntity armorStand) checkIfEgg(armorStand); } @@ -46,6 +66,14 @@ public class EggFinder { if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableEggFinder) return; if (SkyblockTime.skyblockSeason.get() != SkyblockTime.Season.SPRING) return; if (armorStand.hasCustomName() || !armorStand.isInvisible() || !armorStand.shouldHideBasePlate()) return; + if (Utils.getLocation() == Location.UNKNOWN) { //The location is unknown upon world change and will be changed via /locraw soon, so we can queue it for now + armorStandQueue.add(armorStand); + return; + } + if (isLocationCorrect) handleArmorStand(armorStand); + } + + private static void handleArmorStand(ArmorStandEntity armorStand) { for (ItemStack itemStack : armorStand.getArmorItems()) { ItemUtils.getHeadTextureOptional(itemStack).ifPresent(texture -> { for (EggType type : EggType.entries) { @@ -58,8 +86,9 @@ public class EggFinder { } } - private static void clearEggs() { + private static void invalidateState() { if (!SkyblockerConfigManager.get().helpers.chocolateFactory.enableEggFinder) return; + isLocationCorrect = false; for (EggType type : EggType.entries) { type.egg.setValue(null); } -- cgit From 8866c7af5555298a29bbc26675289529b15b7cee Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Sun, 19 May 2024 09:10:03 +0300 Subject: Change String == null check into String#isBlank --- src/main/java/de/hysky/skyblocker/utils/ItemUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java index 6f98efa6..ba41a1df 100644 --- a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java @@ -217,7 +217,7 @@ public class ItemUtils { public static Optional getHeadTextureOptional(ItemStack stack) { String texture = getHeadTexture(stack); - if (texture == null) return Optional.empty(); + if (texture.isBlank()) return Optional.empty(); return Optional.of(texture); } -- cgit From 475be1aa49068ce46e46c112842f72f28e5e680b Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Sun, 19 May 2024 09:21:34 +0300 Subject: Narrow the scope of the line smoother in ItemTooltip Not necessarily related to the chocolate factory, but it was also added by me so should be fine --- .../de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java index 6e269790..70586d89 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java @@ -394,10 +394,14 @@ public class ItemTooltip { return message; } + //This is static to not create a new text object for each line in every item + private static final Text bumpyLine = Text.literal("-----------------").formatted(Formatting.DARK_GRAY, Formatting.STRIKETHROUGH); + private static void smoothenLines(List lines) { for (int i = 0; i < lines.size(); i++) { - Text line = lines.get(i); - if (line.getString().equals("-----------------")) { + List lineSiblings = lines.get(i).getSiblings(); + //Compare the first sibling rather than the whole object as the style of the root object can change while visually staying the same + if (lineSiblings.size() == 1 && lineSiblings.getFirst().equals(bumpyLine)) { lines.set(i, createSmoothLine()); } } -- cgit From 63833288d637e67902ac07c90f43c89825d6811e Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Sun, 19 May 2024 09:22:47 +0300 Subject: Fix crash caused by Time Tower lore being empty in rare cases --- .../skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/main/java/de/hysky') 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 a6ec144e..b3c4e85a 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -121,7 +121,10 @@ public class ChocolateFactorySolver extends ContainerSolver { //Time Tower is in slot 39 timeTowerMultiplier = romanToDecimal(StringUtils.substringAfterLast(slots.get(39).getName().getString(), ' ')) / 10.0; //The name holds the level, which is multiplier * 10 in roman numerals - isTimeTowerActive = ItemUtils.getLore(slots.get(39)).getLast().getString().equals("The Time Tower is active!"); + List timeTowerLore = ItemUtils.getLore(slots.get(39)); + if (!timeTowerLore.isEmpty()) { + isTimeTowerActive = timeTowerLore.getLast().getString().equals("The Time Tower is active!"); + } //Compare cost/cpsIncrease rather than cpsIncrease/cost to avoid getting close to 0 and losing precision. cpsIncreaseFactors.sort(Comparator.comparingDouble(rabbit -> rabbit.cost() / rabbit.cpsIncrease())); //Ascending order, lower = better -- cgit From 25080e6f171946e22ba1292decfb7b3823c2a6fd Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Sun, 19 May 2024 09:23:29 +0300 Subject: Code cleanup --- .../skyblock/chocolatefactory/ChocolateFactorySolver.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/main/java/de/hysky') 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 b3c4e85a..2b403330 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -135,6 +135,8 @@ public class ChocolateFactorySolver extends ContainerSolver { if (!(MinecraftClient.getInstance().currentScreen instanceof GenericContainerScreen screen) || !screen.getTitle().getString().equals("Chocolate Factory")) 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; String lore = concatenateLore(lines); @@ -161,7 +163,7 @@ public class ChocolateFactorySolver extends ContainerSolver { } private static boolean addUpgradeTimerToLore(List lines, long cost) { - if (totalChocolate == -1L || totalCps == -1.0) return false; + 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))); @@ -180,7 +182,7 @@ public class ChocolateFactorySolver extends ContainerSolver { } private static boolean addTimeTowerStatsToLore(List lines) { - if (totalCps == -1.0 || totalCpsMultiplier == -1.0 || timeTowerMultiplier == -1.0) return false; + 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)) -- cgit From 7a6fc4c624946719de43feed4d86b4a43a30e6cc Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Sun, 19 May 2024 09:32:57 +0300 Subject: Fix time tower reminder being sent outside skyblock --- .../hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java index f1458b59..eb5f60cf 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java @@ -4,6 +4,7 @@ import com.mojang.brigadier.Message; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.events.SkyblockEvents; import de.hysky.skyblocker.utils.Constants; +import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.scheduler.Scheduler; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; import net.minecraft.client.MinecraftClient; @@ -54,7 +55,7 @@ public class TimeTowerReminder { } private static void sendMessage() { - if (MinecraftClient.getInstance().player == null) return; + if (MinecraftClient.getInstance().player == null || !Utils.isOnSkyblock()) return; MinecraftClient.getInstance().player.sendMessage(Constants.PREFIX.get().append(Text.literal("Your Chocolate Factory's Time Tower has deactivated!").formatted(Formatting.RED))); File tempFile = SkyblockerMod.CONFIG_DIR.resolve(TIME_TOWER_FILE).toFile(); -- cgit From eb256675c76ffd8ba6c69d9c3fed92fb9a87cd93 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Sun, 19 May 2024 09:33:11 +0300 Subject: Fix time tower reminder being sent multiple times --- .../skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java index eb5f60cf..72cbeb2a 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/TimeTowerReminder.java @@ -24,6 +24,7 @@ public class TimeTowerReminder { private static final String TIME_TOWER_FILE = "time_tower.txt"; private static final Pattern TIME_TOWER_PATTERN = Pattern.compile("^TIME TOWER! Your Chocolate Factory production has increased by \\+[\\d.]+x for \\dh!$"); private static final Logger LOGGER = LoggerFactory.getLogger("Skyblocker Time Tower Reminder"); + private static boolean scheduled = false; private TimeTowerReminder() { } @@ -34,9 +35,9 @@ public class TimeTowerReminder { } public static void checkIfTimeTower(Message message, boolean overlay) { - if (!TIME_TOWER_PATTERN.matcher(message.getString()).matches()) return; + if (!TIME_TOWER_PATTERN.matcher(message.getString()).matches() || scheduled) return; Scheduler.INSTANCE.schedule(TimeTowerReminder::sendMessage, 60 * 60 * 20); // 1 hour - + scheduled = true; File tempFile = SkyblockerMod.CONFIG_DIR.resolve(TIME_TOWER_FILE).toFile(); if (!tempFile.exists()) { try { @@ -60,6 +61,7 @@ public class TimeTowerReminder { File tempFile = SkyblockerMod.CONFIG_DIR.resolve(TIME_TOWER_FILE).toFile(); try { + scheduled = false; if (tempFile.exists()) Files.delete(tempFile.toPath()); } catch (Exception e) { LOGGER.error("[Skyblocker Time Tower Reminder] Failed to delete temp file for Time Tower Reminder!", e); @@ -68,7 +70,7 @@ public class TimeTowerReminder { private static void checkTempFile() { File tempFile = SkyblockerMod.CONFIG_DIR.resolve(TIME_TOWER_FILE).toFile(); - if (!tempFile.exists()) return; + if (!tempFile.exists() || scheduled) return; long time; try (Stream file = Files.lines(tempFile.toPath())) { -- cgit From b43cf96525534465dc94584f04dffd8ef38814d3 Mon Sep 17 00:00:00 2001 From: Kevin <92656833+kevinthegreat1@users.noreply.github.com> Date: Mon, 20 May 2024 15:42:43 -0400 Subject: Revert backwards compatible changes in ItemUtils.getHeadTexture to avoid merge conflicts --- src/main/java/de/hysky/skyblocker/utils/ItemUtils.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java index ba41a1df..13b28808 100644 --- a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java @@ -206,13 +206,13 @@ public class ItemUtils { public static String getHeadTexture(ItemStack stack) { if (!stack.isOf(Items.PLAYER_HEAD) || !stack.contains(DataComponentTypes.PROFILE)) return ""; - Iterator iterator = stack.get(DataComponentTypes.PROFILE) - .properties() - .get("textures") - .iterator(); + ProfileComponent profile = stack.get(DataComponentTypes.PROFILE); + String texture = profile.properties().get("textures").stream() + .map(Property::value) + .findFirst() + .orElse(""); - if (!iterator.hasNext()) return ""; - return iterator.next().value(); + return texture; } public static Optional getHeadTextureOptional(ItemStack stack) { -- cgit From c28c60bcc2b0aa308d8550161f2fcd27ee270201 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 21 May 2024 14:29:45 +0300 Subject: Fix time tower calculations being wrong due to incorrect string matching --- .../skyblock/chocolatefactory/ChocolateFactorySolver.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/main/java/de/hysky') 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 2b403330..b06b65f7 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -36,6 +36,7 @@ public class ChocolateFactorySolver extends ContainerSolver { private static final Pattern MULTIPLIER_INCREASE_PATTERN = Pattern.compile("\\+([\\d.]+)x Chocolate per second"); private static final Pattern CHOCOLATE_PATTERN = Pattern.compile("^([\\d,]+) Chocolate$"); private static final Pattern PRESTIGE_REQUIREMENT_PATTERN = Pattern.compile("Chocolate this Prestige: ([\\d,]+) +Requires (\\S+) Chocolate this Prestige!"); + private static final Pattern TIME_TOWER_STATUS_PATTERN = Pattern.compile("Status: (ACTIVE|INACTIVE)"); private static final ObjectArrayList cpsIncreaseFactors = new ObjectArrayList<>(6); private static long totalChocolate = -1L; private static double totalCps = -1.0; @@ -121,9 +122,9 @@ public class ChocolateFactorySolver extends ContainerSolver { //Time Tower is in slot 39 timeTowerMultiplier = romanToDecimal(StringUtils.substringAfterLast(slots.get(39).getName().getString(), ' ')) / 10.0; //The name holds the level, which is multiplier * 10 in roman numerals - List timeTowerLore = ItemUtils.getLore(slots.get(39)); - if (!timeTowerLore.isEmpty()) { - isTimeTowerActive = timeTowerLore.getLast().getString().equals("The Time Tower is active!"); + Matcher timeTowerStatusMatcher = TIME_TOWER_STATUS_PATTERN.matcher(getConcatenatedLore(slots.get(39))); + if (timeTowerStatusMatcher.find()) { + isTimeTowerActive = timeTowerStatusMatcher.group(1).equals("ACTIVE"); } //Compare cost/cpsIncrease rather than cpsIncrease/cost to avoid getting close to 0 and losing precision. -- cgit From 92865430f6b9c7e1646b199a5ae1d7c3482956b5 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Tue, 21 May 2024 14:30:04 +0300 Subject: Renamed variable --- .../skyblock/chocolatefactory/ChocolateFactorySolver.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/main/java/de/hysky') 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 b06b65f7..306d09ee 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -109,10 +109,10 @@ public class ChocolateFactorySolver extends ContainerSolver { RegexUtils.getDoubleFromMatcher(multiplierMatcher, cpsMatcher.hasMatch() ? cpsMatcher.end() : 0).ifPresent(d -> totalCpsMultiplier = d); //Prestige item is in slot 28 - Matcher matcher = PRESTIGE_REQUIREMENT_PATTERN.matcher(getConcatenatedLore(slots.get(28))); - OptionalLong currentChocolate = RegexUtils.getLongFromMatcher(matcher); + Matcher prestigeMatcher = PRESTIGE_REQUIREMENT_PATTERN.matcher(getConcatenatedLore(slots.get(28))); + OptionalLong currentChocolate = RegexUtils.getLongFromMatcher(prestigeMatcher); if (currentChocolate.isPresent()) { - String requirement = matcher.group(2); //If the first one matched, we can assume the 2nd one is also matched since it's one whole regex + String requirement = prestigeMatcher.group(2); //If the first one matched, we can assume the 2nd one is also matched since it's one whole regex //Since the last character is either M or B we can just try to replace both characters. Only the correct one will actually replace anything. String amountString = requirement.replace("M", "000000").replace("B", "000000000"); if (NumberUtils.isParsable(amountString)) { -- cgit From 2bbeccd147b715f1eb766d2c34f9326986160557 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Thu, 23 May 2024 02:01:32 -0400 Subject: Clean up small formatting --- .../java/de/hysky/skyblocker/SkyblockerMod.java | 3 +- .../config/categories/HelperCategory.java | 5 +- .../mixins/ClientPlayNetworkHandlerMixin.java | 180 ++++++++++----------- .../chocolatefactory/ChocolateFactorySolver.java | 5 +- .../skyblock/item/tooltip/ItemTooltip.java | 5 +- .../de/hysky/skyblocker/utils/SkyblockTime.java | 6 +- 6 files changed, 99 insertions(+), 105 deletions(-) (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index 79f241b8..a57b4177 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -2,10 +2,9 @@ package de.hysky.skyblocker; import com.google.gson.Gson; import com.google.gson.GsonBuilder; - -import de.hysky.skyblocker.config.datafixer.ConfigDataFixer; import de.hysky.skyblocker.config.ImageRepoLoader; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.config.datafixer.ConfigDataFixer; import de.hysky.skyblocker.debug.Debug; import de.hysky.skyblocker.skyblock.*; import de.hysky.skyblocker.skyblock.calculators.CalculatorCommand; diff --git a/src/main/java/de/hysky/skyblocker/config/categories/HelperCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/HelperCategory.java index 79bd0d65..9e4935cb 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/HelperCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/HelperCategory.java @@ -3,13 +3,11 @@ package de.hysky.skyblocker.config.categories; import de.hysky.skyblocker.config.ConfigUtils; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.utils.waypoint.Waypoint; -import dev.isxander.yacl3.api.*; import dev.isxander.yacl3.api.ConfigCategory; import dev.isxander.yacl3.api.Option; import dev.isxander.yacl3.api.OptionDescription; +import dev.isxander.yacl3.api.OptionGroup; import dev.isxander.yacl3.api.controller.FloatFieldControllerBuilder; -import dev.isxander.yacl3.api.controller.TickBoxControllerBuilder; -import dev.isxander.yacl3.config.v2.api.autogen.TickBox; import net.minecraft.text.Text; public class HelperCategory { @@ -184,7 +182,6 @@ public class HelperCategory { newValue -> config.helpers.chocolateFactory.enableTimeTowerReminder = newValue) .controller(ConfigUtils::createBooleanController) .build()) - .build()) .build(); diff --git a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java index bc555e6b..48389d40 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java @@ -34,95 +34,95 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(ClientPlayNetworkHandler.class) public abstract class ClientPlayNetworkHandlerMixin { - @Shadow - private ClientWorld world; - - @Shadow - @Final - private static Logger LOGGER; - - @Inject(method = "onBlockUpdate", at = @At("RETURN")) - private void skyblocker$onBlockUpdate(BlockUpdateS2CPacket packet, CallbackInfo ci) { - if (Utils.isInTheEnd() && SlayerUtils.isInSlayer()) { - BeaconHighlighter.beaconPositions.remove(packet.getPos()); - if (packet.getState().isOf(Blocks.BEACON)) { - BeaconHighlighter.beaconPositions.add(packet.getPos()); - } - } - } - - @Inject(method = "method_37472", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientWorld;removeEntity(ILnet/minecraft/entity/Entity$RemovalReason;)V")) - private void skyblocker$onItemDestroy(int entityId, CallbackInfo ci) { - if (world.getEntityById(entityId) instanceof ItemEntity itemEntity) { - DungeonManager.onItemPickup(itemEntity); - } - } - - @ModifyVariable(method = "onItemPickupAnimation", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientWorld;removeEntity(ILnet/minecraft/entity/Entity$RemovalReason;)V", ordinal = 0)) - private ItemEntity skyblocker$onItemPickup(ItemEntity itemEntity) { - DungeonManager.onItemPickup(itemEntity); - return itemEntity; - } - - @WrapWithCondition(method = "onEntityPassengersSet", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;)V", remap = false)) - private boolean skyblocker$cancelEntityPassengersWarning(Logger instance, String msg) { - return !Utils.isOnHypixel(); - } - - @WrapWithCondition(method = "onPlayerList", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V", remap = false)) - private boolean skyblocker$cancelPlayerListWarning(Logger instance, String format, Object arg1, Object arg2) { - return !Utils.isOnHypixel(); - } - - @Inject(method = "onPlaySound", at = @At("RETURN")) - private void skyblocker$onPlaySound(PlaySoundS2CPacket packet, CallbackInfo ci) { - FishingHelper.onSound(packet); - } - - @WrapWithCondition(method = "warnOnUnknownPayload", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V", remap = false)) - private boolean skyblocker$dropBadlionPacketWarnings(Logger instance, String message, Object identifier) { - return !(Utils.isOnHypixel() && ((Identifier) identifier).getNamespace().equals("badlion")); - } - - @WrapWithCondition(method = {"onScoreboardScoreUpdate", "onScoreboardScoreReset"}, at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V", remap = false)) - private boolean skyblocker$cancelUnknownScoreboardObjectiveWarnings(Logger instance, String message, Object objectiveName) { - return !Utils.isOnHypixel(); - } - - @WrapWithCondition(method = "onTeam", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;[Ljava/lang/Object;)V", remap = false)) - private boolean skyblocker$cancelTeamWarning(Logger instance, String format, Object... arg) { - return !Utils.isOnHypixel(); - } - - @Inject(method = "onParticle", at = @At("RETURN")) - private void skyblocker$onParticle(ParticleS2CPacket packet, CallbackInfo ci) { - MythologicalRitual.onParticle(packet); - EnderNodes.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;")) - private Entity skyblocker$onEntityDeath(Entity entity, @Local(argsOnly = true) EntityStatusS2CPacket packet) { - if (packet.getStatus() == EntityStatuses.PLAY_DEATH_SOUND_OR_ADD_PROJECTILE_HIT_PARTICLES) { - DungeonScore.handleEntityDeath(entity); - TheEnd.onEntityDeath(entity); - } - return entity; - } - - @Inject(method = "onEntityTrackerUpdate", at = @At("TAIL")) - private void skyblocker$onEntityTrackerUpdate(EntityTrackerUpdateS2CPacket packet, CallbackInfo ci, @Local Entity entity) { - if (!(entity instanceof ArmorStandEntity armorStandEntity)) return; - - EggFinder.checkIfEgg(armorStandEntity); - try { //Prevent packet handling fails if something goes wrong so that entity trackers still update, just without compact damage numbers + @Shadow + private ClientWorld world; + + @Shadow + @Final + private static Logger LOGGER; + + @Inject(method = "onBlockUpdate", at = @At("RETURN")) + private void skyblocker$onBlockUpdate(BlockUpdateS2CPacket packet, CallbackInfo ci) { + if (Utils.isInTheEnd() && SlayerUtils.isInSlayer()) { + BeaconHighlighter.beaconPositions.remove(packet.getPos()); + if (packet.getState().isOf(Blocks.BEACON)) { + BeaconHighlighter.beaconPositions.add(packet.getPos()); + } + } + } + + @Inject(method = "method_37472", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientWorld;removeEntity(ILnet/minecraft/entity/Entity$RemovalReason;)V")) + private void skyblocker$onItemDestroy(int entityId, CallbackInfo ci) { + if (world.getEntityById(entityId) instanceof ItemEntity itemEntity) { + DungeonManager.onItemPickup(itemEntity); + } + } + + @ModifyVariable(method = "onItemPickupAnimation", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientWorld;removeEntity(ILnet/minecraft/entity/Entity$RemovalReason;)V", ordinal = 0)) + private ItemEntity skyblocker$onItemPickup(ItemEntity itemEntity) { + DungeonManager.onItemPickup(itemEntity); + return itemEntity; + } + + @WrapWithCondition(method = "onEntityPassengersSet", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;)V", remap = false)) + private boolean skyblocker$cancelEntityPassengersWarning(Logger instance, String msg) { + return !Utils.isOnHypixel(); + } + + @WrapWithCondition(method = "onPlayerList", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V", remap = false)) + private boolean skyblocker$cancelPlayerListWarning(Logger instance, String format, Object arg1, Object arg2) { + return !Utils.isOnHypixel(); + } + + @Inject(method = "onPlaySound", at = @At("RETURN")) + private void skyblocker$onPlaySound(PlaySoundS2CPacket packet, CallbackInfo ci) { + FishingHelper.onSound(packet); + } + + @WrapWithCondition(method = "warnOnUnknownPayload", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V", remap = false)) + private boolean skyblocker$dropBadlionPacketWarnings(Logger instance, String message, Object identifier) { + return !(Utils.isOnHypixel() && ((Identifier) identifier).getNamespace().equals("badlion")); + } + + @WrapWithCondition(method = {"onScoreboardScoreUpdate", "onScoreboardScoreReset"}, at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V", remap = false)) + private boolean skyblocker$cancelUnknownScoreboardObjectiveWarnings(Logger instance, String message, Object objectiveName) { + return !Utils.isOnHypixel(); + } + + @WrapWithCondition(method = "onTeam", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;[Ljava/lang/Object;)V", remap = false)) + private boolean skyblocker$cancelTeamWarning(Logger instance, String format, Object... arg) { + return !Utils.isOnHypixel(); + } + + @Inject(method = "onParticle", at = @At("RETURN")) + private void skyblocker$onParticle(ParticleS2CPacket packet, CallbackInfo ci) { + MythologicalRitual.onParticle(packet); + EnderNodes.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;")) + private Entity skyblocker$onEntityDeath(Entity entity, @Local(argsOnly = true) EntityStatusS2CPacket packet) { + if (packet.getStatus() == EntityStatuses.PLAY_DEATH_SOUND_OR_ADD_PROJECTILE_HIT_PARTICLES) { + DungeonScore.handleEntityDeath(entity); + TheEnd.onEntityDeath(entity); + } + return entity; + } + + @Inject(method = "onEntityTrackerUpdate", at = @At("TAIL")) + private void skyblocker$onEntityTrackerUpdate(EntityTrackerUpdateS2CPacket packet, CallbackInfo ci, @Local Entity entity) { + if (!(entity instanceof ArmorStandEntity armorStandEntity)) return; + + EggFinder.checkIfEgg(armorStandEntity); + try { //Prevent packet handling fails if something goes wrong so that entity trackers still update, just without compact damage numbers CompactDamage.compactDamage(armorStandEntity); - } catch (Exception e) { - LOGGER.error("[Skyblocker Compact Damage] Failed to compact damage number", e); - } - } - - @Inject(method = "onEntityEquipmentUpdate", at = @At(value = "TAIL")) - private void skyblocker$onEntityEquip(EntityEquipmentUpdateS2CPacket packet, CallbackInfo ci, @Local Entity entity) { - EggFinder.checkIfEgg(entity); - } + } catch (Exception e) { + LOGGER.error("[Skyblocker Compact Damage] Failed to compact damage number", e); + } + } + + @Inject(method = "onEntityEquipmentUpdate", at = @At(value = "TAIL")) + private void skyblocker$onEntityEquip(EntityEquipmentUpdateS2CPacket packet, CallbackInfo ci, @Local Entity entity) { + EggFinder.checkIfEgg(entity); + } } 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 306d09ee..33bf7b11 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -6,7 +6,7 @@ import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.RegexUtils; import de.hysky.skyblocker.utils.render.gui.ColorHighlight; import de.hysky.skyblocker.utils.render.gui.ContainerSolver; -import it.unimi.dsi.fastutil.ints.*; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback; import net.minecraft.client.MinecraftClient; @@ -24,7 +24,6 @@ import org.apache.commons.lang3.math.NumberUtils; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.*; -import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -156,7 +155,7 @@ public class ChocolateFactorySolver extends ContainerSolver { } //Rabbits else if (stack.isOf(Items.PLAYER_HEAD)) { - shouldAddLine = addRabbitStatsToLore(lines, stack) || shouldAddLine ; + shouldAddLine = addRabbitStatsToLore(lines, stack) || shouldAddLine; } //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 diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java index 70586d89..8c083e25 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java @@ -2,7 +2,6 @@ package de.hysky.skyblocker.skyblock.item.tooltip; import com.google.gson.JsonObject; import de.hysky.skyblocker.SkyblockerMod; -import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.config.configs.GeneralConfig; import de.hysky.skyblocker.skyblock.item.MuseumItemCache; @@ -395,13 +394,13 @@ public class ItemTooltip { } //This is static to not create a new text object for each line in every item - private static final Text bumpyLine = Text.literal("-----------------").formatted(Formatting.DARK_GRAY, Formatting.STRIKETHROUGH); + private static final Text BUMPY_LINE = Text.literal("-----------------").formatted(Formatting.DARK_GRAY, Formatting.STRIKETHROUGH); private static void smoothenLines(List lines) { for (int i = 0; i < lines.size(); i++) { List lineSiblings = lines.get(i).getSiblings(); //Compare the first sibling rather than the whole object as the style of the root object can change while visually staying the same - if (lineSiblings.size() == 1 && lineSiblings.getFirst().equals(bumpyLine)) { + if (lineSiblings.size() == 1 && lineSiblings.getFirst().equals(BUMPY_LINE)) { lines.set(i, createSmoothLine()); } } diff --git a/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java b/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java index 36db4ef3..5a6074e1 100644 --- a/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java +++ b/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java @@ -45,17 +45,17 @@ public class SkyblockTime { skyblockSeason.set(Season.values()[getSkyblockMonth() / 3]); skyblockMonth.set(Month.values()[getSkyblockMonth()]); skyblockDay.set(getSkyblockDay()); - LOGGER.info("[Skyblocker Time] Skyblock time updated to Year {}, Season {}, Month {}, Day {}",skyblockYear.get(), skyblockSeason.get(), skyblockMonth.get(), skyblockDay.get()); + LOGGER.info("[Skyblocker Time] Skyblock time updated to Year {}, Season {}, Month {}, Day {}", skyblockYear.get(), skyblockSeason.get(), skyblockMonth.get(), skyblockDay.get()); } public enum Season { - SPRING, SUMMER, FALL, WINTER; + SPRING, SUMMER, FALL, WINTER } public enum Month { EARLY_SPRING, SPRING, LATE_SPRING, EARLY_SUMMER, SUMMER, LATE_SUMMER, EARLY_FALL, FALL, LATE_FALL, - EARLY_WINTER, WINTER, LATE_WINTER; + EARLY_WINTER, WINTER, LATE_WINTER } } -- cgit From 76019594b31c053f03ad76465de8d371d33f0c15 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Thu, 23 May 2024 13:26:05 +0300 Subject: Fix egg found message being sent twice in rare cases --- .../java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/de/hysky') 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 a38a7396..c4fd7d4d 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/EggFinder.java @@ -76,8 +76,8 @@ public class EggFinder { private static void handleArmorStand(ArmorStandEntity armorStand) { for (ItemStack itemStack : armorStand.getArmorItems()) { ItemUtils.getHeadTextureOptional(itemStack).ifPresent(texture -> { - for (EggType type : EggType.entries) { - if (texture.equals(type.texture) && type.egg.getValue() == null) { + for (EggType type : EggType.entries) { //Compare blockPos rather than entity to avoid incorrect matches when the entity just moves rather than a new one being spawned elsewhere + if (texture.equals(type.texture) && (type.egg.getValue() == null || !type.egg.getValue().entity.getBlockPos().equals(armorStand.getBlockPos()))) { handleFoundEgg(armorStand, type); return; } -- cgit From 3c578b31af7eecc541619473c8c8c3eacb554a23 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Thu, 23 May 2024 14:44:25 +0300 Subject: Fix 1 second gap in formatTime --- .../skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src/main/java/de/hysky') 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 33bf7b11..2d530b6d 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/chocolatefactory/ChocolateFactorySolver.java @@ -230,6 +230,7 @@ public class ChocolateFactorySolver extends ContainerSolver { } private static MutableText formatTime(double seconds) { + seconds = Math.ceil(seconds); if (seconds <= 0) return Text.literal("Now").formatted(Formatting.GREEN); StringBuilder builder = new StringBuilder(); -- cgit From 1f6798df58af5eec4dfe954ab413c5a92d0fee63 Mon Sep 17 00:00:00 2001 From: Kevin <92656833+kevinthegreat1@users.noreply.github.com> Date: Thu, 23 May 2024 22:12:26 -0400 Subject: Change poch to epoch --- src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/de/hysky') diff --git a/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java b/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java index 5a6074e1..045ecc4e 100644 --- a/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java +++ b/src/main/java/de/hysky/skyblocker/utils/SkyblockTime.java @@ -8,7 +8,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; public class SkyblockTime { - private static final long SKYBLOCK_POCH = 1560275700000L; + private static final long SKYBLOCK_EPOCH = 1560275700000L; public static final AtomicInteger skyblockYear = new AtomicInteger(0); public static final AtomicReference skyblockSeason = new AtomicReference<>(Season.SPRING); public static final AtomicReference skyblockMonth = new AtomicReference<>(Month.EARLY_SPRING); @@ -25,7 +25,7 @@ public class SkyblockTime { } private static long getSkyblockMillis() { - return System.currentTimeMillis() - SKYBLOCK_POCH; + return System.currentTimeMillis() - SKYBLOCK_EPOCH; } private static int getSkyblockYear() { -- cgit