aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/de/hysky/skyblocker/skyblock/fancybars
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/de/hysky/skyblocker/skyblock/fancybars')
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/fancybars/FancyStatusBars.java269
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/fancybars/StatusBarsConfigScreen.java1
2 files changed, 269 insertions, 1 deletions
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/fancybars/FancyStatusBars.java b/src/main/java/de/hysky/skyblocker/skyblock/fancybars/FancyStatusBars.java
new file mode 100644
index 00000000..9a9dc391
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/fancybars/FancyStatusBars.java
@@ -0,0 +1,269 @@
+package de.hysky.skyblocker.skyblock.fancybars;
+
+import com.google.gson.JsonObject;
+import de.hysky.skyblocker.SkyblockerMod;
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.skyblock.StatusBarTracker;
+import de.hysky.skyblocker.utils.Utils;
+import de.hysky.skyblocker.utils.scheduler.Scheduler;
+import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
+import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
+import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.gui.DrawContext;
+import net.minecraft.client.gui.ScreenPos;
+import net.minecraft.client.texture.Sprite;
+import net.minecraft.text.Text;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.math.MathHelper;
+import org.lwjgl.glfw.GLFW;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.awt.*;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Supplier;
+
+public class FancyStatusBars {
+ private static final Path FILE = SkyblockerMod.CONFIG_DIR.resolve("status_bars.json");
+ private static final Logger LOGGER = LoggerFactory.getLogger(FancyStatusBars.class);
+
+ private final MinecraftClient client = MinecraftClient.getInstance();
+ private final StatusBarTracker statusBarTracker = SkyblockerMod.getInstance().statusBarTracker;
+
+ public static BarPositioner barPositioner = new BarPositioner();
+ public static Map<String, StatusBar> statusBars = new HashMap<>();
+
+ public static void init() {
+ statusBars.put("health", new StatusBar(new Identifier(SkyblockerMod.NAMESPACE, "bars/icons/health"),
+ new Color[]{new Color(255, 0, 0), new Color(255, 220, 0)},
+ true, new Color(255, 85, 85), Text.translatable("skyblocker.bars.config.health")));
+ statusBars.put("intelligence", new StatusBar(new Identifier(SkyblockerMod.NAMESPACE, "bars/icons/intelligence"),
+ new Color[]{new Color(0, 255, 255), new Color(180, 0, 255)},
+ true, new Color(85, 255, 255), Text.translatable("skyblocker.bars.config.intelligence")));
+ statusBars.put("defense", new StatusBar(new Identifier(SkyblockerMod.NAMESPACE, "bars/icons/defense"),
+ new Color[]{new Color(255, 255, 255)},
+ false, new Color(185, 185, 185), Text.translatable("skyblocker.bars.config.defense")));
+ statusBars.put("experience", new StatusBar(new Identifier(SkyblockerMod.NAMESPACE, "bars/icons/experience"),
+ new Color[]{new Color(100, 230, 70)},
+ false, new Color(128, 255, 32), Text.translatable("skyblocker.bars.config.experience")));
+
+ // Default positions
+ StatusBar health = statusBars.get("health");
+ health.anchor = BarPositioner.BarAnchor.HOTBAR_TOP;
+ health.gridX = 0;
+ health.gridY = 0;
+ StatusBar intelligence = statusBars.get("intelligence");
+ intelligence.anchor = BarPositioner.BarAnchor.HOTBAR_TOP;
+ intelligence.gridX = 1;
+ intelligence.gridY = 0;
+ StatusBar defense = statusBars.get("defense");
+ defense.anchor = BarPositioner.BarAnchor.HOTBAR_RIGHT;
+ defense.gridX = 0;
+ defense.gridY = 0;
+ StatusBar experience = statusBars.get("experience");
+ experience.anchor = BarPositioner.BarAnchor.HOTBAR_TOP;
+ experience.gridX = 0;
+ experience.gridY = 1;
+
+ CompletableFuture.supplyAsync(FancyStatusBars::loadBarConfig).thenAccept(object -> {
+ if (object != null) {
+ for (String s : object.keySet()) {
+ if (statusBars.containsKey(s)) {
+ try {
+ statusBars.get(s).loadFromJson(object.get(s).getAsJsonObject());
+ } catch (Exception e) {
+ LOGGER.error("[Skyblocker] Failed to load {} status bar", s, e);
+ }
+ } else {
+ LOGGER.warn("[Skyblocker] Unknown status bar: {}", s);
+ }
+ }
+ }
+ placeBarsInPositioner();
+ configLoaded = true;
+ }).exceptionally(throwable -> {
+ LOGGER.error("[Skyblocker] Failed reading status bars config", throwable);
+ return null;
+ });
+ ClientLifecycleEvents.CLIENT_STOPPING.register((client) -> {
+ saveBarConfig();
+ GLFW.glfwDestroyCursor(StatusBarsConfigScreen.RESIZE_CURSOR);
+ });
+ /*barGrid.addRow(1, false);
+ barGrid.add(1, 1, statusBars.get("health"));
+ barGrid.add(2, 1, statusBars.get("intelligence"));
+ barGrid.addRow(2, false);
+ barGrid.add(1, 2, statusBars.get("experience"));
+ barGrid.addRow(-1, true);
+ barGrid.add(1, -1, statusBars.get("defense"));*/
+ //placeBarsInGrid();
+
+ ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(
+ ClientCommandManager.literal(SkyblockerMod.NAMESPACE)
+ .then(ClientCommandManager.literal("bars").executes(Scheduler.queueOpenScreenCommand(StatusBarsConfigScreen::new)))));
+ }
+
+ private static boolean configLoaded = false;
+
+ private static void placeBarsInPositioner() {
+ List<StatusBar> original = statusBars.values().stream().toList();
+
+ for (BarPositioner.BarAnchor barAnchor : BarPositioner.BarAnchor.allAnchors()) {
+ List<StatusBar> barList = new ArrayList<>(original.stream().filter(bar -> bar.anchor == barAnchor).toList());
+ if (barList.isEmpty()) continue;
+ barList.sort((a, b) -> a.gridY == b.gridY ? Integer.compare(a.gridX, b.gridX) : Integer.compare(a.gridY, b.gridY));
+
+ int y = -1;
+ int rowNum = -1;
+ for (StatusBar statusBar : barList) {
+ if (statusBar.gridY > y) {
+ barPositioner.addRow(barAnchor);
+ rowNum++;
+ y = statusBar.gridY;
+ }
+ barPositioner.addBar(barAnchor, rowNum, statusBar);
+ }
+ }
+ }
+
+ public static JsonObject loadBarConfig() {
+ try (BufferedReader reader = Files.newBufferedReader(FILE)) {
+ return SkyblockerMod.GSON.fromJson(reader, JsonObject.class);
+ } catch (NoSuchFileException e) {
+ LOGGER.warn("[Skyblocker] No status bar config file found, using defaults");
+ } catch (Exception e) {
+ LOGGER.error("[Skyblocker] Failed to load status bars config", e);
+ }
+ return null;
+ }
+
+ public static void saveBarConfig() {
+ JsonObject output = new JsonObject();
+ statusBars.forEach((s, statusBar) -> output.add(s, statusBar.toJson()));
+ try (BufferedWriter writer = Files.newBufferedWriter(FILE)) {
+ SkyblockerMod.GSON.toJson(output, writer);
+ LOGGER.info("[Skyblocker] Saved status bars config");
+ } catch (IOException e) {
+ LOGGER.error("[Skyblocker] Failed to save status bars config", e);
+ }
+ }
+
+ public static void updatePositions() {
+ if (!configLoaded) return;
+ final int width = MinecraftClient.getInstance().getWindow().getScaledWidth();
+ final int height = MinecraftClient.getInstance().getWindow().getScaledHeight();
+
+ for (BarPositioner.BarAnchor barAnchor : BarPositioner.BarAnchor.allAnchors()) {
+ ScreenPos anchorPosition = barAnchor.getAnchorPosition(width, height);
+ BarPositioner.SizeRule sizeRule = barAnchor.getSizeRule();
+
+ if (sizeRule.isTargetSize()) {
+ for (int row = 0; row < barPositioner.getRowCount(barAnchor); row++) {
+ LinkedList<StatusBar> barRow = barPositioner.getRow(barAnchor, row);
+ if (barRow.isEmpty()) continue;
+
+ // FIX SIZES
+ int totalSize = 0;
+ for (StatusBar statusBar : barRow)
+ totalSize += (statusBar.size = MathHelper.clamp(statusBar.size, sizeRule.minSize(), sizeRule.maxSize()));
+
+ whileLoop:
+ while (totalSize != sizeRule.targetSize()) {
+ if (totalSize > sizeRule.targetSize()) {
+ for (StatusBar statusBar : barRow) {
+ if (statusBar.size > sizeRule.minSize()) {
+ statusBar.size--;
+ totalSize--;
+ if (totalSize == sizeRule.targetSize()) break whileLoop;
+ }
+ }
+ } else {
+ for (StatusBar statusBar : barRow) {
+ if (statusBar.size < sizeRule.maxSize()) {
+ statusBar.size++;
+ totalSize++;
+ if (totalSize == sizeRule.targetSize()) break whileLoop;
+ }
+ }
+ }
+ }
+
+ }
+ }
+
+ for (int row = 0; row < barPositioner.getRowCount(barAnchor); row++) {
+ List<StatusBar> barRow = barPositioner.getRow(barAnchor, row);
+ if (barRow.isEmpty()) continue;
+
+
+ // Update the positions
+ float widthPerSize;
+ if (sizeRule.isTargetSize())
+ widthPerSize = (float) sizeRule.totalWidth() / sizeRule.targetSize();
+ else
+ widthPerSize = sizeRule.widthPerSize();
+
+ int currSize = 0;
+ for (int i = 0; i < barRow.size(); i++) {
+ StatusBar statusBar = barRow.get(i);
+ statusBar.size = MathHelper.clamp(statusBar.size, sizeRule.minSize(), sizeRule.maxSize());
+
+ float x = barAnchor.isRight() ?
+ anchorPosition.x() + currSize * widthPerSize :
+ anchorPosition.x() - currSize * widthPerSize - statusBar.size * widthPerSize;
+ statusBar.setX((int) x);
+
+ int y = barAnchor.isUp() ?
+ anchorPosition.y() - (row + 1) * (statusBar.getHeight() + 1) :
+ anchorPosition.y() + row * (statusBar.getHeight() + 1);
+ statusBar.setY(y);
+
+ statusBar.setWidth((int) (statusBar.size * widthPerSize));
+ currSize += statusBar.size;
+ statusBar.gridX = i;
+ statusBar.gridY = row;
+
+ }
+ }
+
+ }
+ }
+
+ public FancyStatusBars() {}
+
+ private static final Identifier BAR_FILL = new Identifier(SkyblockerMod.NAMESPACE, "bars/bar_fill");
+ private static final Identifier BAR_BACK = new Identifier(SkyblockerMod.NAMESPACE, "bars/bar_back");
+ private static final Supplier<Sprite> SUPPLIER = () -> MinecraftClient.getInstance().getGuiAtlasManager().getSprite(BAR_FILL);
+
+ public boolean render(DrawContext context, int scaledWidth, int scaledHeight) {
+ var player = client.player;
+ if (!SkyblockerConfigManager.get().general.bars.enableBars || player == null || Utils.isInTheRift())
+ return false;
+
+ Collection<StatusBar> barCollection = statusBars.values();
+ for (StatusBar value : barCollection) {
+ value.render(context, -1, -1, client.getLastFrameDuration());
+ }
+ for (StatusBar statusBar : barCollection) {
+ if (statusBar.showText()) statusBar.renderText(context);
+ }
+ StatusBarTracker.Resource health = statusBarTracker.getHealth();
+ statusBars.get("health").updateValues(health.value() / (float) health.max(), health.overflow() / (float) health.max(), health.value());
+
+ StatusBarTracker.Resource intelligence = statusBarTracker.getMana();
+ statusBars.get("intelligence").updateValues(intelligence.value() / (float) intelligence.max(), intelligence.overflow() / (float) intelligence.max(), intelligence.value());
+ int defense = statusBarTracker.getDefense();
+ statusBars.get("defense").updateValues(defense / (defense + 100.f), 0, defense);
+ statusBars.get("experience").updateValues(player.experienceProgress, 0, player.experienceLevel);
+ return true;
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/fancybars/StatusBarsConfigScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/fancybars/StatusBarsConfigScreen.java
index 7c1aa71b..4d23dc07 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/fancybars/StatusBarsConfigScreen.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/fancybars/StatusBarsConfigScreen.java
@@ -1,7 +1,6 @@
package de.hysky.skyblocker.skyblock.fancybars;
import de.hysky.skyblocker.mixin.accessor.WindowAccessor;
-import de.hysky.skyblocker.skyblock.FancyStatusBars;
import it.unimi.dsi.fastutil.Pair;
import it.unimi.dsi.fastutil.objects.ObjectBooleanMutablePair;
import it.unimi.dsi.fastutil.objects.ObjectObjectMutablePair;