From 92bb441b31cd72d142adee578cc253708cf0101c Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Fri, 26 Jan 2024 00:12:07 -0500 Subject: [PATCH 01/10] Add NamedWaypoint and WaypointCategory --- .../skyblock/dungeon/secrets/Room.java | 4 +- .../dungeon/secrets/SecretWaypoint.java | 15 ++-- .../skyblock/waypoint/Waypoints.java | 25 ++++++ .../de/hysky/skyblocker/utils/PosUtils.java | 5 ++ .../utils/waypoint/NamedWaypoint.java | 79 +++++++++++++++++++ .../skyblocker/utils/waypoint/Waypoint.java | 6 ++ .../utils/waypoint/WaypointCategory.java | 26 ++++++ .../hysky/skyblocker/utils/PosUtilsTest.java | 7 ++ .../utils/waypoint/WaypointCategoryTest.java | 39 +++++++++ .../utils/waypoint/WaypointsTest.java | 20 +++++ 10 files changed, 217 insertions(+), 9 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java create mode 100644 src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java create mode 100644 src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java create mode 100644 src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointCategoryTest.java create mode 100644 src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointsTest.java diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java index e6a8b9d1db..3f07ccf223 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java @@ -208,7 +208,7 @@ protected void addCustomWaypoint(CommandContext conte SecretWaypoint.Category category = SecretWaypoint.Category.CategoryArgumentType.getCategory(context, "category"); Text waypointName = context.getArgument("name", Text.class); addCustomWaypoint(secretIndex, category, waypointName, pos); - context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.stringifiedTranslatable("skyblocker.dungeons.secrets.customWaypointAdded", pos.getX(), pos.getY(), pos.getZ(), name, secretIndex, category, waypointName))); + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.customWaypointAdded", pos.getX(), pos.getY(), pos.getZ(), name, secretIndex, category.asString(), waypointName))); } /** @@ -242,7 +242,7 @@ private void addCustomWaypoint(SecretWaypoint relativeWaypoint) { protected void removeCustomWaypoint(CommandContext context, BlockPos pos) { SecretWaypoint waypoint = removeCustomWaypoint(pos); if (waypoint != null) { - context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.stringifiedTranslatable("skyblocker.dungeons.secrets.customWaypointRemoved", pos.getX(), pos.getY(), pos.getZ(), name, waypoint.secretIndex, waypoint.category, waypoint.name))); + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.customWaypointRemoved", pos.getX(), pos.getY(), pos.getZ(), name, waypoint.secretIndex, waypoint.category.asString(), waypoint.getName()))); } else { context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.customWaypointNotFound", pos.getX(), pos.getY(), pos.getZ(), name))); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java index 42fe6dbe13..0e4f5f1ddc 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java @@ -9,6 +9,7 @@ import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.config.configs.DungeonsConfig; import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.waypoint.NamedWaypoint; import de.hysky.skyblocker.utils.waypoint.Waypoint; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.minecraft.client.MinecraftClient; @@ -29,7 +30,7 @@ import java.util.function.Supplier; import java.util.function.ToDoubleFunction; -public class SecretWaypoint extends Waypoint { +public class SecretWaypoint extends NamedWaypoint { private static final Logger LOGGER = LoggerFactory.getLogger(SecretWaypoint.class); public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( Codec.INT.fieldOf("secretIndex").forGetter(secretWaypoint -> secretWaypoint.secretIndex), @@ -43,8 +44,6 @@ public class SecretWaypoint extends Waypoint { static final Supplier TYPE_SUPPLIER = () -> CONFIG.get().waypointType; final int secretIndex; final Category category; - final Text name; - private final Vec3d centerPos; SecretWaypoint(int secretIndex, JsonObject waypoint, String name, BlockPos pos) { this(secretIndex, Category.get(waypoint), name, pos); @@ -55,11 +54,9 @@ public class SecretWaypoint extends Waypoint { } SecretWaypoint(int secretIndex, Category category, Text name, BlockPos pos) { - super(pos, TYPE_SUPPLIER, category.colorComponents); + super(pos, name, TYPE_SUPPLIER, category.colorComponents); this.secretIndex = secretIndex; this.category = category; - this.name = name; - this.centerPos = pos.toCenterPos(); } static ToDoubleFunction getSquaredDistanceToFunction(Entity entity) { @@ -96,6 +93,11 @@ public boolean equals(Object obj) { return super.equals(obj) || obj instanceof SecretWaypoint other && secretIndex == other.secretIndex && category == other.category && name.equals(other.name) && pos.equals(other.pos); } + @Override + protected boolean shouldRenderName() { + return CONFIG.get().showSecretText; + } + /** * Renders the secret waypoint, including a waypoint through {@link Waypoint#render(WorldRenderContext)}, the name, and the distance from the player. */ @@ -106,7 +108,6 @@ public void render(WorldRenderContext context) { if (CONFIG.get().showSecretText) { Vec3d posUp = centerPos.add(0, 1, 0); - RenderHelper.renderText(context, name, posUp, true); double distance = context.camera().getPos().distanceTo(centerPos); RenderHelper.renderText(context, Text.literal(Math.round(distance) + "m").formatted(Formatting.YELLOW), posUp, 1, MinecraftClient.getInstance().textRenderer.fontHeight + 1, true); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java new file mode 100644 index 0000000000..070cacaa1c --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java @@ -0,0 +1,25 @@ +package de.hysky.skyblocker.skyblock.waypoint; + +import com.google.gson.JsonObject; +import com.mojang.serialization.Codec; +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.utils.waypoint.WaypointCategory; + +import java.util.*; + +public class Waypoints { + Codec> CODEC = WaypointCategory.CODEC.listOf(); + private static final Map waypoints = new HashMap<>(); + + public static Collection fromSkytilsBase64(String base64) { + return fromSkytilsJson(new String(Base64.getDecoder().decode(base64))); + } + + public static Collection fromSkytilsJson(String waypointCategories) { + JsonObject waypointCategoriesJson = SkyblockerMod.GSON.fromJson(waypointCategories, JsonObject.class); + return waypointCategoriesJson.getAsJsonArray("categories").asList().stream() + .map(JsonObject.class::cast) + .map(WaypointCategory::fromSkytilsJson) + .toList(); + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/PosUtils.java b/src/main/java/de/hysky/skyblocker/utils/PosUtils.java index 73ada88924..4ca37a833d 100644 --- a/src/main/java/de/hysky/skyblocker/utils/PosUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/PosUtils.java @@ -1,5 +1,6 @@ package de.hysky.skyblocker.utils; +import com.google.gson.JsonObject; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; @@ -17,6 +18,10 @@ public static BlockPos parsePosString(String posData) { return new BlockPos(Integer.parseInt(posArray[0]), Integer.parseInt(posArray[1]), Integer.parseInt(posArray[2])); } + public static BlockPos parsePosJson(JsonObject posJson) { + return new BlockPos(posJson.get("x").getAsInt(), posJson.get("y").getAsInt(), posJson.get("z").getAsInt()); + } + public static String getPosString(BlockPos blockPos) { return blockPos.getX() + "," + blockPos.getY() + "," + blockPos.getZ(); } diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java new file mode 100644 index 0000000000..f35ad95da3 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java @@ -0,0 +1,79 @@ +package de.hysky.skyblocker.utils.waypoint; + +import com.google.common.primitives.Floats; +import com.google.gson.JsonObject; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.PosUtils; +import de.hysky.skyblocker.utils.render.RenderHelper; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.minecraft.text.Text; +import net.minecraft.text.TextCodecs; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +import java.util.function.Supplier; + +public class NamedWaypoint extends Waypoint { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + BlockPos.CODEC.fieldOf("pos").forGetter(secretWaypoint -> secretWaypoint.pos), + TextCodecs.CODEC.fieldOf("name").forGetter(secretWaypoint -> secretWaypoint.name), + Codec.floatRange(0, 1).listOf().comapFlatMap( + colorComponentsList -> colorComponentsList.size() == 3 ? DataResult.success(Floats.toArray(colorComponentsList)) : DataResult.error(() -> "Expected 3 color components, got " + colorComponentsList.size() + " instead"), + Floats::asList + ).fieldOf("colorComponents").forGetter(secretWaypoint -> secretWaypoint.colorComponents), + Codec.BOOL.fieldOf("shouldRender").forGetter(Waypoint::shouldRender) + ).apply(instance, NamedWaypoint::new)); + protected final Text name; + protected final Vec3d centerPos; + + public NamedWaypoint(BlockPos pos, String name, float[] colorComponents, boolean shouldRender) { + this(pos, Text.of(name), colorComponents, shouldRender); + } + + public NamedWaypoint(BlockPos pos, Text name, float[] colorComponents, boolean shouldRender) { + this(pos, name, () -> SkyblockerConfigManager.get().general.waypoints.waypointType, colorComponents, shouldRender); + } + + public NamedWaypoint(BlockPos pos, String name, Supplier typeSupplier, float[] colorComponents, boolean shouldRender) { + this(pos, Text.of(name), typeSupplier, colorComponents, shouldRender); + } + + public NamedWaypoint(BlockPos pos, Text name, Supplier typeSupplier, float[] colorComponents) { + this(pos, name, typeSupplier, colorComponents, true); + } + + public NamedWaypoint(BlockPos pos, Text name, Supplier typeSupplier, float[] colorComponents, boolean shouldRender) { + super(pos, typeSupplier, colorComponents, DEFAULT_HIGHLIGHT_ALPHA, DEFAULT_LINE_WIDTH, true, shouldRender); + this.name = name; + this.centerPos = pos.toCenterPos(); + } + + public static NamedWaypoint fromSkytilsJson(JsonObject waypointJson) { + int color = waypointJson.get("color").getAsInt(); + return new NamedWaypoint(PosUtils.parsePosJson(waypointJson), waypointJson.get("name").getAsString(), () -> SkyblockerConfigManager.get().general.waypoints.waypointType, new float[]{((color & 0x00FF0000) >> 16) / 255f, ((color & 0x0000FF00) >> 8) / 255f, (color & 0x000000FF) / 255f}, waypointJson.get("enabled").getAsBoolean()); + } + + public Text getName() { + return name; + } + + protected boolean shouldRenderName() { + return true; + } + + @Override + public void render(WorldRenderContext context) { + super.render(context); + if (shouldRenderName()) { + RenderHelper.renderText(context, name, centerPos.add(0, 1, 0), true); + } + } + + @Override + public boolean equals(Object obj) { + return this == obj || obj instanceof NamedWaypoint waypoint && name.equals(waypoint.name); + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java index 622e165846..1a83f1755a 100644 --- a/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java @@ -6,6 +6,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; +import java.util.Arrays; import java.util.function.Supplier; public class Waypoint implements Renderable { @@ -94,6 +95,11 @@ public void render(WorldRenderContext context) { } } + @Override + public boolean equals(Object obj) { + return super.equals(obj) || obj instanceof Waypoint other && pos.equals(other.pos) && typeSupplier.get() == other.typeSupplier.get() && Arrays.equals(colorComponents, other.colorComponents) && alpha == other.alpha && lineWidth == other.lineWidth && throughWalls == other.throughWalls && shouldRender == other.shouldRender; + } + public enum Type { WAYPOINT, OUTLINED_WAYPOINT, diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java new file mode 100644 index 0000000000..0597fc95f6 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java @@ -0,0 +1,26 @@ +package de.hysky.skyblocker.utils.waypoint; + +import com.google.gson.JsonObject; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import java.util.List; + +public record WaypointCategory(String name, String island, List waypoints) { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.STRING.fieldOf("name").forGetter(WaypointCategory::name), + Codec.STRING.fieldOf("island").forGetter(WaypointCategory::island), + NamedWaypoint.CODEC.listOf().fieldOf("waypoints").forGetter(WaypointCategory::waypoints) + ).apply(instance, WaypointCategory::new)); + + public static WaypointCategory fromSkytilsJson(JsonObject waypointCategory) { + return new WaypointCategory( + waypointCategory.get("name").getAsString(), + waypointCategory.get("island").getAsString(), + waypointCategory.getAsJsonArray("waypoints").asList().stream() + .map(JsonObject.class::cast) + .map(NamedWaypoint::fromSkytilsJson) + .toList() + ); + } +} diff --git a/src/test/java/de/hysky/skyblocker/utils/PosUtilsTest.java b/src/test/java/de/hysky/skyblocker/utils/PosUtilsTest.java index 1f433af332..470ea07948 100644 --- a/src/test/java/de/hysky/skyblocker/utils/PosUtilsTest.java +++ b/src/test/java/de/hysky/skyblocker/utils/PosUtilsTest.java @@ -1,5 +1,7 @@ package de.hysky.skyblocker.utils; +import com.google.gson.JsonObject; +import de.hysky.skyblocker.SkyblockerMod; import net.minecraft.util.math.BlockPos; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -10,6 +12,11 @@ void testParsePosString() { Assertions.assertEquals(PosUtils.parsePosString("-1,0,1"), new BlockPos(-1, 0, 1)); } + @Test + void testParsePosJson() { + Assertions.assertEquals(PosUtils.parsePosJson(SkyblockerMod.GSON.fromJson("{\"x\":-1,\"y\":0,\"z\":1}", JsonObject.class)), new BlockPos(-1, 0, 1)); + } + @Test void testGetPosString() { Assertions.assertEquals(PosUtils.getPosString(new BlockPos(-1, 0, 1)), "-1,0,1"); diff --git a/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointCategoryTest.java b/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointCategoryTest.java new file mode 100644 index 0000000000..65304e0c90 --- /dev/null +++ b/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointCategoryTest.java @@ -0,0 +1,39 @@ +package de.hysky.skyblocker.utils.waypoint; + +import com.google.gson.JsonElement; +import com.mojang.serialization.JsonOps; +import de.hysky.skyblocker.SkyblockerMod; +import net.minecraft.Bootstrap; +import net.minecraft.SharedConstants; +import net.minecraft.util.math.BlockPos; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.List; + +public class WaypointCategoryTest { + @BeforeAll + static void beforeAll() { + SharedConstants.createGameVersion(); + Bootstrap.initialize(); + } + + @Test + void testCodecEncode() { + WaypointCategory category = new WaypointCategory("category", "hub", List.of(new NamedWaypoint(BlockPos.ORIGIN, "waypoint", new float[]{0f, 0.5f, 1f}, false), new NamedWaypoint(new BlockPos(-1, 0, 1), "waypoint", new float[]{0f, 0f, 0f}, true))); + Object categoryJson = WaypointCategory.CODEC.encodeStart(JsonOps.INSTANCE, category).result().orElseThrow(); + String expectedJson = "{\"name\":\"category\",\"island\":\"hub\",\"waypoints\":[{\"pos\":[0,0,0],\"name\":\"waypoint\",\"colorComponents\":[0.0,0.5,1.0],\"shouldRender\":false},{\"pos\":[-1,0,1],\"name\":\"waypoint\",\"colorComponents\":[0.0,0.0,0.0],\"shouldRender\":true}]}"; + + Assertions.assertEquals(expectedJson, categoryJson.toString()); + } + + @Test + void testCodecDecode() { + String categoryJson = "{\"name\":\"category\",\"island\":\"hub\",\"waypoints\":[{\"pos\":[0,0,0],\"name\":\"waypoint\",\"colorComponents\":[0.0,0.5,1.0],\"shouldRender\":false},{\"pos\":[-1,0,1],\"name\":\"waypoint\",\"colorComponents\":[0.0,0.0,0.0],\"shouldRender\":true}]}"; + WaypointCategory category = WaypointCategory.CODEC.parse(JsonOps.INSTANCE, SkyblockerMod.GSON.fromJson(categoryJson, JsonElement.class)).result().orElseThrow(); + WaypointCategory expectedCategory = new WaypointCategory("category", "hub", List.of(new NamedWaypoint(BlockPos.ORIGIN, "waypoint", new float[]{0f, 0.5f, 1f}, false), new NamedWaypoint(new BlockPos(-1, 0, 1), "waypoint", new float[]{0f, 0f, 0f}, true))); + + Assertions.assertEquals(expectedCategory, category); + } +} diff --git a/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointsTest.java b/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointsTest.java new file mode 100644 index 0000000000..914702242a --- /dev/null +++ b/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointsTest.java @@ -0,0 +1,20 @@ +package de.hysky.skyblocker.utils.waypoint; + +import de.hysky.skyblocker.skyblock.waypoint.Waypoints; +import net.minecraft.util.math.BlockPos; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Collection; +import java.util.List; + +public class WaypointsTest { + @Test + void testFromSkytilsBase64() { + String waypointCategoriesSkytilsBase64 = "eyJjYXRlZ29yaWVzIjpbeyJuYW1lIjoiY2F0ZWdvcnkiLCJ3YXlwb2ludHMiOlt7Im5hbWUiOiJ3YXlwb2ludCIsIngiOjAsInkiOjAsInoiOjAsImVuYWJsZWQiOmZhbHNlLCJjb2xvciI6MzMwMjMsImFkZGVkQXQiOjF9LHsibmFtZSI6MSwieCI6LTEsInkiOjAsInoiOjEsImVuYWJsZWQiOnRydWUsImNvbG9yIjowLCJhZGRlZEF0IjoxfV0sImlzbGFuZCI6Imh1YiJ9XX0="; + Collection waypointCategories = Waypoints.fromSkytilsBase64(waypointCategoriesSkytilsBase64); + Collection expectedWaypointCategories = List.of(new WaypointCategory("category", "hub", List.of(new NamedWaypoint(BlockPos.ORIGIN, "waypoint", new float[]{0f, 0.5f, 1f}, false), new NamedWaypoint(new BlockPos(-1, 0, 1), "1", new float[]{0f, 0f, 0f}, true)))); + + Assertions.assertEquals(expectedWaypointCategories, waypointCategories); + } +} From 6ad1335dd95e5df4db38e1d8d022a6c2925d6921 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Fri, 26 Jan 2024 21:43:29 -0500 Subject: [PATCH 02/10] Add waypoints loading and saving --- .../skyblock/waypoint/Waypoints.java | 51 ++++++++++++++++++- .../utils/waypoint/WaypointCategory.java | 7 +++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java index 070cacaa1c..1a9d683693 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java @@ -1,16 +1,49 @@ package de.hysky.skyblocker.skyblock.waypoint; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.mojang.serialization.Codec; +import com.mojang.serialization.JsonOps; import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.waypoint.WaypointCategory; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.MinecraftClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.*; public class Waypoints { - Codec> CODEC = WaypointCategory.CODEC.listOf(); + private static final Logger LOGGER = LoggerFactory.getLogger(Waypoints.class); + private static final Codec> CODEC = WaypointCategory.CODEC.listOf(); + private static final Path waypointsFile = FabricLoader.getInstance().getConfigDir().resolve(SkyblockerMod.NAMESPACE).resolve("waypoints.json"); private static final Map waypoints = new HashMap<>(); + public static void init() { + loadWaypoints(); + ClientLifecycleEvents.CLIENT_STOPPING.register(Waypoints::saveWaypoints); + WorldRenderEvents.AFTER_TRANSLUCENT.register(Waypoints::render); + } + + public static void loadWaypoints() { + waypoints.clear(); + try (BufferedReader reader = Files.newBufferedReader(waypointsFile)) { + List waypoints = CODEC.parse(JsonOps.INSTANCE, SkyblockerMod.GSON.fromJson(reader, JsonArray.class)).resultOrPartial(LOGGER::error).orElseThrow(); + waypoints.forEach(waypointCategory -> Waypoints.waypoints.put(waypointCategory.island(), waypointCategory)); + } catch (Exception e) { + LOGGER.error("Encountered exception while loading waypoints", e); + } + } + public static Collection fromSkytilsBase64(String base64) { return fromSkytilsJson(new String(Base64.getDecoder().decode(base64))); } @@ -22,4 +55,20 @@ public static Collection fromSkytilsJson(String waypointCatego .map(WaypointCategory::fromSkytilsJson) .toList(); } + + public static void saveWaypoints(MinecraftClient client) { + try (BufferedWriter writer = Files.newBufferedWriter(waypointsFile)) { + JsonElement waypointsJson = CODEC.encodeStart(JsonOps.INSTANCE, new ArrayList<>(waypoints.values())).resultOrPartial(LOGGER::error).orElseThrow(); + SkyblockerMod.GSON.toJson(waypointsJson, writer); + } catch (Exception e) { + LOGGER.error("Encountered exception while saving waypoints", e); + } + } + + public static void render(WorldRenderContext context) { + WaypointCategory category = waypoints.get(Utils.getLocationRaw()); + if (category != null) { + category.render(context); + } + } } diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java index 0597fc95f6..16a227962f 100644 --- a/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java @@ -3,6 +3,7 @@ import com.google.gson.JsonObject; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import java.util.List; @@ -23,4 +24,10 @@ public static WaypointCategory fromSkytilsJson(JsonObject waypointCategory) { .toList() ); } + + public void render(WorldRenderContext context) { + for (NamedWaypoint waypoint : waypoints) { + waypoint.render(context); + } + } } From bf4034da76adcc7760628d49e518404273efceee Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Sun, 28 Jan 2024 22:14:27 -0500 Subject: [PATCH 03/10] Add waypoints gui --- .../config/categories/GeneralCategory.java | 29 +++++++ .../waypoint/WaypointsListWidget.java | 76 +++++++++++++++++++ .../skyblock/waypoint/WaypointsScreen.java | 37 +++++++++ .../utils/waypoint/NamedWaypoint.java | 4 + .../utils/waypoint/ProfileAwareWaypoint.java | 2 +- .../skyblocker/utils/waypoint/Waypoint.java | 2 +- .../assets/skyblocker/lang/en_us.json | 2 + 7 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsScreen.java diff --git a/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java index 1477d669fc..305c85f2ca 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java @@ -4,6 +4,9 @@ import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.configs.GeneralConfig; import de.hysky.skyblocker.skyblock.shortcut.ShortcutsConfigScreen; +import de.hysky.skyblocker.skyblock.waypoint.WaypointsScreen; +import de.hysky.skyblocker.utils.render.title.TitleContainerConfigScreen; +import de.hysky.skyblocker.utils.waypoint.Waypoint; import dev.isxander.yacl3.api.*; import dev.isxander.yacl3.api.controller.FloatSliderControllerBuilder; import net.minecraft.client.MinecraftClient; @@ -67,6 +70,32 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig .build()) .build()) + //Waypoints + .group(OptionGroup.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.waypoints")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.waypoints.enableWaypoints")) + .binding(defaults.general.waypoints.enableWaypoints, + () -> config.general.waypoints.enableWaypoints, + newValue -> config.general.waypoints.enableWaypoints = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.waypoints.waypointType")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.general.waypoints.waypointType.@Tooltip"), Text.translatable("text.autoconfig.skyblocker.option.general.waypoints.waypointType.generalNote"))) + .binding(defaults.general.waypoints.waypointType, + () -> config.general.waypoints.waypointType, + newValue -> config.general.waypoints.waypointType = newValue) + .controller(ConfigUtils::createEnumCyclingListController) + .build()) + .option(ButtonOption.createBuilder() + .name(Text.translatable("skyblocker.waypoints.config")) + .text(Text.translatable("text.skyblocker.open")) + .action((screen, opt) -> MinecraftClient.getInstance().setScreen(new WaypointsScreen(screen))) + .build()) + .build()) + //Quiver Warning .group(OptionGroup.createBuilder() .name(Text.translatable("skyblocker.config.general.quiverWarning")) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java new file mode 100644 index 0000000000..a1410397c4 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java @@ -0,0 +1,76 @@ +package de.hysky.skyblocker.skyblock.waypoint; + +import de.hysky.skyblocker.utils.waypoint.NamedWaypoint; +import de.hysky.skyblocker.utils.waypoint.WaypointCategory; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.Element; +import net.minecraft.client.gui.Selectable; +import net.minecraft.client.gui.widget.ElementListWidget; +import net.minecraft.util.math.BlockPos; + +import java.util.List; + +public class WaypointsListWidget extends ElementListWidget { + public WaypointsListWidget(MinecraftClient client, int width, int height, int y, int itemHeight) { + super(client, width, height, y, itemHeight); + } + + protected static abstract class AbstractWaypointEntry extends ElementListWidget.Entry { + } + + protected class WaypointCategoryEntry extends AbstractWaypointEntry { + private final WaypointCategory category; + + public WaypointCategoryEntry(WaypointCategory category) { + this.category = category; + } + + @Override + public List selectableChildren() { + return List.of(); + } + + @Override + public List children() { + return List.of(); + } + + @Override + public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { + context.drawTextWithShadow(client.textRenderer, category.name(), width / 2 - 150, y + 5, 0xFFFFFF); + } + } + + protected class WaypointEntry extends AbstractWaypointEntry { + private final WaypointCategoryEntry category; + private final NamedWaypoint waypoint; + + public WaypointEntry(WaypointCategoryEntry category) { + this(category, new NamedWaypoint(BlockPos.ORIGIN, "New Waypoint", new float[]{0f, 1f, 0f})); + } + + public WaypointEntry(WaypointCategoryEntry category, NamedWaypoint waypoint) { + this.category = category; + this.waypoint = waypoint; + } + + @Override + public List selectableChildren() { + return null; + } + + @Override + public List children() { + return null; + } + + @Override + public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { + context.drawTextWithShadow(client.textRenderer, waypoint.getName(), width / 2 - 125, y + 5, 0xFFFFFF); + context.drawTextWithShadow(client.textRenderer, waypoint.pos.toString(), width / 2 - 50, y + 5, 0xFFFFFF); + float[] colorComponents = waypoint.getColorComponents(); + context.drawTextWithShadow(client.textRenderer, String.format("#%02X%02X%02X", (int) (colorComponents[0] * 255), (int) (colorComponents[1] * 255), (int) (colorComponents[2] * 255)), width / 2 + 10, y + 5, 0xFFFFFF); + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsScreen.java new file mode 100644 index 0000000000..f98addda1f --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsScreen.java @@ -0,0 +1,37 @@ +package de.hysky.skyblocker.skyblock.waypoint; + +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.text.Text; + +public class WaypointsScreen extends Screen { + private WaypointsListWidget waypointsListWidget; + private final Screen parent; + + protected WaypointsScreen() { + this(null); + } + + public WaypointsScreen(Screen parent) { + super(Text.translatable("skyblocker.waypoints.config")); + this.parent = parent; + } + + @Override + protected void init() { + super.init(); + waypointsListWidget = addDrawableChild(new WaypointsListWidget(client, width, height - 96, 32, 25)); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + super.render(context, mouseX, mouseY, delta); + context.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 16, 0xFFFFFF); + } + + @SuppressWarnings("DataFlowIssue") + @Override + public void close() { + client.setScreen(parent); + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java index f35ad95da3..db95634bed 100644 --- a/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java @@ -29,6 +29,10 @@ public class NamedWaypoint extends Waypoint { protected final Text name; protected final Vec3d centerPos; + public NamedWaypoint(BlockPos pos, String name, float[] colorComponents) { + this(pos, name, colorComponents, true); + } + public NamedWaypoint(BlockPos pos, String name, float[] colorComponents, boolean shouldRender) { this(pos, Text.of(name), colorComponents, shouldRender); } diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/ProfileAwareWaypoint.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/ProfileAwareWaypoint.java index 7aa99d14e5..7369a2efc4 100644 --- a/src/main/java/de/hysky/skyblocker/utils/waypoint/ProfileAwareWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/ProfileAwareWaypoint.java @@ -38,7 +38,7 @@ public void setMissing() { } @Override - protected float[] getColorComponents() { + public float[] getColorComponents() { return foundProfiles.contains(Utils.getProfile()) ? foundColor : missingColor; } } diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java index 1a83f1755a..75e2edcf38 100644 --- a/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java @@ -72,7 +72,7 @@ public void toggle() { this.shouldRender = !this.shouldRender; } - protected float[] getColorComponents() { + public float[] getColorComponents() { return colorComponents; } diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index dbc60ca0e9..6c663dc17f 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -720,6 +720,8 @@ "skyblocker.shortcuts.new": "New Shortcut", "skyblocker.shortcuts.commandSuggestionTooltip": "Due to limitations of Minecraft, command suggestions will only work after joining a new world.", + "skyblocker.waypoints.config": "Waypoints Config", + "skyblocker.customItemNames.removed": "§fRemoved this item's custom name.", "skyblocker.customItemNames.neverHad": "§fThis item doesn't have a custom name set, but why not add one? ;)", "skyblocker.customItemNames.added": "§fSet a custom name for your currently held item!", From d84b0ce5169c1aea99c6e4842665c6e3598e97d8 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Sun, 4 Feb 2024 16:10:04 -0500 Subject: [PATCH 04/10] Add waypoint adding --- .../de/hysky/skyblocker/SkyblockerMod.java | 2 + .../shortcut/ShortcutsConfigScreen.java | 12 +-- .../skyblock/waypoint/Waypoints.java | 23 +++-- .../waypoint/WaypointsListWidget.java | 90 +++++++++++++++++-- .../skyblock/waypoint/WaypointsScreen.java | 36 +++++++- .../assets/skyblocker/lang/en_us.json | 5 ++ 6 files changed, 144 insertions(+), 24 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index a9aab3b6eb..bdb1766cb9 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -46,6 +46,7 @@ import de.hysky.skyblocker.skyblock.waypoint.MythologicalRitual; import de.hysky.skyblocker.skyblock.waypoint.OrderedWaypoints; import de.hysky.skyblocker.skyblock.waypoint.Relics; +import de.hysky.skyblocker.skyblock.waypoint.Waypoints; import de.hysky.skyblocker.utils.*; import de.hysky.skyblocker.utils.chat.ChatMessageListener; import de.hysky.skyblocker.utils.discord.DiscordRPCManager; @@ -112,6 +113,7 @@ public void onInitializeClient() { ItemTooltip.init(); AccessoriesHelper.init(); WikiLookup.init(); + Waypoints.init(); FairySouls.init(); Relics.init(); MythologicalRitual.init(); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigScreen.java index 120eb099e6..c73836abf2 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigScreen.java @@ -51,22 +51,16 @@ protected void init() { buttonDelete = ButtonWidget.builder(Text.translatable("selectServer.delete"), button -> { if (client != null && shortcutsConfigListWidget.getSelectedOrNull() instanceof ShortcutsConfigListWidget.ShortcutEntry shortcutEntry) { scrollAmount = shortcutsConfigListWidget.getScrollAmount(); - client.setScreen(new ConfirmScreen(this::deleteEntry, Text.translatable("skyblocker.shortcuts.deleteQuestion"), Text.stringifiedTranslatable("skyblocker.shortcuts.deleteWarning", shortcutEntry), Text.translatable("selectServer.deleteButton"), ScreenTexts.CANCEL)); + client.setScreen(new ConfirmScreen(this::deleteEntry, Text.translatable("skyblocker.shortcuts.deleteQuestion"), Text.translatable("skyblocker.shortcuts.deleteWarning", shortcutEntry.toString()), Text.translatable("selectServer.deleteButton"), ScreenTexts.CANCEL)); } }).build(); adder.add(buttonDelete); buttonNew = ButtonWidget.builder(Text.translatable("skyblocker.shortcuts.new"), buttonNew -> shortcutsConfigListWidget.addShortcutAfterSelected()).build(); adder.add(buttonNew); - adder.add(ButtonWidget.builder(ScreenTexts.CANCEL, button -> { - if (client != null) { - close(); - } - }).build()); + adder.add(ButtonWidget.builder(ScreenTexts.CANCEL, button -> close()).build()); buttonDone = ButtonWidget.builder(ScreenTexts.DONE, button -> { shortcutsConfigListWidget.saveShortcuts(); - if (client != null) { - close(); - } + close(); }).tooltip(Tooltip.of(Text.translatable("skyblocker.shortcuts.commandSuggestionTooltip"))).build(); adder.add(buttonDone); gridWidget.refreshPositions(); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java index 1a9d683693..89c3f051aa 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java @@ -1,5 +1,7 @@ package de.hysky.skyblocker.skyblock.waypoint; +import com.google.common.collect.Multimap; +import com.google.common.collect.MultimapBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -20,13 +22,15 @@ import java.io.BufferedWriter; import java.nio.file.Files; import java.nio.file.Path; -import java.util.*; +import java.util.Base64; +import java.util.Collection; +import java.util.List; public class Waypoints { private static final Logger LOGGER = LoggerFactory.getLogger(Waypoints.class); private static final Codec> CODEC = WaypointCategory.CODEC.listOf(); private static final Path waypointsFile = FabricLoader.getInstance().getConfigDir().resolve(SkyblockerMod.NAMESPACE).resolve("waypoints.json"); - private static final Map waypoints = new HashMap<>(); + static final Multimap waypoints = MultimapBuilder.hashKeys().arrayListValues().build(); public static void init() { loadWaypoints(); @@ -40,7 +44,7 @@ public static void loadWaypoints() { List waypoints = CODEC.parse(JsonOps.INSTANCE, SkyblockerMod.GSON.fromJson(reader, JsonArray.class)).resultOrPartial(LOGGER::error).orElseThrow(); waypoints.forEach(waypointCategory -> Waypoints.waypoints.put(waypointCategory.island(), waypointCategory)); } catch (Exception e) { - LOGGER.error("Encountered exception while loading waypoints", e); + LOGGER.error("[Skyblocker Waypoints] Encountered exception while loading waypoints", e); } } @@ -58,17 +62,20 @@ public static Collection fromSkytilsJson(String waypointCatego public static void saveWaypoints(MinecraftClient client) { try (BufferedWriter writer = Files.newBufferedWriter(waypointsFile)) { - JsonElement waypointsJson = CODEC.encodeStart(JsonOps.INSTANCE, new ArrayList<>(waypoints.values())).resultOrPartial(LOGGER::error).orElseThrow(); + JsonElement waypointsJson = CODEC.encodeStart(JsonOps.INSTANCE, List.copyOf(waypoints.values())).resultOrPartial(LOGGER::error).orElseThrow(); SkyblockerMod.GSON.toJson(waypointsJson, writer); + LOGGER.info("[Skyblocker Waypoints] Saved waypoints"); } catch (Exception e) { - LOGGER.error("Encountered exception while saving waypoints", e); + LOGGER.error("[Skyblocker Waypoints] Encountered exception while saving waypoints", e); } } public static void render(WorldRenderContext context) { - WaypointCategory category = waypoints.get(Utils.getLocationRaw()); - if (category != null) { - category.render(context); + Collection categories = waypoints.get(Utils.getLocationRaw()); + for (WaypointCategory category : categories) { + if (category != null) { + category.render(context); + } } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java index a1410397c4..22d3e2bb6b 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java @@ -1,43 +1,123 @@ package de.hysky.skyblocker.skyblock.waypoint; +import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.waypoint.NamedWaypoint; import de.hysky.skyblocker.utils.waypoint.WaypointCategory; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.Element; import net.minecraft.client.gui.Selectable; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.ClickableWidget; import net.minecraft.client.gui.widget.ElementListWidget; +import net.minecraft.text.Text; import net.minecraft.util.math.BlockPos; +import java.util.ArrayList; import java.util.List; +import java.util.Objects; +import java.util.Optional; public class WaypointsListWidget extends ElementListWidget { - public WaypointsListWidget(MinecraftClient client, int width, int height, int y, int itemHeight) { + private final WaypointsScreen screen; + private final String island; + private final List waypoints; + + public WaypointsListWidget(MinecraftClient client, WaypointsScreen screen, int width, int height, int y, int itemHeight) { super(client, width, height, y, itemHeight); + this.screen = screen; + island = Utils.getLocationRaw(); + waypoints = (List) screen.waypoints.get(island); + for (WaypointCategory category : waypoints) { + WaypointCategoryEntry categoryEntry = new WaypointCategoryEntry(category); + addEntry(categoryEntry); + for (NamedWaypoint waypoint : category.waypoints()) { + addEntry(new WaypointEntry(categoryEntry, waypoint)); + } + } + } + + Optional getCategory() { + if (getSelectedOrNull() instanceof WaypointCategoryEntry category) { + return Optional.of(category); + } else if (getSelectedOrNull() instanceof WaypointEntry waypointEntry) { + return Optional.of(waypointEntry.category); + } + return Optional.empty(); + } + + void addWaypointCategoryAfterSelected() { + WaypointCategoryEntry categoryEntry = new WaypointCategoryEntry(); + Optional selectedCategoryEntryOptional = getCategory(); + int index = waypoints.size(); + int entryIndex = children().size(); + if (selectedCategoryEntryOptional.isPresent()) { + WaypointCategoryEntry selectedCategoryEntry = selectedCategoryEntryOptional.get(); + index = waypoints.indexOf(selectedCategoryEntry.category) + 1; + entryIndex = children().indexOf(selectedCategoryEntry) + 1; + while (entryIndex < children().size() && !(children().get(entryIndex) instanceof WaypointCategoryEntry)) { + entryIndex++; + } + } + waypoints.add(index, categoryEntry.category); + children().add(entryIndex, categoryEntry); + } + + @Override + protected boolean isSelectedEntry(int index) { + return Objects.equals(getSelectedOrNull(), children().get(index)); } protected static abstract class AbstractWaypointEntry extends ElementListWidget.Entry { + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + super.mouseClicked(mouseX, mouseY, button); + return true; + } } protected class WaypointCategoryEntry extends AbstractWaypointEntry { private final WaypointCategory category; + private final List children; + private final ButtonWidget buttonNewWaypoint; + + public WaypointCategoryEntry() { + this(new WaypointCategory("New Category", island, new ArrayList<>())); + } public WaypointCategoryEntry(WaypointCategory category) { this.category = category; + buttonNewWaypoint = ButtonWidget.builder(Text.translatable("skyblocker.waypoints.new"), buttonNewWaypoint -> { + WaypointEntry waypointEntry = new WaypointEntry(this); + int entryIndex; + if (getSelectedOrNull() instanceof WaypointEntry selectedWaypointEntry && selectedWaypointEntry.category == this) { + entryIndex = WaypointsListWidget.this.children().indexOf(selectedWaypointEntry) + 1; + } else { + entryIndex = WaypointsListWidget.this.children().indexOf(this) + 1; + while (entryIndex < children().size() && !(children().get(entryIndex) instanceof WaypointCategoryEntry)) { + entryIndex++; + } + } + category.waypoints().add(waypointEntry.waypoint); + WaypointsListWidget.this.children().add(entryIndex, waypointEntry); + }).width(100).build(); + children = List.of(buttonNewWaypoint); } @Override public List selectableChildren() { - return List.of(); + return children; } @Override public List children() { - return List.of(); + return children; } @Override public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { + buttonNewWaypoint.setPosition(x + entryWidth - 30, y + 6); + buttonNewWaypoint.render(context, mouseX, mouseY, tickDelta); context.drawTextWithShadow(client.textRenderer, category.name(), width / 2 - 150, y + 5, 0xFFFFFF); } } @@ -57,12 +137,12 @@ public WaypointEntry(WaypointCategoryEntry category, NamedWaypoint waypoint) { @Override public List selectableChildren() { - return null; + return List.of(); } @Override public List children() { - return null; + return List.of(); } @Override diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsScreen.java index f98addda1f..4f760995aa 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsScreen.java @@ -1,12 +1,22 @@ package de.hysky.skyblocker.skyblock.waypoint; +import com.google.common.collect.Multimap; +import com.google.common.collect.MultimapBuilder; +import de.hysky.skyblocker.utils.waypoint.WaypointCategory; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.GridWidget; +import net.minecraft.client.gui.widget.SimplePositioningWidget; +import net.minecraft.screen.ScreenTexts; import net.minecraft.text.Text; public class WaypointsScreen extends Screen { - private WaypointsListWidget waypointsListWidget; private final Screen parent; + final Multimap waypoints = MultimapBuilder.hashKeys().arrayListValues().build(Waypoints.waypoints); // TODO deep copy + private WaypointsListWidget waypointsListWidget; + private ButtonWidget buttonNew; + private ButtonWidget buttonDone; protected WaypointsScreen() { this(null); @@ -20,7 +30,21 @@ public WaypointsScreen(Screen parent) { @Override protected void init() { super.init(); - waypointsListWidget = addDrawableChild(new WaypointsListWidget(client, width, height - 96, 32, 25)); + waypointsListWidget = addDrawableChild(new WaypointsListWidget(client, this, width, height - 96, 32, 25)); + GridWidget gridWidget = new GridWidget(); + gridWidget.getMainPositioner().marginX(5).marginY(2); + GridWidget.Adder adder = gridWidget.createAdder(2); + adder.add(ButtonWidget.builder(Text.translatable("skyblocker.waypoints.share"), buttonShare -> {}).build()); + buttonNew = adder.add(ButtonWidget.builder(Text.translatable("skyblocker.waypoints.newCategory"), buttonNew -> waypointsListWidget.addWaypointCategoryAfterSelected()).build()); + adder.add(ButtonWidget.builder(ScreenTexts.CANCEL, button -> close()).build()); + buttonDone = adder.add(ButtonWidget.builder(ScreenTexts.DONE, button -> { + saveWaypoints(); + close(); + }).build()); + gridWidget.refreshPositions(); + SimplePositioningWidget.setPos(gridWidget, 0, this.height - 64, this.width, 64); + gridWidget.forEachChild(this::addDrawableChild); + updateButtons(); } @Override @@ -29,6 +53,14 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) { context.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 16, 0xFFFFFF); } + private void saveWaypoints() { + Waypoints.waypoints.clear(); + Waypoints.waypoints.putAll(waypoints); + Waypoints.saveWaypoints(client); + } + + private void updateButtons() {} + @SuppressWarnings("DataFlowIssue") @Override public void close() { diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 6c663dc17f..a212ddfa53 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -721,6 +721,11 @@ "skyblocker.shortcuts.commandSuggestionTooltip": "Due to limitations of Minecraft, command suggestions will only work after joining a new world.", "skyblocker.waypoints.config": "Waypoints Config", + "skyblocker.waypoints.newCategory": "New Waypoint Category", + "skyblocker.waypoints.new": "New Waypoint", + "skyblocker.waypoints.share": "Share", + "skyblocker.waypoints.deleteQuestion": "Are you sure you want to remove this waypoint?", + "skyblocker.waypoints.deleteWarning": "Waypoint '%s' will be lost forever! (A long time!)", "skyblocker.customItemNames.removed": "§fRemoved this item's custom name.", "skyblocker.customItemNames.neverHad": "§fThis item doesn't have a custom name set, but why not add one? ;)", From f6ba429409ac73ee45992fd80e527c96b39e52e3 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Sun, 4 Feb 2024 17:35:52 -0500 Subject: [PATCH 05/10] Add waypoint deleting --- .../shortcut/ShortcutsConfigListWidget.java | 6 ++ .../shortcut/ShortcutsConfigScreen.java | 5 +- .../waypoint/WaypointsListWidget.java | 56 ++++++++++++++----- .../skyblock/waypoint/WaypointsScreen.java | 5 +- .../utils/waypoint/WaypointCategory.java | 5 ++ 5 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigListWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigListWidget.java index 3918037f32..a6b5e62ded 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigListWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigListWidget.java @@ -1,5 +1,6 @@ package de.hysky.skyblocker.skyblock.shortcut; +import de.hysky.skyblocker.debug.Debug; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.Element; @@ -76,6 +77,11 @@ protected void updatePositions() { } } + @Override + protected boolean isSelectedEntry(int index) { + return Debug.debugEnabled() ? Objects.equals(getSelectedOrNull(), children().get(index)) : super.isSelectedEntry(index); + } + @Override protected boolean removeEntry(AbstractShortcutEntry entry) { return super.removeEntry(entry); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigScreen.java index c73836abf2..9d411fa441 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigScreen.java @@ -11,7 +11,6 @@ import net.minecraft.text.Text; public class ShortcutsConfigScreen extends Screen { - private ShortcutsConfigListWidget shortcutsConfigListWidget; private ButtonWidget buttonDelete; private ButtonWidget buttonNew; @@ -41,14 +40,14 @@ protected void init() { shortcutsConfigListWidget.setDimensions(width, height - 96); shortcutsConfigListWidget.updatePositions(); } else { - shortcutsConfigListWidget = new ShortcutsConfigListWidget(client, this, width, height - 96, 32, 25); + shortcutsConfigListWidget = new ShortcutsConfigListWidget(client, this, width, height - 96, 32, 24); initialized = true; } addDrawableChild(shortcutsConfigListWidget); GridWidget gridWidget = new GridWidget(); gridWidget.getMainPositioner().marginX(5).marginY(2); GridWidget.Adder adder = gridWidget.createAdder(2); - buttonDelete = ButtonWidget.builder(Text.translatable("selectServer.delete"), button -> { + buttonDelete = ButtonWidget.builder(Text.translatable("selectServer.deleteButton"), button -> { if (client != null && shortcutsConfigListWidget.getSelectedOrNull() instanceof ShortcutsConfigListWidget.ShortcutEntry shortcutEntry) { scrollAmount = shortcutsConfigListWidget.getScrollAmount(); client.setScreen(new ConfirmScreen(this::deleteEntry, Text.translatable("skyblocker.shortcuts.deleteQuestion"), Text.translatable("skyblocker.shortcuts.deleteWarning", shortcutEntry.toString()), Text.translatable("selectServer.deleteButton"), ScreenTexts.CANCEL)); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java index 22d3e2bb6b..7a01a494fe 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java @@ -1,5 +1,6 @@ package de.hysky.skyblocker.skyblock.waypoint; +import de.hysky.skyblocker.debug.Debug; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.waypoint.NamedWaypoint; import de.hysky.skyblocker.utils.waypoint.WaypointCategory; @@ -37,6 +38,16 @@ public WaypointsListWidget(MinecraftClient client, WaypointsScreen screen, int w } } + @Override + public int getRowWidth() { + return super.getRowWidth() + 100; + } + + @Override + protected int getScrollbarPositionX() { + return super.getScrollbarPositionX() + 50; + } + Optional getCategory() { if (getSelectedOrNull() instanceof WaypointCategoryEntry category) { return Optional.of(category); @@ -65,21 +76,17 @@ void addWaypointCategoryAfterSelected() { @Override protected boolean isSelectedEntry(int index) { - return Objects.equals(getSelectedOrNull(), children().get(index)); + return Debug.debugEnabled() ? Objects.equals(getSelectedOrNull(), children().get(index)) : super.isSelectedEntry(index); } protected static abstract class AbstractWaypointEntry extends ElementListWidget.Entry { - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - super.mouseClicked(mouseX, mouseY, button); - return true; - } } protected class WaypointCategoryEntry extends AbstractWaypointEntry { private final WaypointCategory category; private final List children; private final ButtonWidget buttonNewWaypoint; + private final ButtonWidget buttonDelete; public WaypointCategoryEntry() { this(new WaypointCategory("New Category", island, new ArrayList<>())); @@ -94,14 +101,22 @@ public WaypointCategoryEntry(WaypointCategory category) { entryIndex = WaypointsListWidget.this.children().indexOf(selectedWaypointEntry) + 1; } else { entryIndex = WaypointsListWidget.this.children().indexOf(this) + 1; - while (entryIndex < children().size() && !(children().get(entryIndex) instanceof WaypointCategoryEntry)) { + while (entryIndex < WaypointsListWidget.this.children().size() && !(WaypointsListWidget.this.children().get(entryIndex) instanceof WaypointCategoryEntry)) { entryIndex++; } } category.waypoints().add(waypointEntry.waypoint); WaypointsListWidget.this.children().add(entryIndex, waypointEntry); - }).width(100).build(); - children = List.of(buttonNewWaypoint); + }).width(75).build(); + buttonDelete = ButtonWidget.builder(Text.translatable("selectServer.deleteButton"), buttonDelete -> { + int entryIndex = WaypointsListWidget.this.children().indexOf(this) + 1; + while (entryIndex < WaypointsListWidget.this.children().size() && !(WaypointsListWidget.this.children().get(entryIndex) instanceof WaypointCategoryEntry)) { + WaypointsListWidget.this.children().remove(entryIndex); + } + WaypointsListWidget.this.children().remove(this); + waypoints.remove(category); + }).width(50).build(); + children = List.of(buttonNewWaypoint, buttonDelete); } @Override @@ -116,15 +131,19 @@ public List children() { @Override public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - buttonNewWaypoint.setPosition(x + entryWidth - 30, y + 6); - buttonNewWaypoint.render(context, mouseX, mouseY, tickDelta); context.drawTextWithShadow(client.textRenderer, category.name(), width / 2 - 150, y + 5, 0xFFFFFF); + buttonNewWaypoint.setPosition(x + entryWidth - 133, y); + buttonDelete.setPosition(x + entryWidth - 54, y); + buttonNewWaypoint.render(context, mouseX, mouseY, tickDelta); + buttonDelete.render(context, mouseX, mouseY, tickDelta); } } protected class WaypointEntry extends AbstractWaypointEntry { private final WaypointCategoryEntry category; private final NamedWaypoint waypoint; + private final List children; + private final ButtonWidget buttonDelete; public WaypointEntry(WaypointCategoryEntry category) { this(category, new NamedWaypoint(BlockPos.ORIGIN, "New Waypoint", new float[]{0f, 1f, 0f})); @@ -133,24 +152,31 @@ public WaypointEntry(WaypointCategoryEntry category) { public WaypointEntry(WaypointCategoryEntry category, NamedWaypoint waypoint) { this.category = category; this.waypoint = waypoint; + buttonDelete = ButtonWidget.builder(Text.translatable("selectServer.deleteButton"), button -> { + category.category.waypoints().remove(waypoint); + WaypointsListWidget.this.children().remove(this); + }).width(50).build(); + children = List.of(buttonDelete); } @Override public List selectableChildren() { - return List.of(); + return children; } @Override public List children() { - return List.of(); + return children; } @Override public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { context.drawTextWithShadow(client.textRenderer, waypoint.getName(), width / 2 - 125, y + 5, 0xFFFFFF); - context.drawTextWithShadow(client.textRenderer, waypoint.pos.toString(), width / 2 - 50, y + 5, 0xFFFFFF); + context.drawTextWithShadow(client.textRenderer, waypoint.pos.toShortString(), width / 2 - 25, y + 5, 0xFFFFFF); float[] colorComponents = waypoint.getColorComponents(); - context.drawTextWithShadow(client.textRenderer, String.format("#%02X%02X%02X", (int) (colorComponents[0] * 255), (int) (colorComponents[1] * 255), (int) (colorComponents[2] * 255)), width / 2 + 10, y + 5, 0xFFFFFF); + context.drawTextWithShadow(client.textRenderer, String.format("#%02X%02X%02X", (int) (colorComponents[0] * 255), (int) (colorComponents[1] * 255), (int) (colorComponents[2] * 255)), width / 2 + 25, y + 5, 0xFFFFFF); + buttonDelete.setPosition(x + entryWidth - 54, y); + buttonDelete.render(context, mouseX, mouseY, tickDelta); } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsScreen.java index 4f760995aa..9f82f7a2e1 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsScreen.java @@ -13,7 +13,7 @@ public class WaypointsScreen extends Screen { private final Screen parent; - final Multimap waypoints = MultimapBuilder.hashKeys().arrayListValues().build(Waypoints.waypoints); // TODO deep copy + final Multimap waypoints = MultimapBuilder.hashKeys().arrayListValues().build(); private WaypointsListWidget waypointsListWidget; private ButtonWidget buttonNew; private ButtonWidget buttonDone; @@ -25,12 +25,13 @@ protected WaypointsScreen() { public WaypointsScreen(Screen parent) { super(Text.translatable("skyblocker.waypoints.config")); this.parent = parent; + Waypoints.waypoints.forEach((island, category) -> waypoints.put(island, new WaypointCategory(category))); } @Override protected void init() { super.init(); - waypointsListWidget = addDrawableChild(new WaypointsListWidget(client, this, width, height - 96, 32, 25)); + waypointsListWidget = addDrawableChild(new WaypointsListWidget(client, this, width, height - 96, 32, 24)); GridWidget gridWidget = new GridWidget(); gridWidget.getMainPositioner().marginX(5).marginY(2); GridWidget.Adder adder = gridWidget.createAdder(2); diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java index 16a227962f..d31455f6f3 100644 --- a/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java @@ -5,6 +5,7 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import java.util.ArrayList; import java.util.List; public record WaypointCategory(String name, String island, List waypoints) { @@ -14,6 +15,10 @@ public record WaypointCategory(String name, String island, List w NamedWaypoint.CODEC.listOf().fieldOf("waypoints").forGetter(WaypointCategory::waypoints) ).apply(instance, WaypointCategory::new)); + public WaypointCategory(WaypointCategory waypointCategory) { + this(waypointCategory.name(), waypointCategory.island(), new ArrayList<>(waypointCategory.waypoints())); + } + public static WaypointCategory fromSkytilsJson(JsonObject waypointCategory) { return new WaypointCategory( waypointCategory.get("name").getAsString(), From 7675f7569b381c8b9cbf36e2e69e716737455069 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Fri, 8 Mar 2024 19:35:56 -0500 Subject: [PATCH 06/10] Update Skytils format to codecs --- .../skyblock/waypoint/Waypoints.java | 21 ++++++++++++------- .../utils/waypoint/NamedWaypoint.java | 16 +++++++++----- .../utils/waypoint/WaypointCategory.java | 17 +++++---------- .../utils/waypoint/WaypointsTest.java | 9 ++++++++ 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java index 89c3f051aa..8eeae2aa37 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java @@ -29,6 +29,7 @@ public class Waypoints { private static final Logger LOGGER = LoggerFactory.getLogger(Waypoints.class); private static final Codec> CODEC = WaypointCategory.CODEC.listOf(); + private static final Codec> SKYTILS_CODEC = WaypointCategory.SKYTILS_CODEC.listOf(); private static final Path waypointsFile = FabricLoader.getInstance().getConfigDir().resolve(SkyblockerMod.NAMESPACE).resolve("waypoints.json"); static final Multimap waypoints = MultimapBuilder.hashKeys().arrayListValues().build(); @@ -48,16 +49,22 @@ public static void loadWaypoints() { } } - public static Collection fromSkytilsBase64(String base64) { + public static List fromSkytilsBase64(String base64) { return fromSkytilsJson(new String(Base64.getDecoder().decode(base64))); } - public static Collection fromSkytilsJson(String waypointCategories) { - JsonObject waypointCategoriesJson = SkyblockerMod.GSON.fromJson(waypointCategories, JsonObject.class); - return waypointCategoriesJson.getAsJsonArray("categories").asList().stream() - .map(JsonObject.class::cast) - .map(WaypointCategory::fromSkytilsJson) - .toList(); + public static List fromSkytilsJson(String waypointCategories) { + return SKYTILS_CODEC.parse(JsonOps.INSTANCE, SkyblockerMod.GSON.fromJson(waypointCategories, JsonObject.class).getAsJsonArray("categories")).resultOrPartial(LOGGER::error).orElseThrow(); + } + + public static String toSkytilsBase64(Collection waypointCategories) { + return Base64.getEncoder().encodeToString(toSkytilsJson(waypointCategories).getBytes()); + } + + public static String toSkytilsJson(Collection waypointCategories) { + JsonObject waypointCategoriesJson = new JsonObject(); + waypointCategoriesJson.add("categories", SKYTILS_CODEC.encodeStart(JsonOps.INSTANCE, List.copyOf(waypointCategories)).resultOrPartial(LOGGER::error).orElseThrow()); + return SkyblockerMod.GSON.toJson(waypointCategoriesJson); } public static void saveWaypoints(MinecraftClient client) { diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java index db95634bed..f959de78c6 100644 --- a/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java @@ -1,12 +1,11 @@ package de.hysky.skyblocker.utils.waypoint; import com.google.common.primitives.Floats; -import com.google.gson.JsonObject; +import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.codecs.RecordCodecBuilder; import de.hysky.skyblocker.config.SkyblockerConfigManager; -import de.hysky.skyblocker.utils.PosUtils; import de.hysky.skyblocker.utils.render.RenderHelper; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.minecraft.text.Text; @@ -26,6 +25,14 @@ public class NamedWaypoint extends Waypoint { ).fieldOf("colorComponents").forGetter(secretWaypoint -> secretWaypoint.colorComponents), Codec.BOOL.fieldOf("shouldRender").forGetter(Waypoint::shouldRender) ).apply(instance, NamedWaypoint::new)); + public static final Codec SKYTILS_CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.INT.fieldOf("x").forGetter(waypoint -> waypoint.pos.getX()), + Codec.INT.fieldOf("y").forGetter(waypoint -> waypoint.pos.getY()), + Codec.INT.fieldOf("z").forGetter(waypoint -> waypoint.pos.getZ()), + Codec.either(Codec.STRING, Codec.INT).xmap(either -> either.map(str -> str, Object::toString), Either::left).fieldOf("name").forGetter(waypoint -> waypoint.name.getString()), + Codec.INT.fieldOf("color").forGetter(waypoint -> (int) (waypoint.colorComponents[0] * 255) << 16 | (int) (waypoint.colorComponents[1] * 255) << 8 | (int) (waypoint.colorComponents[2] * 255)), + Codec.BOOL.fieldOf("enabled").forGetter(Waypoint::shouldRender) + ).apply(instance, NamedWaypoint::fromSkytils)); protected final Text name; protected final Vec3d centerPos; @@ -55,9 +62,8 @@ public NamedWaypoint(BlockPos pos, Text name, Supplier typeSupplier, float this.centerPos = pos.toCenterPos(); } - public static NamedWaypoint fromSkytilsJson(JsonObject waypointJson) { - int color = waypointJson.get("color").getAsInt(); - return new NamedWaypoint(PosUtils.parsePosJson(waypointJson), waypointJson.get("name").getAsString(), () -> SkyblockerConfigManager.get().general.waypoints.waypointType, new float[]{((color & 0x00FF0000) >> 16) / 255f, ((color & 0x0000FF00) >> 8) / 255f, (color & 0x000000FF) / 255f}, waypointJson.get("enabled").getAsBoolean()); + public static NamedWaypoint fromSkytils(int x, int y, int z, String name, int color, boolean enabled) { + return new NamedWaypoint(new BlockPos(x, y, z), name, new float[]{((color & 0x00FF0000) >> 16) / 255f, ((color & 0x0000FF00) >> 8) / 255f, (color & 0x000000FF) / 255f}, enabled); } public Text getName() { diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java index d31455f6f3..b1ac6135bc 100644 --- a/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java @@ -1,6 +1,5 @@ package de.hysky.skyblocker.utils.waypoint; -import com.google.gson.JsonObject; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; @@ -14,22 +13,16 @@ public record WaypointCategory(String name, String island, List w Codec.STRING.fieldOf("island").forGetter(WaypointCategory::island), NamedWaypoint.CODEC.listOf().fieldOf("waypoints").forGetter(WaypointCategory::waypoints) ).apply(instance, WaypointCategory::new)); + public static final Codec SKYTILS_CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.STRING.fieldOf("name").forGetter(WaypointCategory::name), + Codec.STRING.fieldOf("island").forGetter(WaypointCategory::island), + NamedWaypoint.SKYTILS_CODEC.listOf().fieldOf("waypoints").forGetter(WaypointCategory::waypoints) + ).apply(instance, WaypointCategory::new)); public WaypointCategory(WaypointCategory waypointCategory) { this(waypointCategory.name(), waypointCategory.island(), new ArrayList<>(waypointCategory.waypoints())); } - public static WaypointCategory fromSkytilsJson(JsonObject waypointCategory) { - return new WaypointCategory( - waypointCategory.get("name").getAsString(), - waypointCategory.get("island").getAsString(), - waypointCategory.getAsJsonArray("waypoints").asList().stream() - .map(JsonObject.class::cast) - .map(NamedWaypoint::fromSkytilsJson) - .toList() - ); - } - public void render(WorldRenderContext context) { for (NamedWaypoint waypoint : waypoints) { waypoint.render(context); diff --git a/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointsTest.java b/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointsTest.java index 914702242a..ad237718a4 100644 --- a/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointsTest.java +++ b/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointsTest.java @@ -17,4 +17,13 @@ void testFromSkytilsBase64() { Assertions.assertEquals(expectedWaypointCategories, waypointCategories); } + + @Test + void testToSkytilsBase64() { + Collection waypointCategories = List.of(new WaypointCategory("category", "hub", List.of(new NamedWaypoint(BlockPos.ORIGIN, "waypoint", new float[]{0f, 0.5f, 1f}, false), new NamedWaypoint(new BlockPos(-1, 0, 1), "1", new float[]{0f, 0f, 0f}, true)))); + String waypointCategoriesSkytilsBase64 = Waypoints.toSkytilsBase64(waypointCategories); + String expectedWaypointCategoriesSkytilsBase64 = "ewogICJjYXRlZ29yaWVzIjogWwogICAgewogICAgICAibmFtZSI6ICJjYXRlZ29yeSIsCiAgICAgICJpc2xhbmQiOiAiaHViIiwKICAgICAgIndheXBvaW50cyI6IFsKICAgICAgICB7CiAgICAgICAgICAibmFtZSI6ICJ3YXlwb2ludCIsCiAgICAgICAgICAiY29sb3IiOiAzMjc2NywKICAgICAgICAgICJlbmFibGVkIjogZmFsc2UsCiAgICAgICAgICAieCI6IDAsCiAgICAgICAgICAieSI6IDAsCiAgICAgICAgICAieiI6IDAKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJuYW1lIjogIjEiLAogICAgICAgICAgImNvbG9yIjogMCwKICAgICAgICAgICJlbmFibGVkIjogdHJ1ZSwKICAgICAgICAgICJ4IjogLTEsCiAgICAgICAgICAieSI6IDAsCiAgICAgICAgICAieiI6IDEKICAgICAgICB9CiAgICAgIF0KICAgIH0KICBdCn0="; + + Assertions.assertEquals(expectedWaypointCategoriesSkytilsBase64, waypointCategoriesSkytilsBase64); + } } From e9bd404a36ce3a69e62e97986d42e7f3635ab67d Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Mon, 13 May 2024 14:15:47 -0400 Subject: [PATCH 07/10] Sync with latest --- .../config/categories/GeneralCategory.java | 29 ------------------- .../categories/UIAndVisualsCategory.java | 8 ++++- .../skyblock/dungeon/secrets/Room.java | 2 +- .../dungeon/secrets/SecretWaypoint.java | 1 - .../shortcut/ShortcutsConfigScreen.java | 2 +- 5 files changed, 9 insertions(+), 33 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java index 305c85f2ca..1477d669fc 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java @@ -4,9 +4,6 @@ import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.configs.GeneralConfig; import de.hysky.skyblocker.skyblock.shortcut.ShortcutsConfigScreen; -import de.hysky.skyblocker.skyblock.waypoint.WaypointsScreen; -import de.hysky.skyblocker.utils.render.title.TitleContainerConfigScreen; -import de.hysky.skyblocker.utils.waypoint.Waypoint; import dev.isxander.yacl3.api.*; import dev.isxander.yacl3.api.controller.FloatSliderControllerBuilder; import net.minecraft.client.MinecraftClient; @@ -70,32 +67,6 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig .build()) .build()) - //Waypoints - .group(OptionGroup.createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.general.waypoints")) - .collapsed(true) - .option(Option.createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.general.waypoints.enableWaypoints")) - .binding(defaults.general.waypoints.enableWaypoints, - () -> config.general.waypoints.enableWaypoints, - newValue -> config.general.waypoints.enableWaypoints = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) - .option(Option.createBuilder() - .name(Text.translatable("text.autoconfig.skyblocker.option.general.waypoints.waypointType")) - .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.general.waypoints.waypointType.@Tooltip"), Text.translatable("text.autoconfig.skyblocker.option.general.waypoints.waypointType.generalNote"))) - .binding(defaults.general.waypoints.waypointType, - () -> config.general.waypoints.waypointType, - newValue -> config.general.waypoints.waypointType = newValue) - .controller(ConfigUtils::createEnumCyclingListController) - .build()) - .option(ButtonOption.createBuilder() - .name(Text.translatable("skyblocker.waypoints.config")) - .text(Text.translatable("text.skyblocker.open")) - .action((screen, opt) -> MinecraftClient.getInstance().setScreen(new WaypointsScreen(screen))) - .build()) - .build()) - //Quiver Warning .group(OptionGroup.createBuilder() .name(Text.translatable("skyblocker.config.general.quiverWarning")) diff --git a/src/main/java/de/hysky/skyblocker/config/categories/UIAndVisualsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/UIAndVisualsCategory.java index 369a9a90b3..a2a0f81525 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/UIAndVisualsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/UIAndVisualsCategory.java @@ -3,6 +3,7 @@ import de.hysky.skyblocker.config.ConfigUtils; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.skyblock.fancybars.StatusBarsConfigScreen; +import de.hysky.skyblocker.skyblock.waypoint.WaypointsScreen; import de.hysky.skyblocker.utils.render.title.TitleContainerConfigScreen; import de.hysky.skyblocker.config.configs.UIAndVisualsConfig; import de.hysky.skyblocker.utils.waypoint.Waypoint; @@ -226,12 +227,17 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig .option(Option.createBuilder() .name(Text.translatable("skyblocker.config.uiAndVisuals.waypoints.waypointType")) .description(OptionDescription.of(Text.translatable("skyblocker.config.uiAndVisuals.waypoints.waypointType.@Tooltip"), - Text.translatable("skyblocker.config.uiAndVisuals.waypoints.waypointType"))) + Text.translatable("skyblocker.config.uiAndVisuals.waypoints.waypointType.generalNote"))) .binding(defaults.uiAndVisuals.waypoints.waypointType, () -> config.uiAndVisuals.waypoints.waypointType, newValue -> config.uiAndVisuals.waypoints.waypointType = newValue) .controller(ConfigUtils::createEnumCyclingListController) .build()) + .option(ButtonOption.createBuilder() + .name(Text.translatable("skyblocker.waypoints.config")) + .text(Text.translatable("text.skyblocker.open")) + .action((screen, opt) -> MinecraftClient.getInstance().setScreen(new WaypointsScreen(screen))) + .build()) .build()) //Teleport Overlays diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java index 3f07ccf223..c0e549040e 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java @@ -208,7 +208,7 @@ protected void addCustomWaypoint(CommandContext conte SecretWaypoint.Category category = SecretWaypoint.Category.CategoryArgumentType.getCategory(context, "category"); Text waypointName = context.getArgument("name", Text.class); addCustomWaypoint(secretIndex, category, waypointName, pos); - context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.dungeons.secrets.customWaypointAdded", pos.getX(), pos.getY(), pos.getZ(), name, secretIndex, category.asString(), waypointName))); + context.getSource().sendFeedback(Constants.PREFIX.get().append(Text.stringifiedTranslatable("skyblocker.dungeons.secrets.customWaypointAdded", pos.getX(), pos.getY(), pos.getZ(), name, secretIndex, category, waypointName))); } /** diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java index 0e4f5f1ddc..3779a66e78 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretWaypoint.java @@ -5,7 +5,6 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.JsonOps; import com.mojang.serialization.codecs.RecordCodecBuilder; -import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.config.configs.DungeonsConfig; import de.hysky.skyblocker.utils.render.RenderHelper; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigScreen.java index 9d411fa441..66735511ab 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/shortcut/ShortcutsConfigScreen.java @@ -50,7 +50,7 @@ protected void init() { buttonDelete = ButtonWidget.builder(Text.translatable("selectServer.deleteButton"), button -> { if (client != null && shortcutsConfigListWidget.getSelectedOrNull() instanceof ShortcutsConfigListWidget.ShortcutEntry shortcutEntry) { scrollAmount = shortcutsConfigListWidget.getScrollAmount(); - client.setScreen(new ConfirmScreen(this::deleteEntry, Text.translatable("skyblocker.shortcuts.deleteQuestion"), Text.translatable("skyblocker.shortcuts.deleteWarning", shortcutEntry.toString()), Text.translatable("selectServer.deleteButton"), ScreenTexts.CANCEL)); + client.setScreen(new ConfirmScreen(this::deleteEntry, Text.translatable("skyblocker.shortcuts.deleteQuestion"), Text.stringifiedTranslatable("skyblocker.shortcuts.deleteWarning", shortcutEntry), Text.translatable("selectServer.deleteButton"), ScreenTexts.CANCEL)); } }).build(); adder.add(buttonDelete); From 7bf3958477c179185f9532cebffc36f218aa3bd8 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Tue, 14 May 2024 22:58:56 -0400 Subject: [PATCH 08/10] Port waypoints config screens --- .../accessors/CheckboxWidgetAccessor.java | 11 + .../waypoint/AbstractWaypointsScreen.java | 65 ++++++ .../skyblock/waypoint/DropdownWidget.java | 126 +++++++++++ .../skyblock/waypoint/OrderedWaypoints.java | 2 +- .../skyblock/waypoint/Waypoints.java | 72 +++++-- .../waypoint/WaypointsListWidget.java | 195 ++++++++++++++---- .../skyblock/waypoint/WaypointsScreen.java | 46 +++-- .../waypoint/WaypointsShareScreen.java | 86 ++++++++ .../utils/waypoint/NamedWaypoint.java | 65 ++++-- .../skyblocker/utils/waypoint/Waypoint.java | 40 +++- .../utils/waypoint/WaypointCategory.java | 20 +- .../assets/skyblocker/lang/en_us.json | 15 ++ src/main/resources/skyblocker.mixins.json | 1 + .../utils/waypoint/WaypointCategoryTest.java | 4 +- .../utils/waypoint/WaypointsTest.java | 106 +++++++++- 15 files changed, 747 insertions(+), 107 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/mixins/accessors/CheckboxWidgetAccessor.java create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/waypoint/AbstractWaypointsScreen.java create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/waypoint/DropdownWidget.java create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsShareScreen.java diff --git a/src/main/java/de/hysky/skyblocker/mixins/accessors/CheckboxWidgetAccessor.java b/src/main/java/de/hysky/skyblocker/mixins/accessors/CheckboxWidgetAccessor.java new file mode 100644 index 0000000000..5ec4a8e8c9 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/mixins/accessors/CheckboxWidgetAccessor.java @@ -0,0 +1,11 @@ +package de.hysky.skyblocker.mixins.accessors; + +import net.minecraft.client.gui.widget.CheckboxWidget; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(CheckboxWidget.class) +public interface CheckboxWidgetAccessor { + @Accessor + void setChecked(boolean checked); +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/AbstractWaypointsScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/AbstractWaypointsScreen.java new file mode 100644 index 0000000000..932bc144f7 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/AbstractWaypointsScreen.java @@ -0,0 +1,65 @@ +package de.hysky.skyblocker.skyblock.waypoint; + +import com.google.common.collect.Multimap; +import com.google.common.collect.MultimapBuilder; +import de.hysky.skyblocker.utils.Location; +import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.waypoint.NamedWaypoint; +import de.hysky.skyblocker.utils.waypoint.WaypointCategory; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.text.Text; + +import java.util.Arrays; + +public abstract class AbstractWaypointsScreen extends Screen { + protected final T parent; + protected final Multimap waypoints; + protected String island; + protected WaypointsListWidget waypointsListWidget; + protected DropdownWidget islandWidget; + + public AbstractWaypointsScreen(Text title, T parent) { + this(title, parent, MultimapBuilder.hashKeys().arrayListValues().build()); + } + + public AbstractWaypointsScreen(Text title, T parent, Multimap waypoints) { + this(title, parent, waypoints, Utils.getLocationRaw()); + } + + public AbstractWaypointsScreen(Text title, T parent, Multimap waypoints, String island) { + super(title); + this.parent = parent; + this.waypoints = waypoints; + this.island = island; + } + + @Override + protected void init() { + super.init(); + waypointsListWidget = addDrawableChild(new WaypointsListWidget(client, this, width, height - 96, 32, 24)); + islandWidget = addDrawableChild(new DropdownWidget<>(client, width - 160, 8, 150, Arrays.asList(Location.values()), this::islandChanged, Location.from(island))); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (islandWidget.mouseClicked(mouseX, mouseY, button)) { + return true; + } + boolean mouseClicked = super.mouseClicked(mouseX, mouseY, button); + updateButtons(); + return mouseClicked; + } + + protected void islandChanged(Location location) { + island = location.id(); + waypointsListWidget.setIsland(island); + } + + protected abstract boolean isEnabled(NamedWaypoint waypoint); + + protected abstract void enabledChanged(NamedWaypoint waypoint, boolean enabled); + + protected void updateButtons() { + waypointsListWidget.updateButtons(); + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/DropdownWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/DropdownWidget.java new file mode 100644 index 0000000000..157b0b150c --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/DropdownWidget.java @@ -0,0 +1,126 @@ +package de.hysky.skyblocker.skyblock.waypoint; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.Element; +import net.minecraft.client.gui.Selectable; +import net.minecraft.client.gui.widget.ElementListWidget; +import net.minecraft.text.Style; +import net.minecraft.text.Text; + +import java.util.List; +import java.util.function.Consumer; + +public class DropdownWidget extends ElementListWidget> { + private static final MinecraftClient client = MinecraftClient.getInstance(); + public static final int ENTRY_HEIGHT = 15; + protected final List entries; + protected final Consumer selectCallback; + protected T prevSelected; + protected T selected; + protected boolean open; + + public DropdownWidget(MinecraftClient minecraftClient, int x, int y, int width, List entries, Consumer selectCallback, T selected) { + super(minecraftClient, width, (entries.size() + 1) * ENTRY_HEIGHT + 8, y, ENTRY_HEIGHT); + setX(x); + this.entries = entries; + this.selectCallback = selectCallback; + this.selected = selected; + setRenderHeader(true, ENTRY_HEIGHT + 4); + for (T entry : entries) { + addEntry(new Entry<>(this, entry)); + } + } + + @Override + public int getRowLeft() { + return getX(); + } + + @Override + public int getRowWidth() { + return getWidth(); + } + + @Override + protected boolean clickedHeader(int x, int y) { + open = !open; + return true; + } + + @Override + protected void renderHeader(DrawContext context, int x, int y) { + context.drawTextWithShadow(client.textRenderer, selected.toString(), x + 4, y + 2, 0xFFFFFFFF); + } + + @Override + public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) { + context.getMatrices().push(); + context.getMatrices().translate(0, 0, 100); + + context.fill(getX(), getY(), getX() + width, getY() + headerHeight, 0xFF000000); + context.drawHorizontalLine(getX(), getX() + width, getY(), 0xFFFFFFFF); + context.drawHorizontalLine(getX(), getX() + width, getY() + headerHeight, 0xFFFFFFFF); + context.drawVerticalLine(getX(), getY(), getY() + headerHeight, 0xFFFFFFFF); + context.drawVerticalLine(getX() + width, getY(), getY() + headerHeight, 0xFFFFFFFF); + + if (open) { + context.fill(getX(), getY() + headerHeight + 1, getX() + width, getY() + height, 0xFF000000); + context.drawHorizontalLine(getX(), getX() + width, getY() + height, 0xFFFFFFFF); + context.drawVerticalLine(getX(), getY() + headerHeight, getY() + height, 0xFFFFFFFF); + context.drawVerticalLine(getX() + width, getY() + headerHeight, getY() + height, 0xFFFFFFFF); + + super.renderWidget(context, mouseX, mouseY, delta); + } else { + renderHeader(context, getRowLeft(), getY() + 4 - (int) getScrollAmount()); + } + + context.getMatrices().pop(); + } + + protected void select(T entry) { + selected = entry; + open = false; + if (selected != prevSelected) { + selectCallback.accept(entry); + prevSelected = selected; + } + } + + static class Entry extends ElementListWidget.Entry> { + private final DropdownWidget dropdownWidget; + private final T entry; + + public Entry(DropdownWidget dropdownWidget, T entry) { + this.dropdownWidget = dropdownWidget; + this.entry = entry; + } + + @Override + public List selectableChildren() { + return List.of(); + } + + @Override + public List children() { + return List.of(); + } + + @Override + public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { + context.drawTextWithShadow(client.textRenderer, Text.literal(entry.toString()).fillStyle(Style.EMPTY.withUnderline(hovered)), x + 14, y + 2, 0xFFFFFFFF); + if (dropdownWidget.selected == this.entry) { + context.drawTextWithShadow(client.textRenderer, "✔", x + 4, y + 2, 0xFFFFFFFF); + } + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (button == 0 && dropdownWidget.open) { + dropdownWidget.select(entry); + return true; + } + return super.mouseClicked(mouseX, mouseY, button); + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/OrderedWaypoints.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/OrderedWaypoints.java index bbc9a65547..f89308826f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/OrderedWaypoints.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/OrderedWaypoints.java @@ -408,7 +408,7 @@ private BlockPos getPos() { } @Override - protected float[] getColorComponents() { + public float[] getColorComponents() { if (this.colorComponents.length != 3) { return switch (this.relativeIndex) { case PREVIOUS -> RED; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java index 8eeae2aa37..18096117cb 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/Waypoints.java @@ -2,19 +2,25 @@ import com.google.common.collect.Multimap; import com.google.common.collect.MultimapBuilder; +import com.google.common.collect.Multimaps; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; import com.mojang.serialization.Codec; import com.mojang.serialization.JsonOps; import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.scheduler.Scheduler; import de.hysky.skyblocker.utils.waypoint.WaypointCategory; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.toast.SystemToast; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,19 +30,26 @@ import java.nio.file.Path; import java.util.Base64; import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.function.Function; + +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; public class Waypoints { - private static final Logger LOGGER = LoggerFactory.getLogger(Waypoints.class); + public static final Logger LOGGER = LoggerFactory.getLogger(Waypoints.class); private static final Codec> CODEC = WaypointCategory.CODEC.listOf(); private static final Codec> SKYTILS_CODEC = WaypointCategory.SKYTILS_CODEC.listOf(); + protected static final SystemToast.Type WAYPOINTS_TOAST_TYPE = new SystemToast.Type(); + private static final Path waypointsFile = FabricLoader.getInstance().getConfigDir().resolve(SkyblockerMod.NAMESPACE).resolve("waypoints.json"); - static final Multimap waypoints = MultimapBuilder.hashKeys().arrayListValues().build(); + protected static final Multimap waypoints = MultimapBuilder.hashKeys().arrayListValues().build(); public static void init() { loadWaypoints(); ClientLifecycleEvents.CLIENT_STOPPING.register(Waypoints::saveWaypoints); WorldRenderEvents.AFTER_TRANSLUCENT.register(Waypoints::render); + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE).then(literal("waypoints").executes(Scheduler.queueOpenScreenCommand(() -> new WaypointsScreen(MinecraftClient.getInstance().currentScreen)))))); } public static void loadWaypoints() { @@ -49,22 +62,47 @@ public static void loadWaypoints() { } } - public static List fromSkytilsBase64(String base64) { - return fromSkytilsJson(new String(Base64.getDecoder().decode(base64))); + public static List fromSkytilsBase64(String base64, String defaultIsland) { + try { + if (base64.startsWith("(V")) { + int version = Integer.parseInt(base64.substring(26, base64.indexOf(')'))); + if (version == 1) { + return fromSkytilsJson(new String(Base64.getDecoder().decode(base64.substring(base64.indexOf(':') + 1))), defaultIsland); + } else { + LOGGER.error("[Skyblocker Waypoints] Unknown Skytils waypoint data version: " + version); + } + } else return fromSkytilsJson(new String(Base64.getDecoder().decode(base64)), defaultIsland); + } catch (NumberFormatException e) { + LOGGER.error("[Skyblocker Waypoints] Encountered exception while parsing Skytils waypoint data version", e); + } catch (IllegalArgumentException e) { + LOGGER.error("[Skyblocker Waypoints] Encountered exception while decoding Skytils waypoint data", e); + } + return Collections.emptyList(); } - public static List fromSkytilsJson(String waypointCategories) { - return SKYTILS_CODEC.parse(JsonOps.INSTANCE, SkyblockerMod.GSON.fromJson(waypointCategories, JsonObject.class).getAsJsonArray("categories")).resultOrPartial(LOGGER::error).orElseThrow(); + public static List fromSkytilsJson(String waypointCategories, String defaultIsland) { + JsonArray waypointCategoriesJson; + try { + waypointCategoriesJson = SkyblockerMod.GSON.fromJson(waypointCategories, JsonObject.class).getAsJsonArray("categories"); + } catch (JsonSyntaxException e) { + JsonObject waypointCategoryJson = new JsonObject(); + waypointCategoryJson.addProperty("name", "New Category"); + waypointCategoryJson.addProperty("island", defaultIsland); + waypointCategoryJson.add("waypoints", SkyblockerMod.GSON.fromJson(waypointCategories, JsonArray.class)); + waypointCategoriesJson = new JsonArray(); + waypointCategoriesJson.add(waypointCategoryJson); + } + return SKYTILS_CODEC.parse(JsonOps.INSTANCE, waypointCategoriesJson).resultOrPartial(LOGGER::error).orElseThrow(); } - public static String toSkytilsBase64(Collection waypointCategories) { + public static String toSkytilsBase64(List waypointCategories) { return Base64.getEncoder().encodeToString(toSkytilsJson(waypointCategories).getBytes()); } - public static String toSkytilsJson(Collection waypointCategories) { + public static String toSkytilsJson(List waypointCategories) { JsonObject waypointCategoriesJson = new JsonObject(); - waypointCategoriesJson.add("categories", SKYTILS_CODEC.encodeStart(JsonOps.INSTANCE, List.copyOf(waypointCategories)).resultOrPartial(LOGGER::error).orElseThrow()); - return SkyblockerMod.GSON.toJson(waypointCategoriesJson); + waypointCategoriesJson.add("categories", SKYTILS_CODEC.encodeStart(JsonOps.INSTANCE, waypointCategories).resultOrPartial(LOGGER::error).orElseThrow()); + return SkyblockerMod.GSON_COMPACT.toJson(waypointCategoriesJson); } public static void saveWaypoints(MinecraftClient client) { @@ -77,11 +115,17 @@ public static void saveWaypoints(MinecraftClient client) { } } + public static Multimap waypointsDeepCopy() { + return waypoints.values().stream().map(WaypointCategory::deepCopy).collect(Multimaps.toMultimap(WaypointCategory::island, Function.identity(), () -> MultimapBuilder.hashKeys().arrayListValues().build())); + } + public static void render(WorldRenderContext context) { - Collection categories = waypoints.get(Utils.getLocationRaw()); - for (WaypointCategory category : categories) { - if (category != null) { - category.render(context); + if (SkyblockerConfigManager.get().uiAndVisuals.waypoints.enableWaypoints) { + Collection categories = waypoints.get(Utils.getLocationRaw()); + for (WaypointCategory category : categories) { + if (category != null) { + category.render(context); + } } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java index 7a01a494fe..3e18d67345 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java @@ -1,41 +1,31 @@ package de.hysky.skyblocker.skyblock.waypoint; -import de.hysky.skyblocker.debug.Debug; -import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.mixins.accessors.CheckboxWidgetAccessor; import de.hysky.skyblocker.utils.waypoint.NamedWaypoint; import de.hysky.skyblocker.utils.waypoint.WaypointCategory; +import it.unimi.dsi.fastutil.ints.Int2ObjectFunction; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.Element; import net.minecraft.client.gui.Selectable; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.client.gui.widget.ClickableWidget; -import net.minecraft.client.gui.widget.ElementListWidget; +import net.minecraft.client.gui.widget.*; import net.minecraft.text.Text; import net.minecraft.util.math.BlockPos; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import java.util.Objects; import java.util.Optional; public class WaypointsListWidget extends ElementListWidget { - private final WaypointsScreen screen; - private final String island; - private final List waypoints; + private final AbstractWaypointsScreen screen; + private String island; + private List waypoints; - public WaypointsListWidget(MinecraftClient client, WaypointsScreen screen, int width, int height, int y, int itemHeight) { + public WaypointsListWidget(MinecraftClient client, AbstractWaypointsScreen screen, int width, int height, int y, int itemHeight) { super(client, width, height, y, itemHeight); this.screen = screen; - island = Utils.getLocationRaw(); - waypoints = (List) screen.waypoints.get(island); - for (WaypointCategory category : waypoints) { - WaypointCategoryEntry categoryEntry = new WaypointCategoryEntry(category); - addEntry(categoryEntry); - for (NamedWaypoint waypoint : category.waypoints()) { - addEntry(new WaypointEntry(categoryEntry, waypoint)); - } - } + setIsland(screen.island); } @Override @@ -44,8 +34,8 @@ public int getRowWidth() { } @Override - protected int getScrollbarPositionX() { - return super.getScrollbarPositionX() + 50; + protected int getScrollbarX() { + return super.getScrollbarX(); } Optional getCategory() { @@ -57,6 +47,12 @@ Optional getCategory() { return Optional.empty(); } + void setIsland(String island) { + this.island = island; + waypoints = (List) screen.waypoints.get(island); + updateEntries(); + } + void addWaypointCategoryAfterSelected() { WaypointCategoryEntry categoryEntry = new WaypointCategoryEntry(); Optional selectedCategoryEntryOptional = getCategory(); @@ -74,17 +70,35 @@ void addWaypointCategoryAfterSelected() { children().add(entryIndex, categoryEntry); } - @Override - protected boolean isSelectedEntry(int index) { - return Debug.debugEnabled() ? Objects.equals(getSelectedOrNull(), children().get(index)) : super.isSelectedEntry(index); + void updateEntries() { + clearEntries(); + for (WaypointCategory category : waypoints) { + WaypointCategoryEntry categoryEntry = new WaypointCategoryEntry(category); + addEntry(categoryEntry); + for (NamedWaypoint waypoint : category.waypoints()) { + addEntry(new WaypointEntry(categoryEntry, waypoint)); + } + } + } + + void updateButtons() { + for (Entry entry : children()) { + if (entry instanceof WaypointCategoryEntry categoryEntry && categoryEntry.enabled.isChecked() != categoryEntry.category.waypoints().stream().allMatch(screen::isEnabled)) { + ((CheckboxWidgetAccessor) categoryEntry.enabled).setChecked(!categoryEntry.enabled.isChecked()); + } else if (entry instanceof WaypointEntry waypointEntry && waypointEntry.enabled.isChecked() != screen.isEnabled(waypointEntry.waypoint)) { + waypointEntry.enabled.onPress(); + } + } } - protected static abstract class AbstractWaypointEntry extends ElementListWidget.Entry { + protected abstract static class AbstractWaypointEntry extends Entry { } protected class WaypointCategoryEntry extends AbstractWaypointEntry { - private final WaypointCategory category; + private WaypointCategory category; private final List children; + private final CheckboxWidget enabled; + private final TextFieldWidget nameField; private final ButtonWidget buttonNewWaypoint; private final ButtonWidget buttonDelete; @@ -94,6 +108,10 @@ public WaypointCategoryEntry() { public WaypointCategoryEntry(WaypointCategory category) { this.category = category; + enabled = CheckboxWidget.builder(Text.literal(""), client.textRenderer).checked(!category.waypoints().isEmpty() && category.waypoints().stream().allMatch(screen::isEnabled)).callback((checkbox, checked) -> category.waypoints().forEach(waypoint -> screen.enabledChanged(waypoint, checked))).build(); + nameField = new TextFieldWidget(client.textRenderer, 70, 20, Text.literal("Name")); + nameField.setText(category.name()); + nameField.setChangedListener(this::updateName); buttonNewWaypoint = ButtonWidget.builder(Text.translatable("skyblocker.waypoints.new"), buttonNewWaypoint -> { WaypointEntry waypointEntry = new WaypointEntry(this); int entryIndex; @@ -107,7 +125,7 @@ public WaypointCategoryEntry(WaypointCategory category) { } category.waypoints().add(waypointEntry.waypoint); WaypointsListWidget.this.children().add(entryIndex, waypointEntry); - }).width(75).build(); + }).width(72).build(); buttonDelete = ButtonWidget.builder(Text.translatable("selectServer.deleteButton"), buttonDelete -> { int entryIndex = WaypointsListWidget.this.children().indexOf(this) + 1; while (entryIndex < WaypointsListWidget.this.children().size() && !(WaypointsListWidget.this.children().get(entryIndex) instanceof WaypointCategoryEntry)) { @@ -115,8 +133,8 @@ public WaypointCategoryEntry(WaypointCategory category) { } WaypointsListWidget.this.children().remove(this); waypoints.remove(category); - }).width(50).build(); - children = List.of(buttonNewWaypoint, buttonDelete); + }).width(38).build(); + children = List.of(enabled, nameField, buttonNewWaypoint, buttonDelete); } @Override @@ -129,20 +147,36 @@ public List children() { return children; } + private void updateName(String name) { + int index = waypoints.indexOf(category); + category = category.withName(name); + if (index >= 0) { + waypoints.set(index, category); + } + } + @Override public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - context.drawTextWithShadow(client.textRenderer, category.name(), width / 2 - 150, y + 5, 0xFFFFFF); - buttonNewWaypoint.setPosition(x + entryWidth - 133, y); - buttonDelete.setPosition(x + entryWidth - 54, y); - buttonNewWaypoint.render(context, mouseX, mouseY, tickDelta); - buttonDelete.render(context, mouseX, mouseY, tickDelta); + enabled.setPosition(x, y + 1); + nameField.setPosition(x + 22, y); + buttonNewWaypoint.setPosition(x + entryWidth - 115, y); + buttonDelete.setPosition(x + entryWidth - 38, y); + for (ClickableWidget child : children) { + child.render(context, mouseX, mouseY, tickDelta); + } } } protected class WaypointEntry extends AbstractWaypointEntry { private final WaypointCategoryEntry category; - private final NamedWaypoint waypoint; + private NamedWaypoint waypoint; private final List children; + private final CheckboxWidget enabled; + private final TextFieldWidget nameField; + private final TextFieldWidget xField; + private final TextFieldWidget yField; + private final TextFieldWidget zField; + private final TextFieldWidget colorField; private final ButtonWidget buttonDelete; public WaypointEntry(WaypointCategoryEntry category) { @@ -152,11 +186,27 @@ public WaypointEntry(WaypointCategoryEntry category) { public WaypointEntry(WaypointCategoryEntry category, NamedWaypoint waypoint) { this.category = category; this.waypoint = waypoint; + enabled = CheckboxWidget.builder(Text.literal(""), client.textRenderer).checked(screen.isEnabled(waypoint)).callback((checkbox, checked) -> screen.enabledChanged(waypoint, checked)).build(); + nameField = new TextFieldWidget(client.textRenderer, 65, 20, Text.literal("Name")); + nameField.setText(waypoint.getName().getString()); + nameField.setChangedListener(this::updateName); + xField = new TextFieldWidget(client.textRenderer, 26, 20, Text.literal("X")); + xField.setText(Integer.toString(waypoint.pos.getX())); + xField.setChangedListener(this::updateX); + yField = new TextFieldWidget(client.textRenderer, 26, 20, Text.literal("Y")); + yField.setText(Integer.toString(waypoint.pos.getY())); + yField.setChangedListener(this::updateY); + zField = new TextFieldWidget(client.textRenderer, 26, 20, Text.literal("Z")); + zField.setText(Integer.toString(waypoint.pos.getZ())); + zField.setChangedListener(this::updateZ); + colorField = new TextFieldWidget(client.textRenderer, 56, 20, Text.literal("Color")); + colorField.setText(String.format("%02X%02X%02X%02X", (int) (waypoint.alpha * 255), (int) (waypoint.getColorComponents()[0] * 255), (int) (waypoint.getColorComponents()[1] * 255), (int) (waypoint.getColorComponents()[2] * 255))); + colorField.setChangedListener(this::updateColor); buttonDelete = ButtonWidget.builder(Text.translatable("selectServer.deleteButton"), button -> { category.category.waypoints().remove(waypoint); WaypointsListWidget.this.children().remove(this); - }).width(50).build(); - children = List.of(buttonDelete); + }).width(38).build(); + children = List.of(enabled, nameField, xField, yField, zField, colorField, buttonDelete); } @Override @@ -169,14 +219,73 @@ public List children() { return children; } + public void updateName(String name) { + if (waypoint.name.getString().equals(name)) return; + int index = category.category.waypoints().indexOf(waypoint); + waypoint = waypoint.withName(name); + if (index >= 0) { + category.category.waypoints().set(index, waypoint); + } + } + + public void updateX(String xString) { + updateInt(xString, waypoint.pos.getX(), waypoint::withX); + } + + public void updateY(String yString) { + updateInt(yString, waypoint.pos.getY(), waypoint::withY); + } + + public void updateZ(String zString) { + updateInt(zString, waypoint.pos.getZ(), waypoint::withZ); + } + + public void updateInt(String newValueString, int currentValue, Int2ObjectFunction wither) { + try { + int index = category.category.waypoints().indexOf(waypoint); + int newValue = Integer.parseInt(newValueString); + if (newValue == currentValue) return; + waypoint = wither.apply(newValue); + if (index >= 0) { + category.category.waypoints().set(index, waypoint); + } + } catch (NumberFormatException e) { + Waypoints.LOGGER.warn("[Skyblocker Waypoints] Failed to parse integer: {}", newValueString, e); + } + } + + public void updateColor(String colorString) { + try { + int index = category.category.waypoints().indexOf(waypoint); + int colorInt = Integer.parseInt(colorString, 16); + float[] colorComponents = {((colorInt & 0x00FF0000) >> 16) / 255f, ((colorInt & 0x0000FF00) >> 8) / 255f, (colorInt & 0x000000FF) / 255f}; + float alpha = ((colorInt & 0xFF000000) >>> 24) / 255f; + if (Arrays.equals(waypoint.getColorComponents(), colorComponents) && waypoint.alpha == alpha) return; + waypoint = waypoint.withColor(colorComponents, alpha); + if (index >= 0) { + category.category.waypoints().set(index, waypoint); + } + } catch (NumberFormatException e) { + Waypoints.LOGGER.warn("[Skyblocker Waypoints] Failed to parse color: {}", colorString, e); + } + } + @Override public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - context.drawTextWithShadow(client.textRenderer, waypoint.getName(), width / 2 - 125, y + 5, 0xFFFFFF); - context.drawTextWithShadow(client.textRenderer, waypoint.pos.toShortString(), width / 2 - 25, y + 5, 0xFFFFFF); - float[] colorComponents = waypoint.getColorComponents(); - context.drawTextWithShadow(client.textRenderer, String.format("#%02X%02X%02X", (int) (colorComponents[0] * 255), (int) (colorComponents[1] * 255), (int) (colorComponents[2] * 255)), width / 2 + 25, y + 5, 0xFFFFFF); - buttonDelete.setPosition(x + entryWidth - 54, y); - buttonDelete.render(context, mouseX, mouseY, tickDelta); + context.drawTextWithShadow(client.textRenderer, "X:", width / 2 - 56, y + 6, 0xFFFFFF); + context.drawTextWithShadow(client.textRenderer, "Y:", width / 2 - 19, y + 6, 0xFFFFFF); + context.drawTextWithShadow(client.textRenderer, "Z:", width / 2 + 18, y + 6, 0xFFFFFF); + context.drawTextWithShadow(client.textRenderer, "#", x + entryWidth - 105, y + 6, 0xFFFFFF); + enabled.setPosition(x + 10, y + 1); + nameField.setPosition(x + 32, y); + xField.setPosition(width / 2 - 48, y); + yField.setPosition(width / 2 - 11, y); + zField.setPosition(width / 2 + 26, y); + colorField.setPosition(x + entryWidth - 99, y); + buttonDelete.setPosition(x + entryWidth - 38, y); + for (ClickableWidget child : children) { + child.render(context, mouseX, mouseY, tickDelta); + } } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsScreen.java index 9f82f7a2e1..23a2436189 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsScreen.java @@ -1,9 +1,8 @@ package de.hysky.skyblocker.skyblock.waypoint; -import com.google.common.collect.Multimap; -import com.google.common.collect.MultimapBuilder; -import de.hysky.skyblocker.utils.waypoint.WaypointCategory; +import de.hysky.skyblocker.utils.waypoint.NamedWaypoint; import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.ConfirmScreen; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.GridWidget; @@ -11,31 +10,21 @@ import net.minecraft.screen.ScreenTexts; import net.minecraft.text.Text; -public class WaypointsScreen extends Screen { - private final Screen parent; - final Multimap waypoints = MultimapBuilder.hashKeys().arrayListValues().build(); - private WaypointsListWidget waypointsListWidget; +public class WaypointsScreen extends AbstractWaypointsScreen { private ButtonWidget buttonNew; private ButtonWidget buttonDone; - protected WaypointsScreen() { - this(null); - } - public WaypointsScreen(Screen parent) { - super(Text.translatable("skyblocker.waypoints.config")); - this.parent = parent; - Waypoints.waypoints.forEach((island, category) -> waypoints.put(island, new WaypointCategory(category))); + super(Text.translatable("skyblocker.waypoints.config"), parent, Waypoints.waypointsDeepCopy()); } @Override protected void init() { super.init(); - waypointsListWidget = addDrawableChild(new WaypointsListWidget(client, this, width, height - 96, 32, 24)); GridWidget gridWidget = new GridWidget(); gridWidget.getMainPositioner().marginX(5).marginY(2); GridWidget.Adder adder = gridWidget.createAdder(2); - adder.add(ButtonWidget.builder(Text.translatable("skyblocker.waypoints.share"), buttonShare -> {}).build()); + adder.add(ButtonWidget.builder(Text.translatable("skyblocker.waypoints.share"), buttonShare -> client.setScreen(new WaypointsShareScreen(this, waypoints))).build()); buttonNew = adder.add(ButtonWidget.builder(Text.translatable("skyblocker.waypoints.newCategory"), buttonNew -> waypointsListWidget.addWaypointCategoryAfterSelected()).build()); adder.add(ButtonWidget.builder(ScreenTexts.CANCEL, button -> close()).build()); buttonDone = adder.add(ButtonWidget.builder(ScreenTexts.DONE, button -> { @@ -54,17 +43,34 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) { context.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 16, 0xFFFFFF); } + @Override + protected boolean isEnabled(NamedWaypoint waypoint) { + return waypoint.shouldRender(); + } + + @Override + protected void enabledChanged(NamedWaypoint waypoint, boolean enabled) { + waypoint.setShouldRender(enabled); + } + private void saveWaypoints() { Waypoints.waypoints.clear(); Waypoints.waypoints.putAll(waypoints); Waypoints.saveWaypoints(client); } - private void updateButtons() {} - - @SuppressWarnings("DataFlowIssue") @Override public void close() { - client.setScreen(parent); + assert client != null; + if (!waypoints.equals(Waypoints.waypoints)) { + client.setScreen(new ConfirmScreen(confirmedAction -> client.setScreen(confirmedAction ? parent : this), + Text.translatable("text.skyblocker.quit_config"), + Text.translatable("text.skyblocker.quit_config_sure"), + Text.translatable("text.skyblocker.quit_discard"), + ScreenTexts.CANCEL + )); + } else { + client.setScreen(parent); + } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsShareScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsShareScreen.java new file mode 100644 index 0000000000..aee21ec80c --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsShareScreen.java @@ -0,0 +1,86 @@ +package de.hysky.skyblocker.skyblock.waypoint; + +import com.google.common.collect.Multimap; +import de.hysky.skyblocker.utils.waypoint.NamedWaypoint; +import de.hysky.skyblocker.utils.waypoint.WaypointCategory; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.GridWidget; +import net.minecraft.client.gui.widget.SimplePositioningWidget; +import net.minecraft.client.toast.SystemToast; +import net.minecraft.screen.ScreenTexts; +import net.minecraft.text.Text; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class WaypointsShareScreen extends AbstractWaypointsScreen { + private final Set selectedWaypoints = new HashSet<>(); + + protected WaypointsShareScreen(WaypointsScreen parent, Multimap waypoints) { + super(Text.translatable("skyblocker.waypoints.shareWaypoints"), parent, waypoints, parent.island); + } + + @Override + protected void init() { + super.init(); + GridWidget gridWidget = new GridWidget(); + gridWidget.getMainPositioner().marginX(5).marginY(2); + GridWidget.Adder adder = gridWidget.createAdder(2); + adder.add(ButtonWidget.builder(Text.translatable("skyblocker.waypoints.importWaypointsSkytils"), buttonImport -> { + try { + List waypointCategories = Waypoints.fromSkytilsBase64(client.keyboard.getClipboard(), island); + for (WaypointCategory waypointCategory : waypointCategories) { + selectedWaypoints.addAll(waypointCategory.waypoints()); + waypoints.put(waypointCategory.island(), waypointCategory); + } + waypointsListWidget.updateEntries(); + SystemToast.show(client.getToastManager(), Waypoints.WAYPOINTS_TOAST_TYPE, Text.translatable("skyblocker.waypoints.importSuccess"), Text.translatable("skyblocker.waypoints.importSuccessText", waypointCategories.stream().map(WaypointCategory::waypoints).mapToInt(List::size).sum(), waypointCategories.size())); + } catch (Exception e) { + Waypoints.LOGGER.error("[Skyblocker Waypoints] Encountered exception while parsing Skytils waypoint data", e); + SystemToast.show(client.getToastManager(), Waypoints.WAYPOINTS_TOAST_TYPE, Text.translatable("skyblocker.waypoints.importError"), Text.translatable("skyblocker.waypoints.importErrorText")); + } + }).tooltip(Tooltip.of(Text.translatable("skyblocker.waypoints.importWaypointsSkytils.tooltip"))).build()); + adder.add(ButtonWidget.builder(Text.translatable("skyblocker.waypoints.importWaypointsSnoopy"), buttonImport -> { + }).tooltip(Tooltip.of(Text.translatable("skyblocker.waypoints.importWaypointsSnoopy.tooltip"))).build()); + adder.add(ButtonWidget.builder(ScreenTexts.BACK, buttonBack -> close()).build()); + adder.add(ButtonWidget.builder(Text.translatable("skyblocker.waypoints.exportWaypointsSkytils"), buttonExport -> { + try { + List waypointCategories = waypoints.values().stream().filter(waypointCategory -> waypointCategory.island().equals(island)).map(WaypointCategory.filter(selectedWaypoints::contains)).filter(waypointCategory -> !waypointCategory.waypoints().isEmpty()).toList(); + client.keyboard.setClipboard(Waypoints.toSkytilsBase64(waypointCategories)); + SystemToast.show(client.getToastManager(), Waypoints.WAYPOINTS_TOAST_TYPE, Text.translatable("skyblocker.waypoints.exportSuccess"), Text.translatable("skyblocker.waypoints.exportSuccessText", waypointCategories.stream().map(WaypointCategory::waypoints).mapToInt(List::size).sum(), waypointCategories.size())); + } catch (Exception e) { + Waypoints.LOGGER.error("[Skyblocker Waypoints] Encountered exception while serializing Skytils waypoint data", e); + SystemToast.show(client.getToastManager(), Waypoints.WAYPOINTS_TOAST_TYPE, Text.translatable("skyblocker.waypoints.exportError"), Text.translatable("skyblocker.waypoints.exportErrorText")); + } + }).tooltip(Tooltip.of(Text.translatable("skyblocker.waypoints.exportWaypointsSkytils.tooltip"))).build()); + gridWidget.refreshPositions(); + SimplePositioningWidget.setPos(gridWidget, 0, this.height - 64, this.width, 64); + gridWidget.forEachChild(this::addDrawableChild); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + super.render(context, mouseX, mouseY, delta); + context.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 16, 0xFFFFFF); + } + + @Override + protected boolean isEnabled(NamedWaypoint waypoint) { + return selectedWaypoints.contains(waypoint); + } + + @Override + protected void enabledChanged(NamedWaypoint waypoint, boolean enabled) { + if (enabled) selectedWaypoints.add(waypoint); + else selectedWaypoints.remove(waypoint); + } + + @SuppressWarnings("DataFlowIssue") + @Override + public void close() { + client.setScreen(parent); + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java index f959de78c6..2f02b51f01 100644 --- a/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/NamedWaypoint.java @@ -13,6 +13,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; +import java.util.Objects; import java.util.function.Supplier; public class NamedWaypoint extends Waypoint { @@ -23,6 +24,7 @@ public class NamedWaypoint extends Waypoint { colorComponentsList -> colorComponentsList.size() == 3 ? DataResult.success(Floats.toArray(colorComponentsList)) : DataResult.error(() -> "Expected 3 color components, got " + colorComponentsList.size() + " instead"), Floats::asList ).fieldOf("colorComponents").forGetter(secretWaypoint -> secretWaypoint.colorComponents), + Codec.FLOAT.fieldOf("alpha").forGetter(secretWaypoint -> secretWaypoint.alpha), Codec.BOOL.fieldOf("shouldRender").forGetter(Waypoint::shouldRender) ).apply(instance, NamedWaypoint::new)); public static final Codec SKYTILS_CODEC = RecordCodecBuilder.create(instance -> instance.group( @@ -30,46 +32,78 @@ public class NamedWaypoint extends Waypoint { Codec.INT.fieldOf("y").forGetter(waypoint -> waypoint.pos.getY()), Codec.INT.fieldOf("z").forGetter(waypoint -> waypoint.pos.getZ()), Codec.either(Codec.STRING, Codec.INT).xmap(either -> either.map(str -> str, Object::toString), Either::left).fieldOf("name").forGetter(waypoint -> waypoint.name.getString()), - Codec.INT.fieldOf("color").forGetter(waypoint -> (int) (waypoint.colorComponents[0] * 255) << 16 | (int) (waypoint.colorComponents[1] * 255) << 8 | (int) (waypoint.colorComponents[2] * 255)), + Codec.INT.fieldOf("color").forGetter(waypoint -> (int) (waypoint.alpha * 255) << 24 | (int) (waypoint.colorComponents[0] * 255) << 16 | (int) (waypoint.colorComponents[1] * 255) << 8 | (int) (waypoint.colorComponents[2] * 255)), Codec.BOOL.fieldOf("enabled").forGetter(Waypoint::shouldRender) ).apply(instance, NamedWaypoint::fromSkytils)); - protected final Text name; - protected final Vec3d centerPos; + public final Text name; + public final Vec3d centerPos; public NamedWaypoint(BlockPos pos, String name, float[] colorComponents) { this(pos, name, colorComponents, true); } public NamedWaypoint(BlockPos pos, String name, float[] colorComponents, boolean shouldRender) { - this(pos, Text.of(name), colorComponents, shouldRender); + this(pos, name, colorComponents, DEFAULT_HIGHLIGHT_ALPHA, shouldRender); } - public NamedWaypoint(BlockPos pos, Text name, float[] colorComponents, boolean shouldRender) { - this(pos, name, () -> SkyblockerConfigManager.get().general.waypoints.waypointType, colorComponents, shouldRender); + public NamedWaypoint(BlockPos pos, String name, float[] colorComponents, float alpha, boolean shouldRender) { + this(pos, Text.of(name), colorComponents, alpha, shouldRender); } - public NamedWaypoint(BlockPos pos, String name, Supplier typeSupplier, float[] colorComponents, boolean shouldRender) { - this(pos, Text.of(name), typeSupplier, colorComponents, shouldRender); + public NamedWaypoint(BlockPos pos, Text name, float[] colorComponents, float alpha, boolean shouldRender) { + this(pos, name, () -> SkyblockerConfigManager.get().uiAndVisuals.waypoints.waypointType, colorComponents, alpha, shouldRender); } public NamedWaypoint(BlockPos pos, Text name, Supplier typeSupplier, float[] colorComponents) { - this(pos, name, typeSupplier, colorComponents, true); + this(pos, name, typeSupplier, colorComponents, DEFAULT_HIGHLIGHT_ALPHA, true); } - public NamedWaypoint(BlockPos pos, Text name, Supplier typeSupplier, float[] colorComponents, boolean shouldRender) { - super(pos, typeSupplier, colorComponents, DEFAULT_HIGHLIGHT_ALPHA, DEFAULT_LINE_WIDTH, true, shouldRender); + public NamedWaypoint(BlockPos pos, Text name, Supplier typeSupplier, float[] colorComponents, float alpha, boolean shouldRender) { + super(pos, typeSupplier, colorComponents, alpha, DEFAULT_LINE_WIDTH, true, shouldRender); this.name = name; this.centerPos = pos.toCenterPos(); } public static NamedWaypoint fromSkytils(int x, int y, int z, String name, int color, boolean enabled) { - return new NamedWaypoint(new BlockPos(x, y, z), name, new float[]{((color & 0x00FF0000) >> 16) / 255f, ((color & 0x0000FF00) >> 8) / 255f, (color & 0x000000FF) / 255f}, enabled); + float alpha = ((color & 0xFF000000) >>> 24) / 255f; + if (alpha == 0) { + alpha = DEFAULT_HIGHLIGHT_ALPHA; + } + return new NamedWaypoint(new BlockPos(x, y, z), name, new float[]{((color & 0x00FF0000) >> 16) / 255f, ((color & 0x0000FF00) >> 8) / 255f, (color & 0x000000FF) / 255f}, alpha, enabled); + } + + public NamedWaypoint copy() { + return new NamedWaypoint(pos, name, typeSupplier, getColorComponents(), alpha, shouldRender()); + } + + @Override + public NamedWaypoint withX(int x) { + return new NamedWaypoint(new BlockPos(x, pos.getY(), pos.getZ()), name, typeSupplier, getColorComponents(), alpha, shouldRender()); + } + + @Override + public NamedWaypoint withY(int y) { + return new NamedWaypoint(pos.withY(y), name, typeSupplier, getColorComponents(), alpha, shouldRender()); + } + + @Override + public NamedWaypoint withZ(int z) { + return new NamedWaypoint(new BlockPos(pos.getX(), pos.getY(), z), name, typeSupplier, getColorComponents(), alpha, shouldRender()); + } + + @Override + public NamedWaypoint withColor(float[] colorComponents, float alpha) { + return new NamedWaypoint(pos, name, typeSupplier, colorComponents, alpha, shouldRender()); } public Text getName() { return name; } + public NamedWaypoint withName(String name) { + return new NamedWaypoint(pos, Text.literal(name), typeSupplier, getColorComponents(), alpha, shouldRender()); + } + protected boolean shouldRenderName() { return true; } @@ -82,8 +116,13 @@ public void render(WorldRenderContext context) { } } + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), name); + } + @Override public boolean equals(Object obj) { - return this == obj || obj instanceof NamedWaypoint waypoint && name.equals(waypoint.name); + return this == obj || super.equals(obj) && obj instanceof NamedWaypoint waypoint && name.equals(waypoint.name); } } diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java index 75e2edcf38..c991fb9cdd 100644 --- a/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/Waypoint.java @@ -3,10 +3,12 @@ import de.hysky.skyblocker.utils.render.RenderHelper; import de.hysky.skyblocker.utils.render.Renderable; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.minecraft.util.StringIdentifiable; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; import java.util.Arrays; +import java.util.Objects; import java.util.function.Supplier; public class Waypoint implements Renderable { @@ -16,9 +18,9 @@ public class Waypoint implements Renderable { final Box box; final Supplier typeSupplier; protected final float[] colorComponents; - final float alpha; - final float lineWidth; - final boolean throughWalls; + public final float alpha; + public final float lineWidth; + public final boolean throughWalls; private boolean shouldRender; public Waypoint(BlockPos pos, Type type, float[] colorComponents) { @@ -56,6 +58,22 @@ public Waypoint(BlockPos pos, Supplier typeSupplier, float[] colorComponen this.shouldRender = shouldRender; } + public Waypoint withX(int x) { + return new Waypoint(new BlockPos(x, pos.getY(), pos.getZ()), typeSupplier, getColorComponents(), alpha, lineWidth, throughWalls, shouldRender()); + } + + public Waypoint withY(int y) { + return new Waypoint(pos.withY(y), typeSupplier, getColorComponents(), alpha, lineWidth, throughWalls, shouldRender()); + } + + public Waypoint withZ(int z) { + return new Waypoint(new BlockPos(pos.getX(), pos.getY(), z), typeSupplier, getColorComponents(), alpha, lineWidth, throughWalls, shouldRender()); + } + + public Waypoint withColor(float[] colorComponents, float alpha) { + return new Waypoint(pos, typeSupplier, colorComponents, alpha, lineWidth, throughWalls, shouldRender()); + } + public boolean shouldRender() { return shouldRender; } @@ -72,6 +90,10 @@ public void toggle() { this.shouldRender = !this.shouldRender; } + public void setShouldRender(boolean shouldRender) { + this.shouldRender = shouldRender; + } + public float[] getColorComponents() { return colorComponents; } @@ -95,18 +117,28 @@ public void render(WorldRenderContext context) { } } + @Override + public int hashCode() { + return Objects.hash(pos, typeSupplier.get(), Arrays.hashCode(colorComponents), alpha, lineWidth, throughWalls, shouldRender); + } + @Override public boolean equals(Object obj) { return super.equals(obj) || obj instanceof Waypoint other && pos.equals(other.pos) && typeSupplier.get() == other.typeSupplier.get() && Arrays.equals(colorComponents, other.colorComponents) && alpha == other.alpha && lineWidth == other.lineWidth && throughWalls == other.throughWalls && shouldRender == other.shouldRender; } - public enum Type { + public enum Type implements StringIdentifiable { WAYPOINT, OUTLINED_WAYPOINT, HIGHLIGHT, OUTLINED_HIGHLIGHT, OUTLINE; + @Override + public String asString() { + return name().toLowerCase(); + } + @Override public String toString() { return switch (this) { diff --git a/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java b/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java index b1ac6135bc..db2a6d82c2 100644 --- a/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/WaypointCategory.java @@ -4,8 +4,10 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; -import java.util.ArrayList; import java.util.List; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; public record WaypointCategory(String name, String island, List waypoints) { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( @@ -19,13 +21,23 @@ public record WaypointCategory(String name, String island, List w NamedWaypoint.SKYTILS_CODEC.listOf().fieldOf("waypoints").forGetter(WaypointCategory::waypoints) ).apply(instance, WaypointCategory::new)); - public WaypointCategory(WaypointCategory waypointCategory) { - this(waypointCategory.name(), waypointCategory.island(), new ArrayList<>(waypointCategory.waypoints())); + public static UnaryOperator filter(Predicate predicate) { + return waypointCategory -> new WaypointCategory(waypointCategory.name(), waypointCategory.island(), waypointCategory.waypoints().stream().filter(predicate).toList()); + } + + public WaypointCategory withName(String name) { + return new WaypointCategory(name, island(), waypoints()); + } + + public WaypointCategory deepCopy() { + return new WaypointCategory(name(), island(), waypoints().stream().map(NamedWaypoint::copy).collect(Collectors.toList())); } public void render(WorldRenderContext context) { for (NamedWaypoint waypoint : waypoints) { - waypoint.render(context); + if (waypoint.shouldRender()) { + waypoint.render(context); + } } } } diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index a212ddfa53..98a7b2c92d 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -724,6 +724,21 @@ "skyblocker.waypoints.newCategory": "New Waypoint Category", "skyblocker.waypoints.new": "New Waypoint", "skyblocker.waypoints.share": "Share", + "skyblocker.waypoints.shareWaypoints": "Share Waypoints", + "skyblocker.waypoints.importWaypointsSkytils": "Import Waypoints (Skytils)", + "skyblocker.waypoints.importWaypointsSkytils.tooltip": "Import Waypoints from Clipboard (Skytils Format)", + "skyblocker.waypoints.importWaypointsSnoopy": "Import Waypoints (Snoopy)", + "skyblocker.waypoints.importWaypointsSnoopy.tooltip": "Import Waypoints from Clipboard (Snoopy Format) (Coming Soon)", + "skyblocker.waypoints.exportWaypointsSkytils": "Export Waypoints (Skytils)", + "skyblocker.waypoints.exportWaypointsSkytils.tooltip": "Export Waypoints to Clipboard (Skytils Format)", + "skyblocker.waypoints.importSuccess": "Waypoints Imported", + "skyblocker.waypoints.importSuccessText": "Successfully imported %d waypoints from %d categories.", + "skyblocker.waypoints.importError": "Error Importing Waypoints", + "skyblocker.waypoints.importErrorText": "Failed to import waypoints. See logs for details.", + "skyblocker.waypoints.exportSuccess": "Waypoints Exported", + "skyblocker.waypoints.exportSuccessText": "Successfully exported %d waypoints from %d categories.", + "skyblocker.waypoints.exportError": "Error Exporting Waypoints", + "skyblocker.waypoints.exportErrorText": "Failed to export waypoints. See logs for details.", "skyblocker.waypoints.deleteQuestion": "Are you sure you want to remove this waypoint?", "skyblocker.waypoints.deleteWarning": "Waypoint '%s' will be lost forever! (A long time!)", diff --git a/src/main/resources/skyblocker.mixins.json b/src/main/resources/skyblocker.mixins.json index 828cc206af..9b96ba6160 100644 --- a/src/main/resources/skyblocker.mixins.json +++ b/src/main/resources/skyblocker.mixins.json @@ -39,6 +39,7 @@ "YggdrasilMinecraftSessionServiceMixin", "YggdrasilServicesKeyInfoMixin", "accessors.BeaconBlockEntityRendererInvoker", + "accessors.CheckboxWidgetAccessor", "accessors.DrawContextInvoker", "accessors.EndermanEntityAccessor", "accessors.FrustumInvoker", diff --git a/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointCategoryTest.java b/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointCategoryTest.java index 65304e0c90..f9a17bff74 100644 --- a/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointCategoryTest.java +++ b/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointCategoryTest.java @@ -23,14 +23,14 @@ static void beforeAll() { void testCodecEncode() { WaypointCategory category = new WaypointCategory("category", "hub", List.of(new NamedWaypoint(BlockPos.ORIGIN, "waypoint", new float[]{0f, 0.5f, 1f}, false), new NamedWaypoint(new BlockPos(-1, 0, 1), "waypoint", new float[]{0f, 0f, 0f}, true))); Object categoryJson = WaypointCategory.CODEC.encodeStart(JsonOps.INSTANCE, category).result().orElseThrow(); - String expectedJson = "{\"name\":\"category\",\"island\":\"hub\",\"waypoints\":[{\"pos\":[0,0,0],\"name\":\"waypoint\",\"colorComponents\":[0.0,0.5,1.0],\"shouldRender\":false},{\"pos\":[-1,0,1],\"name\":\"waypoint\",\"colorComponents\":[0.0,0.0,0.0],\"shouldRender\":true}]}"; + String expectedJson = "{\"name\":\"category\",\"island\":\"hub\",\"waypoints\":[{\"colorComponents\":[0.0,0.5,1.0],\"alpha\":0.5,\"shouldRender\":false,\"pos\":[0,0,0],\"name\":\"waypoint\"},{\"colorComponents\":[0.0,0.0,0.0],\"alpha\":0.5,\"shouldRender\":true,\"pos\":[-1,0,1],\"name\":\"waypoint\"}]}"; Assertions.assertEquals(expectedJson, categoryJson.toString()); } @Test void testCodecDecode() { - String categoryJson = "{\"name\":\"category\",\"island\":\"hub\",\"waypoints\":[{\"pos\":[0,0,0],\"name\":\"waypoint\",\"colorComponents\":[0.0,0.5,1.0],\"shouldRender\":false},{\"pos\":[-1,0,1],\"name\":\"waypoint\",\"colorComponents\":[0.0,0.0,0.0],\"shouldRender\":true}]}"; + String categoryJson = "{\"name\":\"category\",\"island\":\"hub\",\"waypoints\":[{\"colorComponents\":[0.0,0.5,1.0],\"alpha\":0.5,\"shouldRender\":false,\"pos\":[0,0,0],\"name\":\"waypoint\"},{\"colorComponents\":[0.0,0.0,0.0],\"alpha\":0.5,\"shouldRender\":true,\"pos\":[-1,0,1],\"name\":\"waypoint\"}]}"; WaypointCategory category = WaypointCategory.CODEC.parse(JsonOps.INSTANCE, SkyblockerMod.GSON.fromJson(categoryJson, JsonElement.class)).result().orElseThrow(); WaypointCategory expectedCategory = new WaypointCategory("category", "hub", List.of(new NamedWaypoint(BlockPos.ORIGIN, "waypoint", new float[]{0f, 0.5f, 1f}, false), new NamedWaypoint(new BlockPos(-1, 0, 1), "waypoint", new float[]{0f, 0f, 0f}, true))); diff --git a/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointsTest.java b/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointsTest.java index ad237718a4..820b687d21 100644 --- a/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointsTest.java +++ b/src/test/java/de/hysky/skyblocker/utils/waypoint/WaypointsTest.java @@ -5,25 +5,119 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.util.Collection; import java.util.List; public class WaypointsTest { @Test void testFromSkytilsBase64() { - String waypointCategoriesSkytilsBase64 = "eyJjYXRlZ29yaWVzIjpbeyJuYW1lIjoiY2F0ZWdvcnkiLCJ3YXlwb2ludHMiOlt7Im5hbWUiOiJ3YXlwb2ludCIsIngiOjAsInkiOjAsInoiOjAsImVuYWJsZWQiOmZhbHNlLCJjb2xvciI6MzMwMjMsImFkZGVkQXQiOjF9LHsibmFtZSI6MSwieCI6LTEsInkiOjAsInoiOjEsImVuYWJsZWQiOnRydWUsImNvbG9yIjowLCJhZGRlZEF0IjoxfV0sImlzbGFuZCI6Imh1YiJ9XX0="; - Collection waypointCategories = Waypoints.fromSkytilsBase64(waypointCategoriesSkytilsBase64); - Collection expectedWaypointCategories = List.of(new WaypointCategory("category", "hub", List.of(new NamedWaypoint(BlockPos.ORIGIN, "waypoint", new float[]{0f, 0.5f, 1f}, false), new NamedWaypoint(new BlockPos(-1, 0, 1), "1", new float[]{0f, 0f, 0f}, true)))); + String waypointCategoriesSkytilsBase64 = "eyJjYXRlZ29yaWVzIjpbeyJuYW1lIjoiY2F0ZWdvcnkiLCJ3YXlwb2ludHMiOlt7Im5hbWUiOiJ3YXlwb2ludCIsIngiOjAsInkiOjAsInoiOjAsImVuYWJsZWQiOmZhbHNlLCJjb2xvciI6LTg3MjM4MjIwOSwiYWRkZWRBdCI6MX0seyJuYW1lIjoxLCJ4IjotMSwieSI6MCwieiI6MSwiZW5hYmxlZCI6dHJ1ZSwiY29sb3IiOjAsImFkZGVkQXQiOjF9XSwiaXNsYW5kIjoiaHViIn1dfQ=="; + List waypointCategories = Waypoints.fromSkytilsBase64(waypointCategoriesSkytilsBase64, ""); + List expectedWaypointCategories = List.of(new WaypointCategory("category", "hub", List.of(new NamedWaypoint(BlockPos.ORIGIN, "waypoint", new float[]{0f, 0.5019608f, 1f}, 0.8f, false), new NamedWaypoint(new BlockPos(-1, 0, 1), "1", new float[]{0f, 0f, 0f}, true)))); Assertions.assertEquals(expectedWaypointCategories, waypointCategories); } @Test void testToSkytilsBase64() { - Collection waypointCategories = List.of(new WaypointCategory("category", "hub", List.of(new NamedWaypoint(BlockPos.ORIGIN, "waypoint", new float[]{0f, 0.5f, 1f}, false), new NamedWaypoint(new BlockPos(-1, 0, 1), "1", new float[]{0f, 0f, 0f}, true)))); + List waypointCategories = List.of(new WaypointCategory("category", "hub", List.of(new NamedWaypoint(BlockPos.ORIGIN, "waypoint", new float[]{0f, 0.5f, 1f}, 0.8f, false), new NamedWaypoint(new BlockPos(-1, 0, 1), "1", new float[]{0f, 0f, 0f}, true)))); String waypointCategoriesSkytilsBase64 = Waypoints.toSkytilsBase64(waypointCategories); - String expectedWaypointCategoriesSkytilsBase64 = "ewogICJjYXRlZ29yaWVzIjogWwogICAgewogICAgICAibmFtZSI6ICJjYXRlZ29yeSIsCiAgICAgICJpc2xhbmQiOiAiaHViIiwKICAgICAgIndheXBvaW50cyI6IFsKICAgICAgICB7CiAgICAgICAgICAibmFtZSI6ICJ3YXlwb2ludCIsCiAgICAgICAgICAiY29sb3IiOiAzMjc2NywKICAgICAgICAgICJlbmFibGVkIjogZmFsc2UsCiAgICAgICAgICAieCI6IDAsCiAgICAgICAgICAieSI6IDAsCiAgICAgICAgICAieiI6IDAKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJuYW1lIjogIjEiLAogICAgICAgICAgImNvbG9yIjogMCwKICAgICAgICAgICJlbmFibGVkIjogdHJ1ZSwKICAgICAgICAgICJ4IjogLTEsCiAgICAgICAgICAieSI6IDAsCiAgICAgICAgICAieiI6IDEKICAgICAgICB9CiAgICAgIF0KICAgIH0KICBdCn0="; + String expectedWaypointCategoriesSkytilsBase64 = "eyJjYXRlZ29yaWVzIjpbeyJuYW1lIjoiY2F0ZWdvcnkiLCJpc2xhbmQiOiJodWIiLCJ3YXlwb2ludHMiOlt7Im5hbWUiOiJ3YXlwb2ludCIsImNvbG9yIjotODcyMzgyNDY1LCJlbmFibGVkIjpmYWxzZSwieCI6MCwieSI6MCwieiI6MH0seyJuYW1lIjoiMSIsImNvbG9yIjoyMTMwNzA2NDMyLCJlbmFibGVkIjp0cnVlLCJ4IjotMSwieSI6MCwieiI6MX1dfV19"; Assertions.assertEquals(expectedWaypointCategoriesSkytilsBase64, waypointCategoriesSkytilsBase64); } + + //https://sharetext.me/gq22cbhdmo + @Test + void testFromSkytilsBase64GlacialCaveWaypoints() { + String waypointCategoriesSkytilsBase64 = "eyJjYXRlZ29yaWVzIjogW3sibmFtZSI6ICJGcm96ZW4gVHJlYXN1cmUgTG9jYXRpb25zIiwid2F5cG9pbnRzIjogW3sibmFtZSI6ICIyNCIsIngiOiA2NCwieSI6IDc4LCJ6IjogMjgsImVuYWJsZWQiOiB0cnVlLCJjb2xvciI6IDEwODU0MDY3MTksImFkZGVkQXQiOiAxNjY5OTk5NzUwNjc3fSx7Im5hbWUiOiAiOSIsIngiOiA0NSwieSI6IDc5LCJ6IjogNDksImVuYWJsZWQiOiB0cnVlLCJjb2xvciI6IDEwODUyNzM1OTksImFkZGVkQXQiOiAxNjY5OTk5NTEwMTA3fSx7Im5hbWUiOiAiMjAiLCJ4IjogNjAsInkiOiA3NiwieiI6IDUxLCJlbmFibGVkIjogdHJ1ZSwiY29sb3IiOiA5NTMzNTE5MzUsImFkZGVkQXQiOiAxNjY5OTk5NzQ5MzI3fSx7Im5hbWUiOiAiMjMiLCJ4IjogNjMsInkiOiA3NiwieiI6IDk1LCJlbmFibGVkIjogdHJ1ZSwiY29sb3IiOiAxMDIwNDYxMDUyLCJhZGRlZEF0IjogMTY2OTk5OTc1MDQ3N30seyJuYW1lIjogIjIyIiwieCI6IDYzLCJ5IjogNzYsInoiOiA1MiwiZW5hYmxlZCI6IHRydWUsImNvbG9yIjogMTA1MjQ0MjYxMSwiYWRkZWRBdCI6IDE2Njk5OTk3NTAyMjd9LHsibmFtZSI6ICI0MCIsIngiOiA5NCwieSI6IDc3LCJ6IjogNDIsImVuYWJsZWQiOiB0cnVlLCJjb2xvciI6IDk4NDYxMjg1NywiYWRkZWRBdCI6IDE2NzAwMDAyMjcwMjR9LHsibmFtZSI6ICIzOCIsIngiOiA5MSwieSI6IDc3LCJ6IjogMjcsImVuYWJsZWQiOiB0cnVlLCJjb2xvciI6IDEwNTI3NzAyOTIsImFkZGVkQXQiOiAxNjcwMDAwMjI2NjI1fSx7Im5hbWUiOiAiMTUiLCJ4IjogNTAsInkiOiA4MCwieiI6IDg4LCJlbmFibGVkIjogdHJ1ZSwiY29sb3IiOiAxMDcxMjUxMTk5LCJhZGRlZEF0IjogMTY2OTk5OTUxMTUwNH0seyJuYW1lIjogIjE0IiwieCI6IDUwLCJ5IjogNzksInoiOiAzNCwiZW5hYmxlZCI6IHRydWUsImNvbG9yIjogMTEwNDkzNjcwMywiYWRkZWRBdCI6IDE2Njk5OTk1MTEzMDZ9LHsibmFtZSI6ICIxOSIsIngiOiA1OCwieSI6IDc5LCJ6IjogODksImVuYWJsZWQiOiB0cnVlLCJjb2xvciI6IDExNTU2NjE4MTgsImFkZGVkQXQiOiAxNjY5OTk5NTE3ODEwfSx7Im5hbWUiOiAiMzAiLCJ4IjogNzgsInkiOiA3NCwieiI6IDk5LCJlbmFibGVkIjogdHJ1ZSwiY29sb3IiOiAxMTE5NDIwNDAzLCJhZGRlZEF0IjogMTY3MDAwMDAyMTgyM30seyJuYW1lIjogIjExIiwieCI6IDQ2LCJ5IjogODAsInoiOiA4NCwiZW5hYmxlZCI6IHRydWUsImNvbG9yIjogMTA3MTY0NDY2MiwiYWRkZWRBdCI6IDE2Njk5OTk1MTA3MDh9LHsibmFtZSI6ICI0MyIsIngiOiA5NywieSI6IDgxLCJ6IjogNzcsImVuYWJsZWQiOiB0cnVlLCJjb2xvciI6IDEwNTE5ODM4NjUsImFkZGVkQXQiOiAxNjcwMDAwMjI3Njc2fSx7Im5hbWUiOiAiMTciLCJ4IjogNTUsInkiOiA3OSwieiI6IDM0LCJlbmFibGVkIjogdHJ1ZSwiY29sb3IiOiAxMTA1MTk5MDk4LCJhZGRlZEF0IjogMTY2OTk5OTUxMTkwNX0seyJuYW1lIjogIjQiLCJ4IjogMzksInkiOiA4MCwieiI6IDczLCJlbmFibGVkIjogdHJ1ZSwiY29sb3IiOiAxMTUzMjM2NDc5LCJhZGRlZEF0IjogMTY2OTk5OTE5ODkyN30seyJuYW1lIjogIjQxIiwieCI6IDk1LCJ5IjogNzYsInoiOiA1OCwiZW5hYmxlZCI6IHRydWUsImNvbG9yIjogMTE1MTk5MTgwMSwiYWRkZWRBdCI6IDE2NzAwMDAyMjcyMjV9LHsibmFtZSI6ICI0MiIsIngiOiA5NywieSI6IDc1LCJ6IjogNzAsImVuYWJsZWQiOiB0cnVlLCJjb2xvciI6IDEwNTE3MjE3MDYsImFkZGVkQXQiOiAxNjcwMDAwMjI3NDczfSx7Im5hbWUiOiAiMTAiLCJ4IjogNDUsInkiOiA3OSwieiI6IDcwLCJlbmFibGVkIjogdHJ1ZSwiY29sb3IiOiAxMDcyMzY1NTYxLCJhZGRlZEF0IjogMTY2OTk5OTUxMDUwOH0seyJuYW1lIjogIjI4IiwieCI6IDc1LCJ5IjogODIsInoiOiAyMCwiZW5hYmxlZCI6IHRydWUsImNvbG9yIjogMTA1MjkwMTM1OSwiYWRkZWRBdCI6IDE2Njk5OTk5ODY0MjZ9LHsibmFtZSI6ICIzIiwieCI6IDM2LCJ5IjogODAsInoiOiA4MCwiZW5hYmxlZCI6IHRydWUsImNvbG9yIjogOTUyNjI5NTAzLCJhZGRlZEF0IjogMTY2OTk5OTE5ODcyN30seyJuYW1lIjogIjciLCJ4IjogNDMsInkiOiA3NywieiI6IDUwLCJlbmFibGVkIjogdHJ1ZSwiY29sb3IiOiAxMTIwNTM0MjcxLCJhZGRlZEF0IjogMTY2OTk5OTE5OTQ2N30seyJuYW1lIjogIjgiLCJ4IjogNDMsInkiOiA3OSwieiI6IDczLCJlbmFibGVkIjogdHJ1ZSwiY29sb3IiOiAxMTUyNzEwMzk5LCJhZGRlZEF0IjogMTY2OTk5OTMxMTAyOX0seyJuYW1lIjogIjIiLCJ4IjogMzUsInkiOiA4LCJ6IjogNzEsImVuYWJsZWQiOiB0cnVlLCJjb2xvciI6IDEwNTQzNDMxNjQsImFkZGVkQXQiOiAxNjY5OTk5MTk4NTY3fSx7Im5hbWUiOiAiMzQiLCJ4IjogODksInkiOiA3NywieiI6IDg0LCJlbmFibGVkIjogdHJ1ZSwiY29sb3IiOiAxMDg2NDU1Nzk3LCJhZGRlZEF0IjogMTY3MDAwMDAyMjUyOX0seyJuYW1lIjogIjI2IiwieCI6IDczLCJ5IjogNzYsInoiOiAzMSwiZW5hYmxlZCI6IHRydWUsImNvbG9yIjogMTExOTE1Nzc1OSwiYWRkZWRBdCI6IDE2Njk5OTk3NTEwNzd9LHsibmFtZSI6ICIxMiIsIngiOiA0NywieSI6IDc3LCJ6IjogNjUsImVuYWJsZWQiOiB0cnVlLCJjb2xvciI6IDEwNzE4NDEyNzcsImFkZGVkQXQiOiAxNjY5OTk5NTEwOTA4fSx7Im5hbWUiOiAiMTYiLCJ4IjogNTIsInkiOiA3NSwieiI6IDQ1LCJlbmFibGVkIjogdHJ1ZSwiY29sb3IiOiAxMTM4NjIyNDU3LCJhZGRlZEF0IjogMTY2OTk5OTUxMTcwM30seyJuYW1lIjogIjMzIiwieCI6IDgyLCJ5IjogNzgsInoiOiAyNiwiZW5hYmxlZCI6IHRydWUsImNvbG9yIjogMTEwMzAzNDM2NywiYWRkZWRBdCI6IDE2NzAwMDAwMjIzNzl9LHsibmFtZSI6ICIyMSIsIngiOiA2MSwieSI6IDc4LCJ6IjogOTIsImVuYWJsZWQiOiB0cnVlLCJjb2xvciI6IDEwMjExODE5NDIsImFkZGVkQXQiOiAxNjY5OTk5NzQ5ODc3fSx7Im5hbWUiOiAiMjciLCJ4IjogNzMsInkiOiA3OSwieiI6IDUyLCJlbmFibGVkIjogdHJ1ZSwiY29sb3IiOiAxMDUxMDAwODI0LCJhZGRlZEF0IjogMTY2OTk5OTk4NjIzMH0seyJuYW1lIjogIjQ2IiwieCI6IDEwMywieSI6IDc0LCJ6IjogOTgsImVuYWJsZWQiOiB0cnVlLCJjb2xvciI6IDExMTg1Njg0MjUsImFkZGVkQXQiOiAxNjcwMDAwMjI4MjIzfSx7Im5hbWUiOiAiNDciLCJ4IjogMTA0LCJ5IjogNzgsInoiOiA2OCwiZW5hYmxlZCI6IHRydWUsImNvbG9yIjogOTUzNDc5OTM1LCJhZGRlZEF0IjogMTY3MDAwMDM1Nzk3NH0seyJuYW1lIjogIjYiLCJ4IjogNDIsInkiOiA3NywieiI6IDU4LCJlbmFibGVkIjogdHJ1ZSwiY29sb3IiOiAxMDE4NDk0OTcwLCJhZGRlZEF0IjogMTY2OTk5OTE5OTMyNX0seyJuYW1lIjogIjUiLCJ4IjogNDEsInkiOiA3OSwieiI6IDgxLCJlbmFibGVkIjogdHJ1ZSwiY29sb3IiOiAxMTM2MzI4MTkxLCJhZGRlZEF0IjogMTY2OTk5OTE5OTEyMX0seyJuYW1lIjogIjM2IiwieCI6IDkwLCJ5IjogNzcsInoiOiA0NiwiZW5hYmxlZCI6IHRydWUsImNvbG9yIjogMTExOTA5MDQzMSwiYWRkZWRBdCI6IDE2NzAwMDAwMjI5Mjh9LHsibmFtZSI6ICIxIiwieCI6IDMyLCJ5IjogODAsInoiOiA3NCwiZW5hYmxlZCI6IHRydWUsImNvbG9yIjogMTM4ODc3MzM3MSwiYWRkZWRBdCI6IDE2Njk5OTkxMDI4ODJ9LHsibmFtZSI6ICIzMSIsIngiOiA3OCwieSI6IDc3LCJ6IjogNDAsImVuYWJsZWQiOiB0cnVlLCJjb2xvciI6IDEwMTkyMTU4NjAsImFkZGVkQXQiOiAxNjcwMDAwMDIxOTc1fSx7Im5hbWUiOiAiMjkiLCJ4IjogNzYsInkiOiA3NiwieiI6IDU1LCJlbmFibGVkIjogdHJ1ZSwiY29sb3IiOiAxMTUzNTY0NjU1LCJhZGRlZEF0IjogMTY2OTk5OTk4NjYyN30seyJuYW1lIjogIjI1IiwieCI6IDY2LCJ5IjogODEsInoiOiAyOCwiZW5hYmxlZCI6IHRydWUsImNvbG9yIjogMTA1MjcwNDc1MCwiYWRkZWRBdCI6IDE2Njk5OTk3NTA5Mjd9LHsibmFtZSI6ICIzNSIsIngiOiA5MCwieSI6IDc3LCJ6IjogMzgsImVuYWJsZWQiOiB0cnVlLCJjb2xvciI6IDEwMTkzNDY5MzMsImFkZGVkQXQiOiAxNjcwMDAwMDIyNzI0fSx7Im5hbWUiOiAiMTgiLCJ4IjogNTUsInkiOiA4MCwieiI6IDM4LCJlbmFibGVkIjogdHJ1ZSwiY29sb3IiOiAxMDg4NjE4NDkzLCJhZGRlZEF0IjogMTY2OTk5OTUxMjE1N30seyJuYW1lIjogIjM5IiwieCI6IDkyLCJ5IjogNzQsInoiOiAxMDgsImVuYWJsZWQiOiB0cnVlLCJjb2xvciI6IDEwODY4NDkwMTQsImFkZGVkQXQiOiAxNjcwMDAwMjI2ODc5fSx7Im5hbWUiOiAiMTMiLCJ4IjogNTAsInkiOiA3NiwieiI6IDUyLCJlbmFibGVkIjogdHJ1ZSwiY29sb3IiOiAxMDcxOTcyMzQ0LCJhZGRlZEF0IjogMTY2OTk5OTUxMTEwMn0seyJuYW1lIjogIjQ0IiwieCI6IDk4LCJ5IjogNzcsInoiOiA3NiwiZW5hYmxlZCI6IHRydWUsImNvbG9yIjogMTA4NTg2NTk3OCwiYWRkZWRBdCI6IDE2NzAwMDAyMjc4ODF9LHsibmFtZSI6ICIzMiIsIngiOiA3OSwieSI6IDgwLCJ6IjogNzMsImVuYWJsZWQiOiB0cnVlLCJjb2xvciI6IDEwNTI3NzAyOTgsImFkZGVkQXQiOiAxNjcwMDAwMDIyMTc0fSx7Im5hbWUiOiAiMzciLCJ4IjogOTEsInkiOiA3NiwieiI6IDM4LCJlbmFibGVkIjogdHJ1ZSwiY29sb3IiOiAxMDUxMTMxMzkxLCJhZGRlZEF0IjogMTY3MDAwMDIyNjQyM30seyJuYW1lIjogIjQ1IiwieCI6IDk4LCJ5IjogNzgsInoiOiA3NSwiZW5hYmxlZCI6IHRydWUsImNvbG9yIjogMTIwMjg0NzczNywiYWRkZWRBdCI6IDE2NzAwMDAyMjgwNzN9XSwiaXNsYW5kIjogIndpbnRlciJ9XX0="; + List waypointCategories = Waypoints.fromSkytilsBase64(waypointCategoriesSkytilsBase64, ""); + List expectedWaypointCategories = List.of(new WaypointCategory("Frozen Treasure Locations", "winter", List.of( + new NamedWaypoint(new BlockPos(64, 78, 28), "24", new float[]{177 / 255f, 253 / 255f, 255 / 255f}, 64 / 255f, true), + new NamedWaypoint(new BlockPos(45, 79, 49), "9", new float[]{175 / 255f, 245 / 255f, 255 / 255f}, 64 / 255f, true), + new NamedWaypoint(new BlockPos(60, 76, 51), "20", new float[]{210 / 255f, 254 / 255f, 255 / 255f}, 56 / 255f, true), + new NamedWaypoint(new BlockPos(63, 76, 95), "23", new float[]{210 / 255f, 255 / 255f, 252 / 255f}, 60 / 255f, true), + new NamedWaypoint(new BlockPos(63, 76, 52), "22", new float[]{186 / 255f, 255 / 255f, 243 / 255f}, 62 / 255f, true), + new NamedWaypoint(new BlockPos(94, 77, 42), "40", new float[]{175 / 255f, 255 / 255f, 249 / 255f}, 58 / 255f, true), + new NamedWaypoint(new BlockPos(91, 77, 27), "38", new float[]{191 / 255f, 255 / 255f, 244 / 255f}, 62 / 255f, true), + new NamedWaypoint(new BlockPos(50, 80, 88), "15", new float[]{217 / 255f, 254 / 255f, 255 / 255f}, 63 / 255f, true), + new NamedWaypoint(new BlockPos(50, 79, 34), "14", new float[]{219 / 255f, 254 / 255f, 255 / 255f}, 65 / 255f, true), + new NamedWaypoint(new BlockPos(58, 79, 89), "19", new float[]{225 / 255f, 255 / 255f, 250 / 255f}, 68 / 255f, true), + new NamedWaypoint(new BlockPos(78, 74, 99), "30", new float[]{184 / 255f, 255 / 255f, 243 / 255f}, 66 / 255f, true), + new NamedWaypoint(new BlockPos(46, 80, 84), "11", new float[]{223 / 255f, 255 / 255f, 246 / 255f}, 63 / 255f, true), + new NamedWaypoint(new BlockPos(97, 81, 77), "43", new float[]{179 / 255f, 255 / 255f, 249 / 255f}, 62 / 255f, true), + new NamedWaypoint(new BlockPos(55, 79, 34), "17", new float[]{223 / 255f, 255 / 255f, 250 / 255f}, 65 / 255f, true), + new NamedWaypoint(new BlockPos(39, 80, 73), "4", new float[]{188 / 255f, 253 / 255f, 255 / 255f}, 68 / 255f, true), + new NamedWaypoint(new BlockPos(95, 76, 58), "41", new float[]{169 / 255f, 255 / 255f, 249 / 255f}, 68 / 255f, true), + new NamedWaypoint(new BlockPos(97, 75, 70), "42", new float[]{175 / 255f, 255 / 255f, 234 / 255f}, 62 / 255f, true), + new NamedWaypoint(new BlockPos(45, 79, 70), "10", new float[]{234 / 255f, 255 / 255f, 249 / 255f}, 63 / 255f, true), + new NamedWaypoint(new BlockPos(75, 82, 20), "28", new float[]{193 / 255f, 255 / 255f, 239 / 255f}, 62 / 255f, true), + new NamedWaypoint(new BlockPos(36, 80, 80), "3", new float[]{199 / 255f, 248 / 255f, 255 / 255f}, 56 / 255f, true), + new NamedWaypoint(new BlockPos(43, 77, 50), "7", new float[]{201 / 255f, 254 / 255f, 255 / 255f}, 66 / 255f, true), + new NamedWaypoint(new BlockPos(43, 79, 73), "8", new float[]{180 / 255f, 246 / 255f, 255 / 255f}, 68 / 255f, true), + new NamedWaypoint(new BlockPos(35, 8, 71), "2", new float[]{215 / 255f, 255 / 255f, 252 / 255f}, 62 / 255f, true), + new NamedWaypoint(new BlockPos(89, 77, 84), "34", new float[]{193 / 255f, 255 / 255f, 245 / 255f}, 64 / 255f, true), + new NamedWaypoint(new BlockPos(73, 76, 31), "26", new float[]{180 / 255f, 253 / 255f, 255 / 255f}, 66 / 255f, true), + new NamedWaypoint(new BlockPos(47, 77, 65), "12", new float[]{226 / 255f, 255 / 255f, 253 / 255f}, 63 / 255f, true), + new NamedWaypoint(new BlockPos(52, 75, 45), "16", new float[]{221 / 255f, 255 / 255f, 249 / 255f}, 67 / 255f, true), + new NamedWaypoint(new BlockPos(82, 78, 26), "33", new float[]{190 / 255f, 247 / 255f, 255 / 255f}, 65 / 255f, true), + new NamedWaypoint(new BlockPos(61, 78, 92), "21", new float[]{221 / 255f, 255 / 255f, 246 / 255f}, 60 / 255f, true), + new NamedWaypoint(new BlockPos(73, 79, 52), "27", new float[]{164 / 255f, 255 / 255f, 248 / 255f}, 62 / 255f, true), + new NamedWaypoint(new BlockPos(103, 74, 98), "46", new float[]{171 / 255f, 255 / 255f, 233 / 255f}, 66 / 255f, true), + new NamedWaypoint(new BlockPos(104, 78, 68), "47", new float[]{212 / 255f, 242 / 255f, 255 / 255f}, 56 / 255f, true), + new NamedWaypoint(new BlockPos(42, 77, 58), "6", new float[]{180 / 255f, 255 / 255f, 250 / 255f}, 60 / 255f, true), + new NamedWaypoint(new BlockPos(41, 79, 81), "5", new float[]{186 / 255f, 253 / 255f, 255 / 255f}, 67 / 255f, true), + new NamedWaypoint(new BlockPos(90, 77, 46), "36", new float[]{179 / 255f, 246 / 255f, 255 / 255f}, 66 / 255f, true), + new NamedWaypoint(new BlockPos(32, 80, 74), "1", new float[]{198 / 255f, 255 / 255f, 251 / 255f}, 82 / 255f, true), + new NamedWaypoint(new BlockPos(78, 77, 40), "31", new float[]{191 / 255f, 255 / 255f, 244 / 255f}, 60 / 255f, true), + new NamedWaypoint(new BlockPos(76, 76, 55), "29", new float[]{193 / 255f, 255 / 255f, 239 / 255f}, 68 / 255f, true), + new NamedWaypoint(new BlockPos(66, 81, 28), "25", new float[]{190 / 255f, 255 / 255f, 238 / 255f}, 62 / 255f, true), + new NamedWaypoint(new BlockPos(90, 77, 38), "35", new float[]{193 / 255f, 255 / 255f, 245 / 255f}, 60 / 255f, true), + new NamedWaypoint(new BlockPos(55, 80, 38), "18", new float[]{226 / 255f, 255 / 255f, 253 / 255f}, 64 / 255f, true), + new NamedWaypoint(new BlockPos(92, 74, 108), "39", new float[]{199 / 255f, 255 / 255f, 246 / 255f}, 64 / 255f, true), + new NamedWaypoint(new BlockPos(50, 76, 52), "13", new float[]{228 / 255f, 255 / 255f, 248 / 255f}, 63 / 255f, true), + new NamedWaypoint(new BlockPos(98, 77, 76), "44", new float[]{184 / 255f, 255 / 255f, 250 / 255f}, 64 / 255f, true), + new NamedWaypoint(new BlockPos(79, 80, 73), "32", new float[]{191 / 255f, 255 / 255f, 250 / 255f}, 62 / 255f, true), + new NamedWaypoint(new BlockPos(91, 76, 38), "37", new float[]{166 / 255f, 253 / 255f, 255 / 255f}, 62 / 255f, true), + new NamedWaypoint(new BlockPos(98, 78, 75), "45", new float[]{177 / 255f, 255 / 255f, 249 / 255f}, 71 / 255f, true) + ))); + + Assertions.assertEquals(expectedWaypointCategories, waypointCategories); + } + + //https://pastebin.com/c4PjUZjJ + @Test + void testFromSkytilsBase64CrystalHollowsWaypoints() { + String waypointsSkytilsBase64 = "W3sibmFtZSI6IlNob3V0b3V0IFRlYmV5IGFuZCB0cmV2YW55YSIsIngiOjUxMCwieSI6NTMsInoiOjM5MywiaXNsYW5kIjoiY3J5c3RhbF9ob2xsb3dzIiwiZW5hYmxlZCI6dHJ1ZSwiY29sb3IiOi02NTUzNn0seyJuYW1lIjoiMDciLCJ4Ijo0NzksInkiOjM5LCJ6Ijo0MDgsImlzbGFuZCI6ImNyeXN0YWxfaG9sbG93cyIsImVuYWJsZWQiOnRydWUsImNvbG9yIjotNjU1MzZ9LHsibmFtZSI6IjExIiwieCI6NDk1LCJ5IjozNCwieiI6NDE4LCJpc2xhbmQiOiJjcnlzdGFsX2hvbGxvd3MiLCJlbmFibGVkIjp0cnVlLCJjb2xvciI6LTY1NTM2fSx7Im5hbWUiOiIwOSIsIngiOjQ4NSwieSI6MzMsInoiOjQwMiwiaXNsYW5kIjoiY3J5c3RhbF9ob2xsb3dzIiwiZW5hYmxlZCI6dHJ1ZSwiY29sb3IiOi02NTUzNn0seyJuYW1lIjoiMjMiLCJ4Ijo1MTQsInkiOjU1LCJ6IjozODMsImlzbGFuZCI6ImNyeXN0YWxfaG9sbG93cyIsImVuYWJsZWQiOnRydWUsImNvbG9yIjotNjU1MzZ9LHsibmFtZSI6IjA2IiwieCI6NDgzLCJ5Ijo0MiwieiI6NDA1LCJpc2xhbmQiOiJjcnlzdGFsX2hvbGxvd3MiLCJlbmFibGVkIjp0cnVlLCJjb2xvciI6LTY1NTM2fSx7Im5hbWUiOiIwMSIsIngiOjUwMiwieSI6NDgsInoiOjQwMywiaXNsYW5kIjoiY3J5c3RhbF9ob2xsb3dzIiwiZW5hYmxlZCI6dHJ1ZSwiY29sb3IiOi02NTUzNn0seyJuYW1lIjoiMTgiLCJ4Ijo1MDMsInkiOjU2LCJ6Ijo0MzYsImlzbGFuZCI6ImNyeXN0YWxfaG9sbG93cyIsImVuYWJsZWQiOnRydWUsImNvbG9yIjotNjU1MzZ9LHsibmFtZSI6IjAwIC0gU3RhcnQiLCJ4Ijo1MDMsInkiOjQ4LCJ6Ijo0MDAsImlzbGFuZCI6ImNyeXN0YWxfaG9sbG93cyIsImVuYWJsZWQiOnRydWUsImNvbG9yIjotNjU1MzZ9LHsibmFtZSI6IjEzIiwieCI6NDc4LCJ5Ijo0NCwieiI6NDE5LCJpc2xhbmQiOiJjcnlzdGFsX2hvbGxvd3MiLCJlbmFibGVkIjp0cnVlLCJjb2xvciI6LTY1NTM2fSx7Im5hbWUiOiIxOSIsIngiOjUwMSwieSI6NTcsInoiOjQzOCwiaXNsYW5kIjoiY3J5c3RhbF9ob2xsb3dzIiwiZW5hYmxlZCI6dHJ1ZSwiY29sb3IiOi02NTUzNn0seyJuYW1lIjoiMDIiLCJ4Ijo0OTYsInkiOjQ1LCJ6Ijo0MDcsImlzbGFuZCI6ImNyeXN0YWxfaG9sbG93cyIsImVuYWJsZWQiOnRydWUsImNvbG9yIjotNjU1MzZ9LHsibmFtZSI6IjA0IiwieCI6NDk1LCJ5Ijo1MywieiI6NDA0LCJpc2xhbmQiOiJjcnlzdGFsX2hvbGxvd3MiLCJlbmFibGVkIjp0cnVlLCJjb2xvciI6LTY1NTM2fSx7Im5hbWUiOiIwNSIsIngiOjQ3OSwieSI6NDksInoiOjQwNywiaXNsYW5kIjoiY3J5c3RhbF9ob2xsb3dzIiwiZW5hYmxlZCI6dHJ1ZSwiY29sb3IiOi02NTUzNn0seyJuYW1lIjoiMTIiLCJ4Ijo1MDQsInkiOjQxLCJ6Ijo0MTksImlzbGFuZCI6ImNyeXN0YWxfaG9sbG93cyIsImVuYWJsZWQiOnRydWUsImNvbG9yIjotNjU1MzZ9LHsibmFtZSI6IjAzIiwieCI6NDkwLCJ5Ijo0NSwieiI6MzkyLCJpc2xhbmQiOiJjcnlzdGFsX2hvbGxvd3MiLCJlbmFibGVkIjp0cnVlLCJjb2xvciI6LTY1NTM2fSx7Im5hbWUiOiIxMCIsIngiOjQ4OCwieSI6MzIsInoiOjQyMSwiaXNsYW5kIjoiY3J5c3RhbF9ob2xsb3dzIiwiZW5hYmxlZCI6dHJ1ZSwiY29sb3IiOi02NTUzNn0seyJuYW1lIjoiMjIiLCJ4Ijo1MDcsInkiOjUyLCJ6IjozODYsImlzbGFuZCI6ImNyeXN0YWxfaG9sbG93cyIsImVuYWJsZWQiOnRydWUsImNvbG9yIjotNjU1MzZ9LHsibmFtZSI6IjE2IiwieCI6NDg4LCJ5Ijo1NSwieiI6NDIxLCJpc2xhbmQiOiJjcnlzdGFsX2hvbGxvd3MiLCJlbmFibGVkIjp0cnVlLCJjb2xvciI6LTY1NTM2fSx7Im5hbWUiOiI5OSAtIEVuZCIsIngiOjUxMCwieSI6NTIsInoiOjM5MywiaXNsYW5kIjoiY3J5c3RhbF9ob2xsb3dzIiwiZW5hYmxlZCI6dHJ1ZSwiY29sb3IiOi02NTUzNn0seyJuYW1lIjoiMTUiLCJ4Ijo0ODYsInkiOjU1LCJ6Ijo0MjgsImlzbGFuZCI6ImNyeXN0YWxfaG9sbG93cyIsImVuYWJsZWQiOnRydWUsImNvbG9yIjotNjU1MzZ9LHsibmFtZSI6IjE0IiwieCI6NDc1LCJ5Ijo0NCwieiI6NDI5LCJpc2xhbmQiOiJjcnlzdGFsX2hvbGxvd3MiLCJlbmFibGVkIjp0cnVlLCJjb2xvciI6LTY1NTM2fSx7Im5hbWUiOiIxNyIsIngiOjUwOSwieSI6NTAsInoiOjQzMiwiaXNsYW5kIjoiY3J5c3RhbF9ob2xsb3dzIiwiZW5hYmxlZCI6dHJ1ZSwiY29sb3IiOi02NTUzNn0seyJuYW1lIjoiMjAiLCJ4Ijo1MDUsInkiOjU4LCJ6Ijo0MjYsImlzbGFuZCI6ImNyeXN0YWxfaG9sbG93cyIsImVuYWJsZWQiOnRydWUsImNvbG9yIjotNjU1MzZ9LHsibmFtZSI6IjA4IiwieCI6NDgwLCJ5IjozOCwieiI6NDA1LCJpc2xhbmQiOiJjcnlzdGFsX2hvbGxvd3MiLCJlbmFibGVkIjp0cnVlLCJjb2xvciI6LTY1NTM2fSx7Im5hbWUiOiIyMSIsIngiOjQ5NywieSI6NTUsInoiOjM5MSwiaXNsYW5kIjoiY3J5c3RhbF9ob2xsb3dzIiwiZW5hYmxlZCI6dHJ1ZSwiY29sb3IiOi02NTUzNn1d"; + List waypointCategories = Waypoints.fromSkytilsBase64(waypointsSkytilsBase64, "crystal_hollows"); + List expectedWaypointCategories = List.of(new WaypointCategory("New Category", "crystal_hollows", List.of( + new NamedWaypoint(new BlockPos(510, 53, 393), "Shoutout Tebey and trevanya", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(479, 39, 408), "07", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(495, 34, 418), "11", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(485, 33, 402), "09", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(514, 55, 383), "23", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(483, 42, 405), "06", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(502, 48, 403), "01", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(503, 56, 436), "18", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(503, 48, 400), "00 - Start", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(478, 44, 419), "13", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(501, 57, 438), "19", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(496, 45, 407), "02", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(495, 53, 404), "04", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(479, 49, 407), "05", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(504, 41, 419), "12", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(490, 45, 392), "03", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(488, 32, 421), "10", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(507, 52, 386), "22", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(488, 55, 421), "16", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(510, 52, 393), "99 - End", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(486, 55, 428), "15", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(475, 44, 429), "14", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(509, 50, 432), "17", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(505, 58, 426), "20", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(480, 38, 405), "08", new float[]{1, 0, 0}, 1, true), + new NamedWaypoint(new BlockPos(497, 55, 391), "21", new float[]{1, 0, 0}, 1, true) + ))); + + Assertions.assertEquals(expectedWaypointCategories, waypointCategories); + } } From ee6664dd964f395cb5737b230123d65cb7c13833 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Fri, 24 May 2024 20:28:21 -0400 Subject: [PATCH 09/10] Add text predicate and default pos --- .../waypoint/WaypointsListWidget.java | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java index 3e18d67345..96e82b63ec 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java @@ -10,6 +10,8 @@ import net.minecraft.client.gui.Selectable; import net.minecraft.client.gui.widget.*; import net.minecraft.text.Text; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.HitResult; import net.minecraft.util.math.BlockPos; import java.util.ArrayList; @@ -91,6 +93,10 @@ void updateButtons() { } } + private BlockPos getDefaultPos() { + return client.crosshairTarget instanceof BlockHitResult blockHitResult && client.crosshairTarget.getType() == HitResult.Type.BLOCK ? blockHitResult.getBlockPos() : client.player != null ? client.player.getBlockPos() : BlockPos.ORIGIN; + } + protected abstract static class AbstractWaypointEntry extends Entry { } @@ -180,7 +186,7 @@ protected class WaypointEntry extends AbstractWaypointEntry { private final ButtonWidget buttonDelete; public WaypointEntry(WaypointCategoryEntry category) { - this(category, new NamedWaypoint(BlockPos.ORIGIN, "New Waypoint", new float[]{0f, 1f, 0f})); + this(category, new NamedWaypoint(getDefaultPos(), "New Waypoint", new float[]{0f, 1f, 0f})); } public WaypointEntry(WaypointCategoryEntry category, NamedWaypoint waypoint) { @@ -192,12 +198,15 @@ public WaypointEntry(WaypointCategoryEntry category, NamedWaypoint waypoint) { nameField.setChangedListener(this::updateName); xField = new TextFieldWidget(client.textRenderer, 26, 20, Text.literal("X")); xField.setText(Integer.toString(waypoint.pos.getX())); + xField.setTextPredicate(this::checkInt); xField.setChangedListener(this::updateX); yField = new TextFieldWidget(client.textRenderer, 26, 20, Text.literal("Y")); yField.setText(Integer.toString(waypoint.pos.getY())); + yField.setTextPredicate(this::checkInt); yField.setChangedListener(this::updateY); zField = new TextFieldWidget(client.textRenderer, 26, 20, Text.literal("Z")); zField.setText(Integer.toString(waypoint.pos.getZ())); + zField.setTextPredicate(this::checkInt); zField.setChangedListener(this::updateZ); colorField = new TextFieldWidget(client.textRenderer, 56, 20, Text.literal("Color")); colorField.setText(String.format("%02X%02X%02X%02X", (int) (waypoint.alpha * 255), (int) (waypoint.getColorComponents()[0] * 255), (int) (waypoint.getColorComponents()[1] * 255), (int) (waypoint.getColorComponents()[2] * 255))); @@ -219,7 +228,7 @@ public List children() { return children; } - public void updateName(String name) { + private void updateName(String name) { if (waypoint.name.getString().equals(name)) return; int index = category.category.waypoints().indexOf(waypoint); waypoint = waypoint.withName(name); @@ -228,19 +237,28 @@ public void updateName(String name) { } } - public void updateX(String xString) { + private boolean checkInt(String string) { + try { + Integer.parseInt(string); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + private void updateX(String xString) { updateInt(xString, waypoint.pos.getX(), waypoint::withX); } - public void updateY(String yString) { + private void updateY(String yString) { updateInt(yString, waypoint.pos.getY(), waypoint::withY); } - public void updateZ(String zString) { + private void updateZ(String zString) { updateInt(zString, waypoint.pos.getZ(), waypoint::withZ); } - public void updateInt(String newValueString, int currentValue, Int2ObjectFunction wither) { + private void updateInt(String newValueString, int currentValue, Int2ObjectFunction wither) { try { int index = category.category.waypoints().indexOf(waypoint); int newValue = Integer.parseInt(newValueString); @@ -254,7 +272,7 @@ public void updateInt(String newValueString, int currentValue, Int2ObjectFunctio } } - public void updateColor(String colorString) { + private void updateColor(String colorString) { try { int index = category.category.waypoints().indexOf(waypoint); int colorInt = Integer.parseInt(colorString, 16); From bd11cc01bfa90695ad7498336a90ee4efb5ec813 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Thu, 13 Jun 2024 13:07:48 +0800 Subject: [PATCH 10/10] Add dropdown scrolling and allow empty string and negative sign in coordinates --- .../waypoint/AbstractWaypointsScreen.java | 10 ++++- .../skyblock/waypoint/DropdownWidget.java | 39 +++++++++++++------ .../waypoint/WaypointsListWidget.java | 15 +++++-- 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/AbstractWaypointsScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/AbstractWaypointsScreen.java index 932bc144f7..da6f52c871 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/AbstractWaypointsScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/AbstractWaypointsScreen.java @@ -37,7 +37,7 @@ public AbstractWaypointsScreen(Text title, T parent, Multimap(client, width - 160, 8, 150, Arrays.asList(Location.values()), this::islandChanged, Location.from(island))); + islandWidget = addDrawableChild(new DropdownWidget<>(client, width - 160, 8, 150, height - 8, Arrays.asList(Location.values()), this::islandChanged, Location.from(island))); } @Override @@ -50,6 +50,14 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { return mouseClicked; } + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { + if (islandWidget.isMouseOver(mouseX, mouseY) && islandWidget.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount)) { + return true; + } + return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); + } + protected void islandChanged(Location location) { island = location.id(); waypointsListWidget.setIsland(island); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/DropdownWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/DropdownWidget.java index 157b0b150c..724cb461ee 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/DropdownWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/DropdownWidget.java @@ -20,8 +20,8 @@ public class DropdownWidget extends ElementListWidget protected T selected; protected boolean open; - public DropdownWidget(MinecraftClient minecraftClient, int x, int y, int width, List entries, Consumer selectCallback, T selected) { - super(minecraftClient, width, (entries.size() + 1) * ENTRY_HEIGHT + 8, y, ENTRY_HEIGHT); + public DropdownWidget(MinecraftClient minecraftClient, int x, int y, int width, int maxHeight, List entries, Consumer selectCallback, T selected) { + super(minecraftClient, width, Math.min((entries.size() + 1) * ENTRY_HEIGHT + 8, maxHeight), y, ENTRY_HEIGHT); setX(x); this.entries = entries; this.selectCallback = selectCallback; @@ -58,29 +58,44 @@ public void renderWidget(DrawContext context, int mouseX, int mouseY, float delt context.getMatrices().push(); context.getMatrices().translate(0, 0, 100); - context.fill(getX(), getY(), getX() + width, getY() + headerHeight, 0xFF000000); - context.drawHorizontalLine(getX(), getX() + width, getY(), 0xFFFFFFFF); - context.drawHorizontalLine(getX(), getX() + width, getY() + headerHeight, 0xFFFFFFFF); - context.drawVerticalLine(getX(), getY(), getY() + headerHeight, 0xFFFFFFFF); - context.drawVerticalLine(getX() + width, getY(), getY() + headerHeight, 0xFFFFFFFF); + int y = getY() - (int) getScrollAmount(); + int height = getMaxPosition(); + + context.fill(getX(), y, getX() + width, y + headerHeight, 0xFF000000); + context.drawHorizontalLine(getX(), getX() + width, y, 0xFFFFFFFF); + context.drawHorizontalLine(getX(), getX() + width, y + headerHeight, 0xFFFFFFFF); + context.drawVerticalLine(getX(), y, y + headerHeight, 0xFFFFFFFF); + context.drawVerticalLine(getX() + width, y, y + headerHeight, 0xFFFFFFFF); if (open) { - context.fill(getX(), getY() + headerHeight + 1, getX() + width, getY() + height, 0xFF000000); - context.drawHorizontalLine(getX(), getX() + width, getY() + height, 0xFFFFFFFF); - context.drawVerticalLine(getX(), getY() + headerHeight, getY() + height, 0xFFFFFFFF); - context.drawVerticalLine(getX() + width, getY() + headerHeight, getY() + height, 0xFFFFFFFF); + context.fill(getX(), y + headerHeight + 1, getX() + width, y + height, 0xFF000000); + context.drawHorizontalLine(getX(), getX() + width, y + height, 0xFFFFFFFF); + context.drawVerticalLine(getX(), y + headerHeight, y + height, 0xFFFFFFFF); + context.drawVerticalLine(getX() + width, y + headerHeight, y + height, 0xFFFFFFFF); super.renderWidget(context, mouseX, mouseY, delta); } else { - renderHeader(context, getRowLeft(), getY() + 4 - (int) getScrollAmount()); + renderHeader(context, getRowLeft(), y + 4); } context.getMatrices().pop(); } + @Override + protected void drawMenuListBackground(DrawContext context) {} + + @Override + protected void drawHeaderAndFooterSeparators(DrawContext context) {} + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) { + return open && super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount); + } + protected void select(T entry) { selected = entry; open = false; + setScrollAmount(0); if (selected != prevSelected) { selectCallback.accept(entry); prevSelected = selected; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java index 96e82b63ec..045c694dfc 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/waypoint/WaypointsListWidget.java @@ -239,7 +239,7 @@ private void updateName(String name) { private boolean checkInt(String string) { try { - Integer.parseInt(string); + parseEmptiableInt(string); return true; } catch (NumberFormatException e) { return false; @@ -261,7 +261,7 @@ private void updateZ(String zString) { private void updateInt(String newValueString, int currentValue, Int2ObjectFunction wither) { try { int index = category.category.waypoints().indexOf(waypoint); - int newValue = Integer.parseInt(newValueString); + int newValue = parseEmptiableInt(newValueString); if (newValue == currentValue) return; waypoint = wither.apply(newValue); if (index >= 0) { @@ -275,7 +275,7 @@ private void updateInt(String newValueString, int currentValue, Int2ObjectFuncti private void updateColor(String colorString) { try { int index = category.category.waypoints().indexOf(waypoint); - int colorInt = Integer.parseInt(colorString, 16); + int colorInt = parseEmptiableInt(colorString, 16); float[] colorComponents = {((colorInt & 0x00FF0000) >> 16) / 255f, ((colorInt & 0x0000FF00) >> 8) / 255f, (colorInt & 0x000000FF) / 255f}; float alpha = ((colorInt & 0xFF000000) >>> 24) / 255f; if (Arrays.equals(waypoint.getColorComponents(), colorComponents) && waypoint.alpha == alpha) return; @@ -288,6 +288,15 @@ private void updateColor(String colorString) { } } + private int parseEmptiableInt(String value) throws NumberFormatException { + return value.isEmpty() || value.equals("-") ? 0 : Integer.parseInt(value); + } + + @SuppressWarnings("SameParameterValue") + private int parseEmptiableInt(String value, int radix) throws NumberFormatException { + return value.isEmpty() || value.equals("-") ? 0 : Integer.parseInt(value, radix); + } + @Override public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { context.drawTextWithShadow(client.textRenderer, "X:", width / 2 - 56, y + 6, 0xFFFFFF);