aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHud.java
blob: dba282c1a40c2f6f1767299cb97cbe13da92f0fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package de.hysky.skyblocker.skyblock.garden;

import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.skyblock.tabhud.widget.hud.HudFarmingWidget;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.Location;
import de.hysky.skyblocker.utils.Utils;
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.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;

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,]+) \\w+");
    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);
                    }
                }

                HudFarmingWidget.INSTANCE.update();
                HudFarmingWidget.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);
                    }
                }
            }
        });
    }

    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;
    }
}