diff options
author | Kevin <92656833+kevinthegreat1@users.noreply.github.com> | 2024-03-18 00:41:11 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-18 00:41:11 -0400 |
commit | 02a7ecc471c3a24a0ef4c9a58b70ebf2510ed55f (patch) | |
tree | db7ec1bc6e5142cd1853c49e3f08148544d16b8e /src/main/java/de/hysky/skyblocker/skyblock/garden | |
parent | 40fc0550c7441ed6966d8a0222b60485180f93e0 (diff) | |
parent | 5cf396aa564ba3b93762f914cc2334d48596ab2e (diff) | |
download | Skyblocker-02a7ecc471c3a24a0ef4c9a58b70ebf2510ed55f.tar.gz Skyblocker-02a7ecc471c3a24a0ef4c9a58b70ebf2510ed55f.tar.bz2 Skyblocker-02a7ecc471c3a24a0ef4c9a58b70ebf2510ed55f.zip |
Merge pull request #589 from kevinthegreat1/farming-hud
Farming HUD & HUD Refactor
Diffstat (limited to 'src/main/java/de/hysky/skyblocker/skyblock/garden')
4 files changed, 222 insertions, 1 deletions
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHud.java b/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHud.java new file mode 100644 index 00000000..95c72241 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHud.java @@ -0,0 +1,123 @@ +package de.hysky.skyblocker.skyblock.garden; + +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.ItemUtils; +import de.hysky.skyblocker.utils.Location; +import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.scheduler.Scheduler; +import it.unimi.dsi.fastutil.floats.FloatLongPair; +import it.unimi.dsi.fastutil.ints.IntLongPair; +import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue; +import it.unimi.dsi.fastutil.longs.LongPriorityQueue; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; +import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; +import net.fabricmc.fabric.api.event.client.player.ClientPlayerBlockBreakEvents; +import net.minecraft.client.MinecraftClient; +import net.minecraft.item.ItemStack; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Locale; +import java.util.Queue; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; + +public class FarmingHud { + private static final Logger LOGGER = LoggerFactory.getLogger(FarmingHud.class); + public static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance(Locale.US); + private static final Pattern COUNTER = Pattern.compile("Counter: (?<count>[\\d,]+) .+"); + private static final Pattern FARMING_XP = Pattern.compile("ยง3\\+(?<xp>\\d+.?\\d*) Farming \\((?<percent>\\d+.?\\d*)%\\)"); + private static final Deque<IntLongPair> counter = new ArrayDeque<>(); + private static final LongPriorityQueue blockBreaks = new LongArrayFIFOQueue(); + private static final Queue<FloatLongPair> farmingXp = new ArrayDeque<>(); + private static float farmingXpPercentProgress; + + public static void init() { + HudRenderCallback.EVENT.register((context, tickDelta) -> { + if (shouldRender()) { + if (!counter.isEmpty() && counter.peek().rightLong() + 10_000 < System.currentTimeMillis()) { + counter.poll(); + } + if (!blockBreaks.isEmpty() && blockBreaks.firstLong() + 1000 < System.currentTimeMillis()) { + blockBreaks.dequeueLong(); + } + if (!farmingXp.isEmpty() && farmingXp.peek().rightLong() + 1000 < System.currentTimeMillis()) { + farmingXp.poll(); + } + + ItemStack stack = MinecraftClient.getInstance().player.getMainHandStack(); + Matcher matcher = ItemUtils.getNbtTooltip(stack, FarmingHud.COUNTER); + if (matcher != null) { + try { + int count = NUMBER_FORMAT.parse(matcher.group("count")).intValue(); + if (counter.isEmpty() || counter.peekLast().leftInt() != count) { + counter.offer(IntLongPair.of(count, System.currentTimeMillis())); + } + } catch (ParseException e) { + LOGGER.error("[Skyblocker Farming HUD] Failed to parse counter", e); + } + } + + FarmingHudWidget.INSTANCE.update(); + FarmingHudWidget.INSTANCE.render(context, SkyblockerConfigManager.get().general.tabHud.enableHudBackground); + } + }); + ClientPlayerBlockBreakEvents.AFTER.register((world, player, pos, state) -> { + if (shouldRender()) { + blockBreaks.enqueue(System.currentTimeMillis()); + } + }); + ClientReceiveMessageEvents.GAME.register((message, overlay) -> { + if (shouldRender() && overlay) { + Matcher matcher = FARMING_XP.matcher(message.getString()); + if (matcher.matches()) { + try { + farmingXp.offer(FloatLongPair.of(NUMBER_FORMAT.parse(matcher.group("xp")).floatValue(), System.currentTimeMillis())); + farmingXpPercentProgress = NUMBER_FORMAT.parse(matcher.group("percent")).floatValue(); + } catch (ParseException e) { + LOGGER.error("[Skyblocker Farming HUD] Failed to parse farming xp", e); + } + } + } + }); + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE).then(literal("hud").then(literal("farming") + .executes(Scheduler.queueOpenScreenCommand(() -> new FarmingHudConfigScreen(null))))))); + } + + private static boolean shouldRender() { + return SkyblockerConfigManager.get().locations.garden.farmingHud.enableHud && Utils.getLocation() == Location.GARDEN; + } + + public static int counter() { + return counter.isEmpty() ? 0 : counter.peekLast().leftInt(); + } + + public static float cropsPerMinute() { + if (counter.isEmpty()) { + return 0; + } + IntLongPair first = counter.peek(); + IntLongPair last = counter.peekLast(); + return (float) (last.leftInt() - first.leftInt()) / (last.rightLong() - first.rightLong()) * 60_000f; + } + + public static int blockBreaks() { + return blockBreaks.size(); + } + + public static float farmingXpPercentProgress() { + return farmingXpPercentProgress; + } + + public static double farmingXpPerHour() { + return farmingXp.stream().mapToDouble(FloatLongPair::leftFloat).sum() * 3600; + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHudConfigScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHudConfigScreen.java new file mode 100644 index 00000000..5384d47a --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHudConfigScreen.java @@ -0,0 +1,30 @@ +package de.hysky.skyblocker.skyblock.garden; + +import de.hysky.skyblocker.config.HudConfigScreen; +import de.hysky.skyblocker.config.SkyblockerConfig; +import de.hysky.skyblocker.skyblock.tabhud.widget.Widget; +import it.unimi.dsi.fastutil.ints.IntIntMutablePair; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.text.Text; + +import java.util.List; + +public class FarmingHudConfigScreen extends HudConfigScreen { + public FarmingHudConfigScreen(Screen parent) { + super(Text.literal("Farming HUD Config"), parent, FarmingHudWidget.INSTANCE); + } + + @SuppressWarnings("SuspiciousNameCombination") + @Override + protected List<IntIntMutablePair> getConfigPos(SkyblockerConfig config) { + return List.of( + IntIntMutablePair.of(config.locations.garden.farmingHud.x, config.locations.garden.farmingHud.y) + ); + } + + @Override + protected void savePos(SkyblockerConfig configManager, List<Widget> widgets) { + configManager.locations.garden.farmingHud.x = widgets.get(0).getX(); + configManager.locations.garden.farmingHud.y = widgets.get(0).getY(); + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHudWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHudWidget.java new file mode 100644 index 00000000..6ddb0e05 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHudWidget.java @@ -0,0 +1,67 @@ +package de.hysky.skyblocker.skyblock.garden; + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.tabhud.util.Ico; +import de.hysky.skyblocker.skyblock.tabhud.widget.Widget; +import de.hysky.skyblocker.skyblock.tabhud.widget.component.PlainTextComponent; +import de.hysky.skyblocker.skyblock.tabhud.widget.component.ProgressComponent; +import de.hysky.skyblocker.utils.ItemUtils; +import net.minecraft.client.MinecraftClient; +import net.minecraft.item.ItemStack; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.math.MathHelper; + +import java.util.Map; + +public class FarmingHudWidget extends Widget { + private static final MutableText TITLE = Text.literal("Farming").formatted(Formatting.YELLOW, Formatting.BOLD); + private static final Map<String, ItemStack> FARMING_TOOLS = Map.ofEntries( + Map.entry("THEORETICAL_HOE_WHEAT_1", Ico.WHEAT), + Map.entry("THEORETICAL_HOE_WHEAT_2", Ico.WHEAT), + Map.entry("THEORETICAL_HOE_WHEAT_3", Ico.WHEAT), + Map.entry("THEORETICAL_HOE_CARROT_1", Ico.CARROT), + Map.entry("THEORETICAL_HOE_CARROT_2", Ico.CARROT), + Map.entry("THEORETICAL_HOE_CARROT_3", Ico.CARROT), + Map.entry("THEORETICAL_HOE_POTATO_1", Ico.POTATO), + Map.entry("THEORETICAL_HOE_POTATO_2", Ico.POTATO), + Map.entry("THEORETICAL_HOE_POTATO_3", Ico.POTATO), + Map.entry("THEORETICAL_HOE_CANE_1", Ico.SUGAR_CANE), + Map.entry("THEORETICAL_HOE_CANE_2", Ico.SUGAR_CANE), + Map.entry("THEORETICAL_HOE_CANE_3", Ico.SUGAR_CANE), + Map.entry("THEORETICAL_HOE_WARTs_1", Ico.NETHER_WART), + Map.entry("THEORETICAL_HOE_WARTs_2", Ico.NETHER_WART), + Map.entry("THEORETICAL_HOE_WARTs_3", Ico.NETHER_WART), + Map.entry("FUNGI_CUTTER", Ico.MUSHROOM), + Map.entry("CACTUS_KNIFE", Ico.CACTUS), + Map.entry("MELON_DICER", Ico.MELON), + Map.entry("PUMPKIN_DICER", Ico.PUMPKIN), + Map.entry("COCO_CHOPPER", Ico.COCOA_BEANS) + ); + public static final FarmingHudWidget INSTANCE = new FarmingHudWidget(); + private final MinecraftClient client = MinecraftClient.getInstance(); + + public FarmingHudWidget() { + super(TITLE, Formatting.YELLOW.getColorValue()); + setX(SkyblockerConfigManager.get().locations.garden.farmingHud.x); + setY(SkyblockerConfigManager.get().locations.garden.farmingHud.y); + update(); + } + + @SuppressWarnings("DataFlowIssue") + @Override + public void updateContent() { + ItemStack icon = FARMING_TOOLS.getOrDefault(ItemUtils.getItemId(client.player.getMainHandStack()), Ico.HOE); + addSimpleIcoText(icon, "Counter: ", Formatting.YELLOW, FarmingHud.NUMBER_FORMAT.format(FarmingHud.counter())); + addSimpleIcoText(icon, "Crops/min: ", Formatting.YELLOW, FarmingHud.NUMBER_FORMAT.format((int) FarmingHud.cropsPerMinute() / 100 * 100)); + addSimpleIcoText(icon, "Blocks/s: ", Formatting.YELLOW, Integer.toString(FarmingHud.blockBreaks())); + addComponent(new ProgressComponent(Ico.LANTERN, Text.literal("Farming Level: "), FarmingHud.farmingXpPercentProgress(), Formatting.GOLD.getColorValue())); + addSimpleIcoText(Ico.LIME_DYE, "Farming XP/h: ", Formatting.YELLOW, FarmingHud.NUMBER_FORMAT.format((int) FarmingHud.farmingXpPerHour())); + + double yaw = client.getCameraEntity().getYaw(); + double pitch = client.getCameraEntity().getPitch(); + addComponent(new PlainTextComponent(Text.literal("Yaw: " + String.format("%.3f", MathHelper.wrapDegrees(yaw))).formatted(Formatting.YELLOW))); + addComponent(new PlainTextComponent(Text.literal("Pitch: " + String.format("%.3f", MathHelper.wrapDegrees(pitch))).formatted(Formatting.YELLOW))); + } +} 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 92e7e258..bde8b3ea 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/garden/VisitorHelper.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/garden/VisitorHelper.java @@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory; import java.text.NumberFormat; import java.util.HashMap; +import java.util.Locale; import java.util.Map; //TODO: check inventory items, sum all repeated items into one @@ -111,7 +112,7 @@ public class VisitorHelper { String itemName = splitItemText[0].trim(); if (itemName.isEmpty()) return; try { - int amount = splitItemText.length == 2 ? NumberFormat.getInstance().parse(splitItemText[1].trim()).intValue() : 1; + int amount = splitItemText.length == 2 ? NumberFormat.getInstance(Locale.US).parse(splitItemText[1].trim()).intValue() : 1; Object2IntMap<String> visitorMap = itemMap.getOrDefault(visitorName, new Object2IntOpenHashMap<>()); visitorMap.putIfAbsent(itemName, amount); itemMap.putIfAbsent(visitorName, visitorMap); |