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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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 8f060cf5e46d54d25841a7b5eef09eaef5d31861 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Wed, 15 May 2024 05:28:10 +0300 Subject: Add the meaning of highlight colors to the config description --- src/main/resources/assets/skyblocker/lang/en_us.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main') diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 6b309d39..99ccdba0 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -275,7 +275,7 @@ "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.enableChocolateFactoryHelper.@Tooltip": "Highlights the best upgrade when enabled. \n\nThe best upgrade is marked as green, but if you can't afford it, it's marked as yellow while marking the next best upgrade that you can afford as green.", "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", -- 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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') 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 0c4284c92fa4e4b3ca637f9b22f38195d7b44500 Mon Sep 17 00:00:00 2001 From: Rime <81419447+Emirlol@users.noreply.github.com> Date: Sun, 19 May 2024 09:36:30 +0300 Subject: Sort chocolate factory translation keys --- src/main/resources/assets/skyblocker/lang/en_us.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main') diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 99ccdba0..c73f49e0 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -278,12 +278,12 @@ "skyblocker.config.helpers.chocolateFactory.enableChocolateFactoryHelper.@Tooltip": "Highlights the best upgrade when enabled. \n\nThe best upgrade is marked as green, but if you can't afford it, it's marked as yellow while marking the next best upgrade that you can afford as green.", "skyblocker.config.helpers.chocolateFactory.enableEggFinder": "Enable Egg Finder", "skyblocker.config.helpers.chocolateFactory.enableEggFinder.@Tooltip": "Highlights eggs from Hoppity's Hunt.", + "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.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.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 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') 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') 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') 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') 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') 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') 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') 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