Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Garden Tweaks & Features #1118

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,28 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig
.build())
.option(Option.<Boolean>createBuilder()
.name(Text.translatable("skyblocker.config.farming.garden.visitorHelper"))
.binding(defaults.farming.garden.visitorHelper,
.description(OptionDescription.of(Text.translatable("skyblocker.config.farming.garden.visitorHelper.@Tooltip")))
.binding(defaults.farming.garden.visitorHelper,
() -> config.farming.garden.visitorHelper,
newValue -> config.farming.garden.visitorHelper = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
.option(Option.<Boolean>createBuilder()
.name(Text.translatable("skyblocker.config.farming.garden.showStacksInVisitorHelper"))
.description(OptionDescription.of(Text.translatable("skyblocker.config.farming.garden.showStacksInVisitorHelper.@Tooltip")))
.binding(defaults.farming.garden.showStacksInVisitorHelper,
() -> config.farming.garden.showStacksInVisitorHelper,
newValue -> config.farming.garden.showStacksInVisitorHelper = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
.option(Option.<Boolean>createBuilder()
.name(Text.translatable("skyblocker.config.farming.garden.visitorHelperGardenOnly"))
.description(OptionDescription.of(Text.translatable("skyblocker.config.farming.garden.visitorHelperGardenOnly.@Tooltip")))
.binding(defaults.farming.garden.visitorHelperGardenOnly,
() -> config.farming.garden.visitorHelperGardenOnly,
newValue -> config.farming.garden.visitorHelperGardenOnly = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
.option(Option.<Boolean>createBuilder()
.name(Text.translatable("skyblocker.config.farming.garden.lockMouseTool"))
.binding(defaults.farming.garden.lockMouseTool,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ public static class Garden {
@SerialEntry
public boolean visitorHelper = true;

@SerialEntry
public boolean visitorHelperGardenOnly = true;

@SerialEntry
public boolean showStacksInVisitorHelper = false;

WannaBeIan marked this conversation as resolved.
Show resolved Hide resolved
@SerialEntry
public boolean lockMouseTool = false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ protected HandledScreenMixin(Text title) {

@Inject(at = @At("HEAD"), method = "mouseClicked")
public void skyblocker$mouseClicked(double mouseX, double mouseY, int button, CallbackInfoReturnable<Boolean> cir) {
if (SkyblockerConfigManager.get().farming.garden.visitorHelper && (Utils.getLocationRaw().equals("garden") && !getTitle().getString().contains("Logbook") || getTitle().getString().startsWith("Bazaar"))) {
if (SkyblockerConfigManager.get().farming.garden.visitorHelper && (!getTitle().getString().contains("Logbook") || getTitle().getString().startsWith("Bazaar"))) {
VisitorHelper.onMouseClicked(mouseX, mouseY, button, this.textRenderer);
}
}
Expand Down
258 changes: 143 additions & 115 deletions src/main/java/de/hysky/skyblocker/skyblock/garden/FarmingHud.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,119 +35,147 @@
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 FARMING_XP = Pattern.compile("§3\\+(?<xp>\\d+.?\\d*) Farming \\((?<percent>[\\d,]+.?\\d*)%\\)");
private static final MinecraftClient client = MinecraftClient.getInstance();
private static CounterType counterType = CounterType.NONE;
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;

@Init
public static void init() {
HudRenderEvents.AFTER_MAIN_HUD.register((context, tickCounter) -> {
if (shouldRender()) {
if (!counter.isEmpty() && counter.peek().rightLong() + 5000 < 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 = client.player.getMainHandStack();
if (stack == null || !tryGetCounter(stack, CounterType.CULTIVATING) && !tryGetCounter(stack, CounterType.COUNTER)) {
counterType = CounterType.NONE;
}
}
});
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 WidgetsConfigurationScreen(Location.GARDEN, "hud_garden", null)))))));
}

private static boolean tryGetCounter(ItemStack stack, CounterType counterType) {
NbtCompound customData = ItemUtils.getCustomData(stack);
if (customData == null || !customData.contains(counterType.nbtKey, NbtElement.NUMBER_TYPE)) return false;
int count = customData.getInt(counterType.nbtKey);
if (FarmingHud.counterType != counterType) {
counter.clear();
FarmingHud.counterType = counterType;
}
if (counter.isEmpty() || counter.peekLast().leftInt() != count) {
counter.offer(IntLongPair.of(count, System.currentTimeMillis()));
}
return true;
}

private static boolean shouldRender() {
return SkyblockerConfigManager.get().farming.garden.farmingHud.enableHud && client.player != null && Utils.getLocation() == Location.GARDEN;
}

public static String counterText() {
return counterType.text;
}

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() * blockBreaks() * 1800; // Hypixel only sends xp updates around every half a second
}

public enum CounterType {
NONE("", "No Counter"),
COUNTER("mined_crops", "Counter: "),
CULTIVATING("farmed_cultivating", "Cultivating Counter: ");

private final String nbtKey;
private final String text;

CounterType(String nbtKey, String text) {
this.nbtKey = nbtKey;
this.text = text;
}
public boolean matchesText(String textToMatch) {
return this.text.equals(textToMatch);
}
}
private static final Logger LOGGER = LoggerFactory.getLogger(FarmingHud.class);
public static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance(Locale.US);
private static final Pattern FARMING_XP = Pattern.compile("§3\\+(?<xp>\\d+(?:\\.\\d+)?) Farming \\((?<percent>[\\d,]+(?:\\.\\d+)?%|[\\d,]+/[\\d,]+)\\)");
WannaBeIan marked this conversation as resolved.
Show resolved Hide resolved
private static final MinecraftClient client = MinecraftClient.getInstance();
private static CounterType counterType = CounterType.NONE;
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;
private static double smoothedBlocksPerSecond = 0.0;
private static double smoothedFarmingXpPerHour = 0.0;

@Init
public static void init() {
HudRenderEvents.AFTER_MAIN_HUD.register((context, tickCounter) -> {
if (shouldRender()) {
if (!counter.isEmpty() && counter.peek().rightLong() + 5000 < 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();
}

assert client.player != null;
ItemStack stack = client.player.getMainHandStack();
if (stack == null || !tryGetCounter(stack, CounterType.CULTIVATING) && !tryGetCounter(stack, CounterType.COUNTER)) {
counterType = CounterType.NONE;
}
}
});
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 WidgetsConfigurationScreen(Location.GARDEN, "hud_garden", null)))))));
}

