diff options
| author | Yasin <a.piri@hotmail.de> | 2023-10-09 12:58:02 +0200 |
|---|---|---|
| committer | Yasin <a.piri@hotmail.de> | 2023-10-09 12:58:02 +0200 |
| commit | bd3f0329d0e391bd84b5f9e3ff207d9dd9815853 (patch) | |
| tree | 2fd1d1ef625f57acc2e4916c967d8d2393844798 /src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder | |
| parent | 2315b90da8117f28f66348927afdb621ee4fc815 (diff) | |
| download | Skyblocker-bd3f0329d0e391bd84b5f9e3ff207d9dd9815853.tar.gz Skyblocker-bd3f0329d0e391bd84b5f9e3ff207d9dd9815853.tar.bz2 Skyblocker-bd3f0329d0e391bd84b5f9e3ff207d9dd9815853.zip | |
new pr because fixing merge conflict would take too long
Diffstat (limited to 'src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder')
7 files changed, 781 insertions, 0 deletions
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/ScreenBuilder.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/ScreenBuilder.java new file mode 100644 index 00000000..ceeaa365 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/ScreenBuilder.java @@ -0,0 +1,179 @@ +package de.hysky.skyblocker.skyblock.tabhud.screenbuilder; + +import java.io.BufferedReader; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.NoSuchElementException; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import de.hysky.skyblocker.skyblock.tabhud.widget.Widget; +import de.hysky.skyblocker.skyblock.tabhud.screenbuilder.pipeline.AlignStage; +import de.hysky.skyblocker.skyblock.tabhud.screenbuilder.pipeline.CollideStage; +import de.hysky.skyblocker.skyblock.tabhud.screenbuilder.pipeline.PipelineStage; +import de.hysky.skyblocker.skyblock.tabhud.screenbuilder.pipeline.PlaceStage; +import de.hysky.skyblocker.skyblock.tabhud.screenbuilder.pipeline.StackStage; +import de.hysky.skyblocker.skyblock.tabhud.widget.DungeonPlayerWidget; +import de.hysky.skyblocker.skyblock.tabhud.widget.ErrorWidget; +import de.hysky.skyblocker.skyblock.tabhud.widget.EventWidget; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.util.Identifier; + +public class ScreenBuilder { + + // layout pipeline + private final ArrayList<PipelineStage> layoutPipeline = new ArrayList<>(); + + // all widget instances this builder knows + private final ArrayList<Widget> instances = new ArrayList<>(); + // maps alias -> widget instance + private final HashMap<String, Widget> objectMap = new HashMap<>(); + + private final String builderName; + + /** + * Create a ScreenBuilder from a json. + */ + public ScreenBuilder(Identifier ident) { + + try (BufferedReader reader = MinecraftClient.getInstance().getResourceManager().openAsReader(ident)) { + this.builderName = ident.getPath(); + + JsonObject json = JsonParser.parseReader(reader).getAsJsonObject(); + + JsonArray widgets = json.getAsJsonArray("widgets"); + JsonArray layout = json.getAsJsonArray("layout"); + + for (JsonElement w : widgets) { + JsonObject widget = w.getAsJsonObject(); + String name = widget.get("name").getAsString(); + String alias = widget.get("alias").getAsString(); + + Widget wid = instanceFrom(name, widget); + objectMap.put(alias, wid); + instances.add(wid); + } + + for (JsonElement l : layout) { + PipelineStage ps = createStage(l.getAsJsonObject()); + layoutPipeline.add(ps); + } + } catch (Exception ex) { + // rethrow as unchecked exception so that I don't have to catch anything in the ScreenMaster + throw new IllegalStateException("Failed to load file " + ident + ". Reason: " + ex.getMessage()); + } + } + + /** + * Try to find a class in the widget package that has the supplied name and + * call it's constructor. Manual work is required if the class has arguments. + */ + public Widget instanceFrom(String name, JsonObject widget) { + + // do widgets that require args the normal way + JsonElement arg; + switch (name) { + case "EventWidget" -> { + return new EventWidget(widget.get("inGarden").getAsBoolean()); + } + case "DungeonPlayerWidget" -> { + return new DungeonPlayerWidget(widget.get("player").getAsInt()); + } + case "ErrorWidget" -> { + arg = widget.get("text"); + if (arg == null) { + return new ErrorWidget(); + } else { + return new ErrorWidget(arg.getAsString()); + } + } + case "Widget" -> + // clown case sanity check. don't instantiate the superclass >:| + throw new NoSuchElementException(builderName + "[ERROR]: No such Widget type \"Widget\"!"); + } + + // reflect something together for the "normal" ones. + + // list all packages that might contain widget classes + // using Package isn't reliable, as some classes might not be loaded yet, + // causing the packages not to show. + String packbase = "de.hysky.skyblocker.skyblock.tabhud.widget"; + String[] packnames = { + packbase, + packbase + ".rift" + }; + + // construct the full class name and try to load. + Class<?> clazz = null; + for (String pn : packnames) { + try { + clazz = Class.forName(pn + "." + name); + } catch (LinkageError | ClassNotFoundException ex) { + continue; + } + } + + // load failed. + if (clazz == null) { + throw new NoSuchElementException(builderName + "/[ERROR]: No such Widget type \"" + name + "\"!"); + } + + // return instance of that class. + try { + Constructor<?> ctor = clazz.getConstructor(); + return (Widget) ctor.newInstance(); + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException + | IllegalArgumentException | InvocationTargetException | SecurityException ex) { + throw new IllegalStateException(builderName + "/" + name + ": Internal error..."); + } + } + + /** + * Create a PipelineStage from a json object. + */ + public PipelineStage createStage(JsonObject descr) throws NoSuchElementException { + + String op = descr.get("op").getAsString(); + + return switch (op) { + case "place" -> new PlaceStage(this, descr); + case "stack" -> new StackStage(this, descr); + case "align" -> new AlignStage(this, descr); + case "collideAgainst" -> new CollideStage(this, descr); + default -> throw new NoSuchElementException("No such op " + op + " as requested by " + this.builderName); + }; + } + + /** + * Lookup Widget instance from alias name + */ + public Widget getInstance(String name) { + if (!this.objectMap.containsKey(name)) { + throw new NoSuchElementException("No widget with alias " + name + " in screen " + builderName); + } + return this.objectMap.get(name); + } + + /** + * Run the pipeline to build a Screen + */ + public void run(DrawContext context, int screenW, int screenH) { + + for (Widget w : instances) { + w.update(); + } + for (PipelineStage ps : layoutPipeline) { + ps.run(screenW, screenH); + } + for (Widget w : instances) { + w.render(context); + } + } + +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/ScreenMaster.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/ScreenMaster.java new file mode 100644 index 00000000..210d8001 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/ScreenMaster.java @@ -0,0 +1,144 @@ +package de.hysky.skyblocker.skyblock.tabhud.screenbuilder; + +import java.io.BufferedReader; +import java.util.HashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import de.hysky.skyblocker.skyblock.tabhud.TabHud; +import de.hysky.skyblocker.skyblock.tabhud.util.PlayerLocator; +import net.fabricmc.fabric.api.resource.ResourceManagerHelper; +import net.fabricmc.fabric.api.resource.ResourcePackActivationType; +import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.resource.Resource; +import net.minecraft.resource.ResourceManager; +import net.minecraft.resource.ResourceType; +import net.minecraft.util.Identifier; + +public class ScreenMaster { + + private static final Logger LOGGER = LoggerFactory.getLogger("skyblocker"); + + private static final int VERSION = 1; + + private static final HashMap<String, ScreenBuilder> standardMap = new HashMap<>(); + private static final HashMap<String, ScreenBuilder> screenAMap = new HashMap<>(); + private static final HashMap<String, ScreenBuilder> screenBMap = new HashMap<>(); + + /** + * Load a screen mapping from an identifier + */ + public static void load(Identifier ident) { + + String path = ident.getPath(); + String[] parts = path.split("/"); + String screenType = parts[parts.length - 2]; + String location = parts[parts.length - 1]; + location = location.replace(".json", ""); + + ScreenBuilder sb = new ScreenBuilder(ident); + switch (screenType) { + case "standard" -> standardMap.put(location, sb); + case "screen_a" -> screenAMap.put(location, sb); + case "screen_b" -> screenBMap.put(location, sb); + } + } + + /** + * Top level render method. + * Calls the appropriate ScreenBuilder with the screen's dimensions + */ + public static void render(DrawContext context, int w, int h) { + String location = PlayerLocator.getPlayerLocation().internal; + HashMap<String, ScreenBuilder> lookup; + if (TabHud.toggleA.isPressed()) { + lookup = screenAMap; + } else if (TabHud.toggleB.isPressed()) { + lookup = screenBMap; + } else { + lookup = standardMap; + } + + ScreenBuilder sb = lookup.get(location); + // seems suboptimal, maybe load the default first into all possible values + // and then override? + if (sb == null) { + sb = lookup.get("default"); + } + + sb.run(context, w, h); + + } + + public static void init() { + + // WHY MUST IT ALWAYS BE SUCH NESTED GARBAGE MINECRAFT KEEP THAT IN DFU FFS + + FabricLoader.getInstance() + .getModContainer("skyblocker") + .ifPresent(container -> ResourceManagerHelper.registerBuiltinResourcePack( + new Identifier("skyblocker", "top_aligned"), + container, + ResourcePackActivationType.NORMAL)); + + ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener( + // ...why are we instantiating an interface again? + new SimpleSynchronousResourceReloadListener() { + @Override + public Identifier getFabricId() { + return new Identifier("skyblocker", "tabhud"); + } + + @Override + public void reload(ResourceManager manager) { + + standardMap.clear(); + screenAMap.clear(); + screenBMap.clear(); + + int excnt = 0; + + for (Map.Entry<Identifier, Resource> entry : manager + .findResources("tabhud", path -> path.getPath().endsWith("version.json")) + .entrySet()) { + + try (BufferedReader reader = MinecraftClient.getInstance().getResourceManager() + .openAsReader(entry.getKey())) { + JsonObject json = JsonParser.parseReader(reader).getAsJsonObject(); + if (json.get("format_version").getAsInt() != VERSION) { + throw new IllegalStateException(String.format("Resource pack isn't compatible! Expected version %d, got %d", VERSION, json.get("format_version").getAsInt())); + } + + } catch (Exception ex) { + throw new IllegalStateException( + "Rejected this resource pack. Reason: " + ex.getMessage()); + } + } + + for (Map.Entry<Identifier, Resource> entry : manager + .findResources("tabhud", path -> path.getPath().endsWith(".json") && !path.getPath().endsWith("version.json")) + .entrySet()) { + try { + + load(entry.getKey()); + } catch (Exception e) { + LOGGER.error(e.getMessage()); + excnt++; + } + } + if (excnt > 0) { + throw new IllegalStateException("This screen definition isn't valid, see above"); + } + } + }); + } + +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/pipeline/AlignStage.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/pipeline/AlignStage.java new file mode 100644 index 00000000..7c01a6db --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/pipeline/AlignStage.java @@ -0,0 +1,83 @@ +package de.hysky.skyblocker.skyblock.tabhud.screenbuilder.pipeline; + +import java.util.ArrayList; +import java.util.NoSuchElementException; + +import com.google.gson.JsonObject; + +import de.hysky.skyblocker.skyblock.tabhud.screenbuilder.ScreenBuilder; +import de.hysky.skyblocker.skyblock.tabhud.widget.Widget; +import de.hysky.skyblocker.skyblock.tabhud.util.ScreenConst; + +public class AlignStage extends PipelineStage { + + private enum AlignReference { + HORICENT("horizontalCenter"), + VERTCENT("verticalCenter"), + LEFTCENT("leftOfCenter"), + RIGHTCENT("rightOfCenter"), + TOPCENT("topOfCenter"), + BOTCENT("botOfCenter"), + TOP("top"), + BOT("bot"), + LEFT("left"), + RIGHT("right"); + + private final String str; + + AlignReference(String d) { + this.str = d; + } + + public static AlignReference parse(String s) throws NoSuchElementException { + for (AlignReference d : AlignReference.values()) { + if (d.str.equals(s)) { + return d; + } + } + throw new NoSuchElementException("\"" + s + "\" is not a valid reference for an align op!"); + } + } + + private final AlignReference reference; + + public AlignStage(ScreenBuilder builder, JsonObject descr) { + this.reference = AlignReference.parse(descr.get("reference").getAsString()); + this.primary = new ArrayList<>(descr.getAsJsonArray("apply_to") + .asList() + .stream() + .map(x -> builder.getInstance(x.getAsString())) + .toList()); + } + + public void run(int screenW, int screenH) { + int wHalf, hHalf; + for (Widget wid : primary) { + switch (this.reference) { + case HORICENT -> wid.setX((screenW - wid.getWidth()) / 2); + case VERTCENT -> wid.setY((screenH - wid.getHeight()) / 2); + case LEFTCENT -> { + wHalf = screenW / 2; + wid.setX(wHalf - ScreenConst.WIDGET_PAD_HALF - wid.getWidth()); + } + case RIGHTCENT -> { + wHalf = screenW / 2; + wid.setX(wHalf + ScreenConst.WIDGET_PAD_HALF); + } + case TOPCENT -> { + hHalf = screenH / 2; + wid.setY(hHalf - ScreenConst.WIDGET_PAD_HALF - wid.getHeight()); + } + case BOTCENT -> { + hHalf = screenH / 2; + wid.setY(hHalf + ScreenConst.WIDGET_PAD_HALF); + } + case TOP -> wid.setY(ScreenConst.getScreenPad()); + case BOT -> wid.setY(screenH - wid.getHeight() - ScreenConst.getScreenPad()); + case LEFT -> wid.setX(ScreenConst.getScreenPad()); + case RIGHT -> wid.setX(screenW - wid.getWidth() - ScreenConst.getScreenPad()); + } + } + } + +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/pipeline/CollideStage.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/pipeline/CollideStage.java new file mode 100644 index 00000000..d100a52e --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/pipeline/CollideStage.java @@ -0,0 +1,153 @@ +package de.hysky.skyblocker.skyblock.tabhud.screenbuilder.pipeline; + +import java.util.ArrayList; +import java.util.NoSuchElementException; + +import com.google.gson.JsonObject; + +import de.hysky.skyblocker.skyblock.tabhud.screenbuilder.ScreenBuilder; +import de.hysky.skyblocker.skyblock.tabhud.widget.Widget; +import de.hysky.skyblocker.skyblock.tabhud.util.ScreenConst; + +public class CollideStage extends PipelineStage { + + private enum CollideDirection { + LEFT("left"), + RIGHT("right"), + TOP("top"), + BOT("bot"); + + private final String str; + + CollideDirection(String d) { + this.str = d; + } + + public static CollideDirection parse(String s) throws NoSuchElementException { + for (CollideDirection d : CollideDirection.values()) { + if (d.str.equals(s)) { + return d; + } + } + throw new NoSuchElementException("\"" + s + "\" is not a valid direction for a collide op!"); + } + } + + private final CollideDirection direction; + + public CollideStage(ScreenBuilder builder, JsonObject descr) { + this.direction = CollideDirection.parse(descr.get("direction").getAsString()); + this.primary = new ArrayList<>(descr.getAsJsonArray("widgets") + .asList() + .stream() + .map(x -> builder.getInstance(x.getAsString())) + .toList()); + this.secondary = new ArrayList<>(descr.getAsJsonArray("colliders") + .asList() + .stream() + .map(x -> builder.getInstance(x.getAsString())) + .toList()); + } + + public void run(int screenW, int screenH) { + switch (this.direction) { + case LEFT -> primary.forEach(w -> collideAgainstL(screenW, w)); + case RIGHT -> primary.forEach(w -> collideAgainstR(screenW, w)); + case TOP -> primary.forEach(w -> collideAgainstT(screenH, w)); + case BOT -> primary.forEach(w -> collideAgainstB(screenH, w)); + } + } + + public void collideAgainstL(int screenW, Widget w) { + int yMin = w.getY(); + int yMax = w.getY() + w.getHeight(); + + int xCor = screenW; + + for (Widget other : secondary) { + if (other.getY() + other.getHeight() + ScreenConst.WIDGET_PAD < yMin) { + // too high, next one + continue; + } + + if (other.getY() - ScreenConst.WIDGET_PAD > yMax) { + // too low, next + continue; + } + + int xPos = other.getX() - ScreenConst.WIDGET_PAD - w.getWidth(); + xCor = Math.min(xCor, xPos); + } + w.setX(xCor); + } + + public void collideAgainstR(int screenW, Widget w) { + int yMin = w.getY(); + int yMax = w.getY() + w.getHeight(); + + int xCor = 0; + + for (Widget other : secondary) { + if (other.getY() + other.getHeight() + ScreenConst.WIDGET_PAD < yMin) { + // too high, next one + continue; + } + + if (other.getY() - ScreenConst.WIDGET_PAD > yMax) { + // too low, next + continue; + } + + int xPos = other.getX() + other.getWidth() + ScreenConst.WIDGET_PAD; + xCor = Math.max(xCor, xPos); + } + w.setX(xCor); + } + + public void collideAgainstT(int screenH, Widget w) { + int xMin = w.getX(); + int xMax = w.getX() + w.getWidth(); + + int yCor = screenH; + + for (Widget other : secondary) { + if (other.getX() + other.getWidth() + ScreenConst.WIDGET_PAD < xMin) { + // too far left, next one + continue; + } + + if (other.getX() - ScreenConst.WIDGET_PAD > xMax) { + // too far right, next + continue; + } + + int yPos = other.getY() - ScreenConst.WIDGET_PAD - w.getHeight(); + yCor = Math.min(yCor, yPos); + } + w.setY(yCor); + } + + public void collideAgainstB(int screenH, Widget w) { + int xMin = w.getX(); + int xMax = w.getX() + w.getWidth(); + + int yCor = 0; + + for (Widget other : secondary) { + if (other.getX() + other.getWidth() + ScreenConst.WIDGET_PAD < xMin) { + // too far left, next one + continue; + } + + if (other.getX() - ScreenConst.WIDGET_PAD > xMax) { + // too far right, next + continue; + } + + int yPos = other.getY() + other.getHeight() + ScreenConst.WIDGET_PAD; + yCor = Math.max(yCor, yPos); + } + w.setY(yCor); + } + +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/pipeline/PipelineStage.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/pipeline/PipelineStage.java new file mode 100644 index 00000000..20e4859e --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/pipeline/PipelineStage.java @@ -0,0 +1,14 @@ +package de.hysky.skyblocker.skyblock.tabhud.screenbuilder.pipeline; + +import java.util.ArrayList; + +import de.hysky.skyblocker.skyblock.tabhud.widget.Widget; + +public abstract class PipelineStage { + + protected ArrayList<Widget> primary = null; + protected ArrayList<Widget> secondary = null; + + public abstract void run(int screenW, int screenH); + +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/pipeline/PlaceStage.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/pipeline/PlaceStage.java new file mode 100644 index 00000000..7d57305b --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/pipeline/PlaceStage.java @@ -0,0 +1,94 @@ +package de.hysky.skyblocker.skyblock.tabhud.screenbuilder.pipeline; + +import java.util.ArrayList; +import java.util.NoSuchElementException; + +import com.google.gson.JsonObject; + +import de.hysky.skyblocker.skyblock.tabhud.screenbuilder.ScreenBuilder; +import de.hysky.skyblocker.skyblock.tabhud.widget.Widget; +import de.hysky.skyblocker.skyblock.tabhud.util.ScreenConst; + +public class PlaceStage extends PipelineStage { + + private enum PlaceLocation { + CENTER("center"), + TOPCENT("centerTop"), + BOTCENT("centerBot"), + LEFTCENT("centerLeft"), + RIGHTCENT("centerRight"), + TRCORNER("cornerTopRight"), + TLCORNER("cornerTopLeft"), + BRCORNER("cornerBotRight"), + BLCORNER("cornerBotLeft"); + + private final String str; + + PlaceLocation(String d) { + this.str = d; + } + + public static PlaceLocation parse(String s) throws NoSuchElementException { + for (PlaceLocation d : PlaceLocation.values()) { + if (d.str.equals(s)) { + return d; + } + } + throw new NoSuchElementException("\"" + s + "\" is not a valid location for a place op!"); + } + } + + private final PlaceLocation where; + + public PlaceStage(ScreenBuilder builder, JsonObject descr) { + this.where = PlaceLocation.parse(descr.get("where").getAsString()); + this.primary = new ArrayList<>(descr.getAsJsonArray("apply_to") + .asList() + .stream() + .map(x -> builder.getInstance(x.getAsString())) + .limit(1) + .toList()); + } + + public void run(int screenW, int screenH) { + Widget wid = primary.get(0); + switch (where) { + case CENTER -> { + wid.setX((screenW - wid.getWidth()) / 2); + wid.setY((screenH - wid.getHeight()) / 2); + } + case TOPCENT -> { + wid.setX((screenW - wid.getWidth()) / 2); + wid.setY(ScreenConst.getScreenPad()); + } + case BOTCENT -> { + wid.setX((screenW - wid.getWidth()) / 2); + wid.setY((screenH - wid.getHeight()) - ScreenConst.getScreenPad()); + } + case LEFTCENT -> { + wid.setX(ScreenConst.getScreenPad()); + wid.setY((screenH - wid.getHeight()) / 2); + } + case RIGHTCENT -> { + wid.setX((screenW - wid.getWidth()) - ScreenConst.getScreenPad()); + wid.setY((screenH - wid.getHeight()) / 2); + } + case TLCORNER -> { + wid.setX(ScreenConst.getScreenPad()); + wid.setY(ScreenConst.getScreenPad()); + } + case TRCORNER -> { + wid.setX((screenW - wid.getWidth()) - ScreenConst.getScreenPad()); + wid.setY(ScreenConst.getScreenPad()); + } + case BLCORNER -> { + wid.setX(ScreenConst.getScreenPad()); + wid.setY((screenH - wid.getHeight()) - ScreenConst.getScreenPad()); + } + case BRCORNER -> { + wid.setX((screenW - wid.getWidth()) - ScreenConst.getScreenPad()); + wid.setY((screenH - wid.getHeight()) - ScreenConst.getScreenPad()); + } + } + } +}
\ No newline at end of file diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/pipeline/StackStage.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/pipeline/StackStage.java new file mode 100644 index 00000000..f4fe07e5 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/screenbuilder/pipeline/StackStage.java @@ -0,0 +1,114 @@ +package de.hysky.skyblocker.skyblock.tabhud.screenbuilder.pipeline; + +import java.util.ArrayList; +import java.util.NoSuchElementException; + +import com.google.gson.JsonObject; + +import de.hysky.skyblocker.skyblock.tabhud.screenbuilder.ScreenBuilder; +import de.hysky.skyblocker.skyblock.tabhud.widget.Widget; +import de.hysky.skyblocker.skyblock.tabhud.util.ScreenConst; + +public class StackStage extends PipelineStage { + + private enum StackDirection { + HORIZONTAL("horizontal"), + VERTICAL("vertical"); + + private final String str; + + StackDirection(String d) { + this.str = d; + } + + public static StackDirection parse(String s) throws NoSuchElementException { + for (StackDirection d : StackDirection.values()) { + if (d.str.equals(s)) { + return d; + } + } + throw new NoSuchElementException("\"" + s + "\" is not a valid direction for a stack op!"); + } + } + + private enum StackAlign { + TOP("top"), + BOT("bot"), + LEFT("left"), + RIGHT("right"), + CENTER("center"); + + private final String str; + + StackAlign(String d) { + this.str = d; + } + + public static StackAlign parse(String s) throws NoSuchElementException { + for (StackAlign d : StackAlign.values()) { + if (d.str.equals(s)) { + return d; + } + } + throw new NoSuchElementException("\"" + s + "\" is not a valid alignment for a stack op!"); + } + } + + private final StackDirection direction; + private final StackAlign align; + + public StackStage(ScreenBuilder builder, JsonObject descr) { + this.direction = StackDirection.parse(descr.get("direction").getAsString()); + this.align = StackAlign.parse(descr.get("align").getAsString()); + this.primary = new ArrayList<>(descr.getAsJsonArray("apply_to") + .asList() + .stream() + .map(x -> builder.getInstance(x.getAsString())) + .toList()); + } + + public void run(int screenW, int screenH) { + switch (this.direction) { + case HORIZONTAL -> stackWidgetsHoriz(screenW); + case VERTICAL -> stackWidgetsVert(screenH); + } + } + + public void stackWidgetsVert(int screenH) { + int compHeight = -ScreenConst.WIDGET_PAD; + for (Widget wid : primary) { + compHeight += wid.getHeight() + 5; + } + + int y = switch (this.align) { + + case TOP -> ScreenConst.getScreenPad(); + case BOT -> (screenH - compHeight) - ScreenConst.getScreenPad(); + default -> (screenH - compHeight) / 2; + }; + + for (Widget wid : primary) { + wid.setY(y); + y += wid.getHeight() + ScreenConst.WIDGET_PAD; + } + } + + public void stackWidgetsHoriz(int screenW) { + int compWidth = -ScreenConst.WIDGET_PAD; + for (Widget wid : primary) { + compWidth += wid.getWidth() + ScreenConst.WIDGET_PAD; + } + + int x = switch (this.align) { + + case LEFT -> ScreenConst.getScreenPad(); + case RIGHT -> (screenW - compWidth) - ScreenConst.getScreenPad(); + default -> (screenW - compWidth) / 2; + }; + + for (Widget wid : primary) { + wid.setX(x); + x += wid.getWidth() + ScreenConst.WIDGET_PAD; + } + } +}
\ No newline at end of file |