private static boolean tryGetCounter(ItemStack stack, CounterType counterType) {
NbtCompound customData = ItemUtils.getCustomData(stack);
if (customData == null || !customData.contains(counterType.nbtKey, NbtElement.NUMBER_TYPE)) return false;
int count = customData.getInt(counterType.nbtKey);
if (FarmingHud.counterType != counterType) {
counter.clear();
FarmingHud.counterType = counterType;
}
if (counter.isEmpty() || counter.peekLast().leftInt() != count) {
counter.offer(IntLongPair.of(count, System.currentTimeMillis()));
}
return true;
}

private static boolean shouldRender() {
return SkyblockerConfigManager.get().farming.garden.farmingHud.enableHud && client.player != null && Utils.getLocation() == Location.GARDEN;
}

public static String counterText() {
return counterType.text;
}

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 double blockBreaks() {
long currentTime = System.currentTimeMillis();
while (!blockBreaks.isEmpty() && blockBreaks.firstLong() + 1000 < currentTime) {
blockBreaks.dequeueLong();
}

double rawBlocksPerSecond = blockBreaks.size();
double t = 0.01;
smoothedBlocksPerSecond += (rawBlocksPerSecond - smoothedBlocksPerSecond) * t;

return Math.round(smoothedBlocksPerSecond * 10) / 10.0;
}
WannaBeIan marked this conversation as resolved.
Show resolved Hide resolved

public static float farmingXpPercentProgress() {
return farmingXpPercentProgress;
}

public static double farmingXpPerHour() {
WannaBeIan marked this conversation as resolved.
Show resolved Hide resolved
double xpPerCrop = farmingXp.isEmpty() ? 0 : farmingXp.peek().leftFloat();
double cropsPerSecond = blockBreaks();
double xpPerSecond = xpPerCrop * cropsPerSecond;
double t = 0.1;

smoothedFarmingXpPerHour += (xpPerSecond * 3600 - smoothedFarmingXpPerHour) * t;

return Math.round(smoothedFarmingXpPerHour * 10) / 10.0;
}


public enum CounterType {
NONE("", "No Counter"),
COUNTER("mined_crops", "Counter: "),
CULTIVATING("farmed_cultivating", "Cultivating Counter: ");

private final String nbtKey;
private final String text;

CounterType(String nbtKey, String text) {
this.nbtKey = nbtKey;
this.text = text;
}

public boolean matchesText(String textToMatch) {
return this.text.equals(textToMatch);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,10 @@ public void updateContent() {
float cropsPerMinute = FarmingHud.cropsPerMinute();
addSimpleIcoText(cropStack, "Crops/min: ", Formatting.YELLOW, FarmingHud.NUMBER_FORMAT.format((int) cropsPerMinute / 10 * 10));
addSimpleIcoText(Ico.GOLD, "Coins/h: ", Formatting.GOLD, getPriceText(cropItemId, cropsPerMinute));
addSimpleIcoText(cropStack, "Blocks/s: ", Formatting.YELLOW, Integer.toString(FarmingHud.blockBreaks()));
addSimpleIcoText(cropStack, "Blocks/s: ", Formatting.YELLOW, Double.toString(FarmingHud.blockBreaks()));
//noinspection DataFlowIssue
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()));
addSimpleIcoText(Ico.LIME_DYE, "Farming XP/h: ", Formatting.YELLOW, FarmingHud.NUMBER_FORMAT.format(FarmingHud.farmingXpPerHour()));

Entity cameraEntity = client.getCameraEntity();
String yaw = cameraEntity == null ? "No Camera Entity" : String.format("%.2f", MathHelper.wrapDegrees(cameraEntity.getYaw()));
Expand Down
Loading
Loading