From 32039f2163226964134a76b2cb0b3773d5df9a8b Mon Sep 17 00:00:00 2001 From: qb42 <42453758+qb42@users.noreply.github.com> Date: Sun, 12 Jul 2026 19:39:31 -0400 Subject: [PATCH 1/5] Add zone and name to enigma_soul_waypoints.json --- .../skyblocker/skyblock/rift/EnigmaSouls.java | 115 +++- .../rift/enigma_soul_waypoints.json | 596 ++++++++++-------- .../de/hysky/skyblocker/VerifyJsonTest.java | 8 +- 3 files changed, 436 insertions(+), 283 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java b/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java index 9fa76502a1e..4b9b6d22752 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java @@ -24,7 +24,9 @@ import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.resources.Identifier; +import net.minecraft.util.StringRepresentable; import net.minecraft.world.item.DyeColor; +import org.apache.commons.text.WordUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,11 +39,13 @@ import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; import java.util.function.Supplier; +import java.util.stream.Stream; import static net.fabricmc.fabric.api.client.command.v2.ClientCommands.literal; @@ -49,7 +53,7 @@ public class EnigmaSouls { private static final Logger LOGGER = LoggerFactory.getLogger(EnigmaSouls.class); private static final Supplier TYPE_SUPPLIER = () -> SkyblockerConfigManager.get().uiAndVisuals.waypoints.waypointType; private static final Identifier WAYPOINTS_JSON = SkyblockerMod.id("rift/enigma_soul_waypoints.json"); - private static final Map SOUL_WAYPOINTS = new HashMap<>(52); + private static final Map> SOUL_WAYPOINTS = HashMap.newHashMap(9); private static final Path FOUND_SOULS_FILE = SkyblockerMod.CONFIG_DIR.resolve("found_enigma_souls.json"); private static final float[] GREEN = ColorUtils.getFloatComponents(DyeColor.GREEN); private static final float[] RED = ColorUtils.getFloatComponents(DyeColor.RED); @@ -60,26 +64,47 @@ static void load(Minecraft client) { //Load waypoints soulsLoaded = CompletableFuture.runAsync(() -> { try (BufferedReader reader = client.getResourceManager().openAsReader(WAYPOINTS_JSON)) { - JsonObject file = JsonParser.parseReader(reader).getAsJsonObject(); - JsonArray waypoints = file.get("waypoints").getAsJsonArray(); + JsonObject zones = JsonParser.parseReader(reader).getAsJsonObject().getAsJsonObject("zones"); - for (int i = 0; i < waypoints.size(); i++) { - JsonObject waypoint = waypoints.get(i).getAsJsonObject(); - BlockPos pos = new BlockPos(waypoint.get("x").getAsInt(), waypoint.get("y").getAsInt(), waypoint.get("z").getAsInt()); - SOUL_WAYPOINTS.put(pos, new EnigmaSoul(pos, TYPE_SUPPLIER, GREEN, RED)); - } + for (Map.Entry zoneJson : zones.entrySet()) { + RiftZone zone = RiftZone.fromSerializedName(zoneJson.getKey()); + JsonArray waypoints_list = zoneJson.getValue().getAsJsonArray(); + Map waypoints = HashMap.newHashMap(waypoints_list.size()); + + for (JsonElement wp : waypoints_list) { + JsonObject waypoint = wp.getAsJsonObject(); + BlockPos pos = new BlockPos(waypoint.get("x").getAsInt(), waypoint.get("y").getAsInt(), waypoint.get("z").getAsInt()); + waypoints.put(pos, new EnigmaSoul(pos, zone, waypoint.get("name").getAsString())); + } + SOUL_WAYPOINTS.put(zone, waypoints); + } } catch (IOException e) { LOGGER.error("[Skyblocker] There was an error while loading enigma soul waypoints!", e); } + LOGGER.info("[Skyblocker] Loaded {} enigma souls across {} locations", SOUL_WAYPOINTS.values().stream().mapToInt(Map::size).sum(), SOUL_WAYPOINTS.size()); + + if (SOUL_WAYPOINTS.size() != RiftZone.values().length) { + LOGGER.debug("[Skyblocker] Zones from enigma soul json do not match RiftZone enum!"); + } + //Load found souls try (BufferedReader reader = Files.newBufferedReader(FOUND_SOULS_FILE)) { for (Map.Entry profile : JsonParser.parseReader(reader).getAsJsonObject().asMap().entrySet()) { - for (JsonElement foundSoul : profile.getValue().getAsJsonArray().asList()) { - SOUL_WAYPOINTS.get(PosUtils.parsePosString(foundSoul.getAsString())).setFound(profile.getKey()); + for (JsonElement foundSoul : profile.getValue().getAsJsonArray()) { + BlockPos pos = PosUtils.parsePosString(foundSoul.getAsString()); + for (Map zone : SOUL_WAYPOINTS.values()) { + ProfileAwareWaypoint waypoint = zone.get(pos); + if (waypoint != null) { + waypoint.setFound(profile.getKey()); + break; + } + } } } + + LOGGER.debug("[Skyblocker] Loaded found enigma souls"); } catch (NoSuchFileException _) { } catch (IOException e) { LOGGER.error("[Skyblocker] There was an error while loading found enigma souls!", e); @@ -89,12 +114,12 @@ static void load(Minecraft client) { static void save(Minecraft client) { Map> foundSouls = new HashMap<>(); - for (ProfileAwareWaypoint soul : SOUL_WAYPOINTS.values()) { + streamWaypoints().forEach(soul -> { for (String profile : soul.foundProfiles) { foundSouls.computeIfAbsent(profile, _ -> new HashSet<>()); foundSouls.get(profile).add(soul.pos); } - } + }); JsonObject json = new JsonObject(); for (Map.Entry> foundSoulsForProfile : foundSouls.entrySet()) { @@ -109,6 +134,7 @@ static void save(Minecraft client) { try (BufferedWriter writer = Files.newBufferedWriter(FOUND_SOULS_FILE)) { SkyblockerMod.GSON.toJson(json, writer); + LOGGER.info("[Skyblocker] Saved found enigma souls"); } catch (IOException e) { LOGGER.error("[Skyblocker] There was an error while saving found enigma souls!", e); } @@ -118,11 +144,11 @@ static void extractRendering(PrimitiveCollector collector) { OtherLocationsConfig.Rift config = SkyblockerConfigManager.get().otherLocations.rift; if (Utils.isInTheRift() && config.enigmaSoulWaypoints && soulsLoaded.isDone()) { - for (Waypoint soul : SOUL_WAYPOINTS.values()) { + streamWaypoints().forEach(soul -> { if (soul.shouldRender() || config.highlightFoundEnigmaSouls) { soul.extractRendering(collector); } - } + }); } } @@ -142,13 +168,13 @@ static void registerCommands(CommandDispatcher dispat .then(literal("rift") .then(literal("enigmaSouls") .then(literal("markAllFound").executes(context -> { - SOUL_WAYPOINTS.values().forEach(Waypoint::setFound); + streamWaypoints().forEach(Waypoint::setFound); context.getSource().sendFeedback(Constants.PREFIX.get().append(Component.translatable("skyblocker.rift.enigmaSouls.markAllFound"))); return Command.SINGLE_SUCCESS; })) .then(literal("markAllMissing").executes(context -> { - SOUL_WAYPOINTS.values().forEach(Waypoint::setMissing); + streamWaypoints().forEach(Waypoint::setMissing); context.getSource().sendFeedback(Constants.PREFIX.get().append(Component.translatable("skyblocker.rift.enigmaSouls.markAllMissing"))); return Command.SINGLE_SUCCESS; @@ -172,21 +198,72 @@ private static void markClosestSoul(boolean asFound) { if (!soulsLoaded.isDone() || player == null) return; - SOUL_WAYPOINTS.values().stream() + streamWaypoints() .filter(Waypoint::shouldRender) .min(Comparator.comparingDouble(soul -> soul.pos.distToCenterSqr(player.position()))) .filter(soul -> soul.pos.distToCenterSqr(player.position()) <= 16) .ifPresent(asFound ? Waypoint::setFound : Waypoint::setMissing); } + private static Stream streamWaypoints() { + return SOUL_WAYPOINTS.values().stream().flatMap(zone -> zone.values().stream()); + } + private static class EnigmaSoul extends ProfileAwareWaypoint { - private EnigmaSoul(BlockPos pos, Supplier typeSupplier, float[] missingColor, float[] foundColor) { - super(pos, typeSupplier, missingColor, foundColor); + public final RiftZone zone; + public final String name; + + private EnigmaSoul(BlockPos pos, RiftZone zone, String name) { + super(pos, TYPE_SUPPLIER, GREEN, RED); + this.zone = zone; + this.name = name; } @Override public boolean shouldRender() { return super.shouldRender() || SkyblockerConfigManager.get().otherLocations.rift.highlightFoundEnigmaSouls; } + + @Override + public void setFound() { + setFound(Utils.getProfile()); + } + + @Override + public void setFound(String profile) { + LOGGER.debug("[Skyblocker] Set enigma soul found for {}: {}/{}", profile, zone.displayName(), name); + super.setFound(profile); + } + + @Override + public void setMissing() { + LOGGER.debug("[Skyblocker] Set enigma soul missing: {}/{}", zone.displayName(), name); + super.setMissing(); + } + } + + private enum RiftZone implements StringRepresentable { + WYLD_WOODS, + BLACK_LAGOON, + WEST_VILLAGE, + DREADFARM, + VILLAGE_PLAZA, + LIVING_CAVE, + COLOSSEUM, + STILLGORE_CHATEAU, + MOUNTAINTOP; + + @Override + public String getSerializedName() { + return name().toLowerCase(Locale.ENGLISH); + } + + public String displayName() { + return WordUtils.capitalizeFully(name().replace("_", " ")); + } + + public static RiftZone fromSerializedName(String name) { + return valueOf(name.toUpperCase(Locale.ENGLISH)); + } } } diff --git a/src/main/resources/assets/skyblocker/rift/enigma_soul_waypoints.json b/src/main/resources/assets/skyblocker/rift/enigma_soul_waypoints.json index 58a1d94dd2f..daf6a9bc506 100644 --- a/src/main/resources/assets/skyblocker/rift/enigma_soul_waypoints.json +++ b/src/main/resources/assets/skyblocker/rift/enigma_soul_waypoints.json @@ -1,265 +1,335 @@ { - "credit": "Official Hypixel Wiki - https://wiki.hypixel.net", - "waypoints": [ - { - "x": -15, - "y": 91, - "z": 94 - }, - { - "x": -27, - "y": 71, - "z": 90 - }, - { - "x": -6, - "y": 60, - "z": 226 - }, - { - "x": -142, - "y": 68, - "z": 174 - }, - { - "x": -137, - "y": 51, - "z": 120 - }, - { - "x": -129, - "y": 72, - "z": 77 - }, - { - "x": -27, - "y": 89, - "z": 136 - }, - { - "x": -137, - "y": 133, - "z": 156 - }, - { - "x": -108, - "y": 117, - "z": 123 - }, - { - "x": -115, - "y": 69, - "z": 61 - }, - { - "x": 43, - "y": 91, - "z": 56 - }, - { - "x": -168, - "y": 81, - "z": 12 - }, - { - "x": -204, - "y": 75, - "z": 49 - }, - { - "x": -93, - "y": 73, - "z": 36 - }, - { - "x": -102, - "y": 72, - "z": -103 - }, - { - "x": -34, - "y": 71, - "z": -88 - }, - { - "x": -106, - "y": 78, - "z": -101 - }, - { - "x": -95, - "y": 76, - "z": -82 - }, - { - "x": -94, - "y": 70, - "z": -84 - }, - { - "x": -38, - "y": 44, - "z": 130 - }, - { - "x": -88, - "y": 79, - "z": -102 - }, - { - "x": -76, - "y": 90, - "z": -149 - }, - { - "x": -106, - "y": 249, - "z": -149 - }, - { - "x": -74, - "y": 65, - "z": -119 - }, - { - "x": -77, - "y": 72, - "z": -176 - }, - { - "x": -21, - "y": 72, - "z": -18 - }, - { - "x": -88, - "y": 20, - "z": 0 - }, - { - "x": 27, - "y": 71, - "z": -77 - }, - { - "x": 42, - "y": 88, - "z": -91 - }, - { - "x": 47, - "y": 68, - "z": -59 - }, - { - "x": -34, - "y": 66, - "z": -25 - }, - { - "x": -23, - "y": 84, - "z": -92 - }, - { - "x": 40, - "y": 70, - "z": 27 - }, - { - "x": 38, - "y": 63, - "z": -198 - }, - { - "x": 3, - "y": 68, - "z": -204 - }, - { - "x": -161, - "y": 98, - "z": -72 - }, - { - "x": 255, - "y": 74, - "z": 160 - }, - { - "x": 262, - "y": 118, - "z": 94 - }, - { - "x": 182, - "y": 92, - "z": 124 - }, - { - "x": 266, - "y": 60, - "z": 145 - }, - { - "x": 232, - "y": 94, - "z": 168 - }, - { - "x": 256, - "y": 130, - "z": 75 - }, - { - "x": 7, - "y": 113, - "z": 73 - }, - { - "x": 35, - "y": 98, - "z": 166 - }, - { - "x": 22, - "y": 208, - "z": -5 - }, - { - "x": 21, - "y": 108, - "z": 55 - }, - { - "x": 39, - "y": 133, - "z": 16 - }, - { - "x": 8, - "y": 157, - "z": 59 - }, - { - "x": -20.5, - "y": 135, - "z": 38.5 - }, - { - "x": 26, - "y": 166, - "z": 7 - }, - { - "x": -203, - "y": 24, - "z": -57 - }, - { - "x": 38, - "y": 89, - "z": 20 - } - ] + "credit": "Official Hypixel Wiki - https://wiki.hypixel.net", + "zones": { + "wyld_woods": [ + { + "name": "Tough Bark", + "x": -15, + "y": 91, + "z": 94 + }, + { + "name": "Woods Flower Pot", + "x": -6, + "y": 60, + "z": 226 + }, + { + "name": "Up in the Sky", + "x": -137, + "y": 133, + "z": 156 + }, + { + "name": "Next to Enigma", + "x": -27, + "y": 71, + "z": 90 + }, + { + "name": "Fleespook", + "x": -27, + "y": 89, + "z": 136 + }, + { + "name": "Pressurized", + "x": -137, + "y": 51, + "z": 120 + }, + { + "name": "Between Branches", + "x": -108, + "y": 117, + "z": 123 + }, + { + "name": "Two Plates", + "x": -129, + "y": 72, + "z": 77 + }, + { + "name": "Wither Cage", + "x": -142, + "y": 68, + "z": 174 + } + ], + "black_lagoon": [ + { + "name": "Lagoon Cave", + "x": 43, + "y": 91, + "z": 56 + }, + { + "name": "Roy", + "x": -204, + "y": 75, + "z": 49 + }, + { + "name": "Mushroom Guy", + "x": -168, + "y": 81, + "z": 12 + }, + { + "name": "Spinning Runes", + "x": -93, + "y": 73, + "z": 36 + }, + { + "name": "Tel Kar", + "x": -115, + "y": 69, + "z": 61 + } + ], + "west_village": [ + { + "name": "Cake House #1", + "x": -95, + "y": 76, + "z": -82 + }, + { + "name": "Cake House #2", + "x": -94, + "y": 70, + "z": -84 + }, + { + "name": "Dolphin Parkour", + "x": -38, + "y": 44, + "z": 130 + }, + { + "name": "Hot Dog Contest", + "x": -102, + "y": 72, + "z": -103 + }, + { + "name": "Fake Neuroscience", + "x": -34, + "y": 71, + "z": -88 + }, + { + "name": "Between Roofs", + "x": -88, + "y": 79, + "z": -102 + }, + { + "name": "2 Players Soul", + "x": -106, + "y": 78, + "z": -101 + } + ], + "dreadfarm": [ + { + "name": "Beanstalk", + "x": -106, + "y": 249, + "z": -149 + }, + { + "name": "Buttons", + "x": -74, + "y": 65, + "z": -119 + }, + { + "name": "Farm Balloons", + "x": -77, + "y": 72, + "z": -176 + }, + { + "name": "Farm Flower Pot", + "x": -76, + "y": 90, + "z": -149 + } + ], + "village_plaza": [ + { + "name": "Back to Basics", + "x": -88, + "y": 20, + "z": 0 + }, + { + "name": "Horsing Around", + "x": 40, + "y": 70, + "z": 27 + }, + { + "name": "Lonely Ävaeìkx", + "x": -34, + "y": 66, + "z": -25 + }, + { + "name": "Plaza Balloons", + "x": 47, + "y": 68, + "z": -59 + }, + { + "name": "Rabbit in the Hat", + "x": -21, + "y": 72, + "z": -18 + }, + { + "name": "Buy BZT Today", + "x": 27, + "y": 71, + "z": -77 + }, + { + "name": "Between Cooler Roofs", + "x": -23, + "y": 84, + "z": -92 + }, + { + "name": "Plaza Fleespook", + "x": 42, + "y": 88, + "z": -91 + } + ], + "living_cave": [ + { + "name": "Flowery Message", + "x": 3, + "y": 68, + "z": -204 + }, + { + "name": "Behind a Living Wall", + "x": 38, + "y": 63, + "z": -198 + } + ], + "colosseum": [ + { + "name": "Full Circle", + "x": -161, + "y": 98, + "z": -72 + } + ], + "stillgore_chateau": [ + { + "name": "Castle Balloons", + "x": 232, + "y": 94, + "z": 168 + }, + { + "name": "Castle Flower Pot", + "x": 266, + "y": 60, + "z": 145 + }, + { + "name": "Castle Fleespook", + "x": 182, + "y": 92, + "z": 124 + }, + { + "name": "Standing there", + "x": 255, + "y": 74, + "z": 160 + }, + { + "name": "Fairylosopher", + "x": 256, + "y": 130, + "z": 75 + }, + { + "name": "Between Towers", + "x": 262, + "y": 118, + "z": 94 + } + ], + "mountaintop": [ + { + "name": "Mountain Balloons", + "x": 7, + "y": 113, + "z": 73 + }, + { + "name": "Rose's End Flower Pot", + "x": 35, + "y": 98, + "z": 166 + }, + { + "name": "Ikrus", + "x": 8, + "y": 157, + "z": 59 + }, + { + "name": "Leap of Faith", + "x": 26, + "y": 166, + "z": 7 + }, + { + "name": "Fleespook", + "x": 22, + "y": 208, + "z": -5 + }, + { + "name": "Sun Gecko", + "x": 38, + "y": 89, + "z": 20 + }, + { + "name": "Ubik's Averages", + "x": 39, + "y": 133, + "z": 16 + }, + { + "name": "Ubik's Boxes", + "x": 21, + "y": 108, + "z": 55 + }, + { + "name": "Ubik's Tit for Tats", + "x": -20, + "y": 135, + "z": 38 + }, + { + "name": "Walk of Fame", + "x": -203, + "y": 24, + "z": -57 + } + ] + } } diff --git a/src/test/java/de/hysky/skyblocker/VerifyJsonTest.java b/src/test/java/de/hysky/skyblocker/VerifyJsonTest.java index 414730634c2..dedf4a42001 100644 --- a/src/test/java/de/hysky/skyblocker/VerifyJsonTest.java +++ b/src/test/java/de/hysky/skyblocker/VerifyJsonTest.java @@ -99,7 +99,13 @@ void verifyEnigmaSoulWaypoints() { @SuppressWarnings("DataFlowIssue") JsonObject waypoints = GSON.fromJson(new InputStreamReader(this.getClass().getResourceAsStream("/assets/skyblocker/rift/enigma_soul_waypoints.json")), JsonObject.class); - verifyBlockPosObjectArray(waypoints.get("waypoints")); + Assertions.assertTrue(waypoints.get("zones").isJsonObject()); + JsonObject zones = waypoints.get("zones").getAsJsonObject(); + Assertions.assertFalse(zones.isEmpty()); + + zones.asMap().values().forEach(zoneElement -> { + verifyBlockPosObjectArray(zoneElement); + }); } @Test From 964d536c2979268eecac8e14ebcb798671086032 Mon Sep 17 00:00:00 2001 From: qb42 <42453758+qb42@users.noreply.github.com> Date: Sun, 12 Jul 2026 23:14:59 -0400 Subject: [PATCH 2/5] Remove redundant/erroneous checks 1. EnigmaSouls.shouldRender already checks highlightFoundEnigmaSouls. 2. filtering by shouldRender makes running with asFound=true fail silently unless highlightFoundEnigmaSouls is set. --- .../java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java b/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java index 4b9b6d22752..a8f3640e481 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java @@ -145,7 +145,7 @@ static void extractRendering(PrimitiveCollector collector) { if (Utils.isInTheRift() && config.enigmaSoulWaypoints && soulsLoaded.isDone()) { streamWaypoints().forEach(soul -> { - if (soul.shouldRender() || config.highlightFoundEnigmaSouls) { + if (soul.shouldRender()) { soul.extractRendering(collector); } }); @@ -199,7 +199,6 @@ private static void markClosestSoul(boolean asFound) { if (!soulsLoaded.isDone() || player == null) return; streamWaypoints() - .filter(Waypoint::shouldRender) .min(Comparator.comparingDouble(soul -> soul.pos.distToCenterSqr(player.position()))) .filter(soul -> soul.pos.distToCenterSqr(player.position()) <= 16) .ifPresent(asFound ? Waypoint::setFound : Waypoint::setMissing); From 78c3b1b52f9aac4b7f1f07ae1ad0bfff7f14bb0b Mon Sep 17 00:00:00 2001 From: qb42 <42453758+qb42@users.noreply.github.com> Date: Sun, 12 Jul 2026 19:42:06 -0400 Subject: [PATCH 3/5] Add markZoneFound,markZoneMissing to enigmaSouls command --- .../skyblocker/skyblock/rift/EnigmaSouls.java | 34 ++++++++++++++++++- .../assets/skyblocker/lang/en_us.json | 2 ++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java b/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java index a8f3640e481..489a78b0442 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java @@ -6,6 +6,7 @@ import com.google.gson.JsonParser; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; +import com.mojang.serialization.Codec; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.config.configs.OtherLocationsConfig; @@ -20,6 +21,7 @@ import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; +import net.minecraft.commands.arguments.StringRepresentableArgument; import net.minecraft.commands.CommandBuildContext; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; @@ -47,6 +49,7 @@ import java.util.function.Supplier; import java.util.stream.Stream; +import static net.fabricmc.fabric.api.client.command.v2.ClientCommands.argument; import static net.fabricmc.fabric.api.client.command.v2.ClientCommands.literal; public class EnigmaSouls { @@ -190,7 +193,24 @@ static void registerCommands(CommandDispatcher dispat context.getSource().sendFeedback(Constants.PREFIX.get().append(Component.translatable("skyblocker.rift.enigmaSouls.markClosestMissing"))); return Command.SINGLE_SUCCESS; - }))))); + })) + .then(literal("markZoneFound").then(argument("zone", RiftZone.RiftZoneArgumentType.riftZone()).executes(context -> { + RiftZone zone = context.getArgument("zone", RiftZone.class); + SOUL_WAYPOINTS.get(zone).values().forEach(Waypoint::setFound); + context.getSource().sendFeedback(Constants.PREFIX.get().append( + Component.translatableEscape("skyblocker.rift.enigmaSouls.markZoneFound", zone.displayName()))); + + return Command.SINGLE_SUCCESS; + }))) + .then(literal("markZoneMissing").then(argument("zone", RiftZone.RiftZoneArgumentType.riftZone()).executes(context -> { + RiftZone zone = context.getArgument("zone", RiftZone.class); + SOUL_WAYPOINTS.get(zone).values().forEach(Waypoint::setMissing); + context.getSource().sendFeedback(Constants.PREFIX.get().append( + Component.translatableEscape("skyblocker.rift.enigmaSouls.markZoneMissing", zone.displayName()))); + + return Command.SINGLE_SUCCESS; + }))) + ))); } private static void markClosestSoul(boolean asFound) { @@ -252,6 +272,8 @@ private enum RiftZone implements StringRepresentable { STILLGORE_CHATEAU, MOUNTAINTOP; + private static final Codec CODEC = StringRepresentable.fromEnum(RiftZone::values); + @Override public String getSerializedName() { return name().toLowerCase(Locale.ENGLISH); @@ -264,5 +286,15 @@ public String displayName() { public static RiftZone fromSerializedName(String name) { return valueOf(name.toUpperCase(Locale.ENGLISH)); } + + public static class RiftZoneArgumentType extends StringRepresentableArgument { + private RiftZoneArgumentType() { + super(CODEC, RiftZone::values); + } + + public static RiftZoneArgumentType riftZone() { + return new RiftZoneArgumentType(); + } + } } } diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 00f8517e311..5b0af7cc16b 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -1871,6 +1871,8 @@ "skyblocker.rift.enigmaSouls.markAllMissing": "Marked all enigma souls as missing!", "skyblocker.rift.enigmaSouls.markClosestFound": "Marked closest enigma soul as found!", "skyblocker.rift.enigmaSouls.markClosestMissing": "Marked closest enigma soul as missing!", + "skyblocker.rift.enigmaSouls.markZoneFound": "Marked all enigma souls in %s as found!", + "skyblocker.rift.enigmaSouls.markZoneMissing": "Marked all enigma souls in %s as missing!", "skyblocker.rift.healNow": "Heal now!", "skyblocker.rift.iceNow": "Ice now!", "skyblocker.rift.mania": "Mania!", From 95cf12d9a0081966890fd650345cf6646fb2faa4 Mon Sep 17 00:00:00 2001 From: qb42 <42453758+qb42@users.noreply.github.com> Date: Sun, 12 Jul 2026 19:44:43 -0400 Subject: [PATCH 4/5] Add sanity-checks to enigmaSouls command --- .../skyblocker/skyblock/rift/EnigmaSouls.java | 24 ++++++++++++++++++- .../utils/command/CommandUtils.java | 13 ++++++++++ .../assets/skyblocker/lang/en_us.json | 3 +++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java b/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java index 489a78b0442..d8c2743ae93 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java @@ -5,6 +5,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.mojang.brigadier.Command; +import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.CommandDispatcher; import com.mojang.serialization.Codec; import de.hysky.skyblocker.SkyblockerMod; @@ -49,6 +50,7 @@ import java.util.function.Supplier; import java.util.stream.Stream; +import static de.hysky.skyblocker.utils.command.CommandUtils.failOnMissingProfile; import static net.fabricmc.fabric.api.client.command.v2.ClientCommands.argument; import static net.fabricmc.fabric.api.client.command.v2.ClientCommands.literal; @@ -171,30 +173,40 @@ static void registerCommands(CommandDispatcher dispat .then(literal("rift") .then(literal("enigmaSouls") .then(literal("markAllFound").executes(context -> { + if (failOnMissingProfile(context)) return 0; + streamWaypoints().forEach(Waypoint::setFound); context.getSource().sendFeedback(Constants.PREFIX.get().append(Component.translatable("skyblocker.rift.enigmaSouls.markAllFound"))); return Command.SINGLE_SUCCESS; })) .then(literal("markAllMissing").executes(context -> { + if (failOnMissingProfile(context)) return 0; + streamWaypoints().forEach(Waypoint::setMissing); context.getSource().sendFeedback(Constants.PREFIX.get().append(Component.translatable("skyblocker.rift.enigmaSouls.markAllMissing"))); return Command.SINGLE_SUCCESS; })) .then(literal("markClosestFound").executes(context -> { + if (failIfNotInRift(context)) return 0; + markClosestSoul(true); context.getSource().sendFeedback(Constants.PREFIX.get().append(Component.translatable("skyblocker.rift.enigmaSouls.markClosestFound"))); return Command.SINGLE_SUCCESS; })) .then(literal("markClosestMissing").executes(context -> { + if (failIfNotInRift(context)) return 0; + markClosestSoul(false); context.getSource().sendFeedback(Constants.PREFIX.get().append(Component.translatable("skyblocker.rift.enigmaSouls.markClosestMissing"))); return Command.SINGLE_SUCCESS; })) .then(literal("markZoneFound").then(argument("zone", RiftZone.RiftZoneArgumentType.riftZone()).executes(context -> { + if (failOnMissingProfile(context)) return 0; + RiftZone zone = context.getArgument("zone", RiftZone.class); SOUL_WAYPOINTS.get(zone).values().forEach(Waypoint::setFound); context.getSource().sendFeedback(Constants.PREFIX.get().append( @@ -203,6 +215,8 @@ static void registerCommands(CommandDispatcher dispat return Command.SINGLE_SUCCESS; }))) .then(literal("markZoneMissing").then(argument("zone", RiftZone.RiftZoneArgumentType.riftZone()).executes(context -> { + if (failOnMissingProfile(context)) return 0; + RiftZone zone = context.getArgument("zone", RiftZone.class); SOUL_WAYPOINTS.get(zone).values().forEach(Waypoint::setMissing); context.getSource().sendFeedback(Constants.PREFIX.get().append( @@ -216,7 +230,7 @@ static void registerCommands(CommandDispatcher dispat private static void markClosestSoul(boolean asFound) { LocalPlayer player = Minecraft.getInstance().player; - if (!soulsLoaded.isDone() || player == null) return; + if (!soulsLoaded.isDone() || player == null || !Utils.isInTheRift()) return; streamWaypoints() .min(Comparator.comparingDouble(soul -> soul.pos.distToCenterSqr(player.position()))) @@ -224,6 +238,14 @@ private static void markClosestSoul(boolean asFound) { .ifPresent(asFound ? Waypoint::setFound : Waypoint::setMissing); } + public static boolean failIfNotInRift(CommandContext context) { + if (!Utils.isInTheRift()) { + context.getSource().sendFeedback(Constants.PREFIX.get().append(Component.translatable("skyblocker.rift.notInRift").withStyle(ChatFormatting.RED))); + return true; + } + return false; + } + private static Stream streamWaypoints() { return SOUL_WAYPOINTS.values().stream().flatMap(zone -> zone.values().stream()); } diff --git a/src/main/java/de/hysky/skyblocker/utils/command/CommandUtils.java b/src/main/java/de/hysky/skyblocker/utils/command/CommandUtils.java index d0c8f502b4d..13c0c512831 100644 --- a/src/main/java/de/hysky/skyblocker/utils/command/CommandUtils.java +++ b/src/main/java/de/hysky/skyblocker/utils/command/CommandUtils.java @@ -1,8 +1,21 @@ package de.hysky.skyblocker.utils.command; import com.mojang.brigadier.Command; +import com.mojang.brigadier.context.CommandContext; +import de.hysky.skyblocker.utils.Constants; +import de.hysky.skyblocker.utils.Utils; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; public final class CommandUtils { public static final Command noOp = _ -> -1; + + public static boolean failOnMissingProfile(CommandContext context) { + if (Utils.getProfile() == null || Utils.getProfile().isEmpty()) { + context.getSource().sendFeedback(Constants.PREFIX.get().append(Component.translatable("skyblocker.command.profileMissing").withStyle(ChatFormatting.RED))); + return true; + } + return false; + } } diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 5b0af7cc16b..3caa95d6c81 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -74,6 +74,8 @@ "skyblocker.chat.confirmationPromptNotification": "Click anywhere on screen within 60 seconds to accept the prompt.", + "skyblocker.command.profileMissing": "Failed to detect current profile, please check you are in Skyblock.", + "skyblocker.config.chat": "Chat", "skyblocker.config.chat.chatRules": "Custom Chat Rules", @@ -1876,6 +1878,7 @@ "skyblocker.rift.healNow": "Heal now!", "skyblocker.rift.iceNow": "Ice now!", "skyblocker.rift.mania": "Mania!", + "skyblocker.rift.notInRift": "This command only works in the rift!", "skyblocker.rift.stakeNow": "Stake now!", "skyblocker.shortcuts.command.replacement": "Replacement Command", From 70e80233c72fb2679afcb4b55f09eb31b6530fbf Mon Sep 17 00:00:00 2001 From: qb42 <42453758+qb42@users.noreply.github.com> Date: Mon, 13 Jul 2026 00:01:24 -0400 Subject: [PATCH 5/5] Handle rift profile names --- .../skyblocker/skyblock/rift/EnigmaSouls.java | 22 ++++++++++++------- .../utils/waypoint/ProfileAwareWaypoint.java | 8 +++++-- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java b/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java index d8c2743ae93..67fc50c20b3 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/rift/EnigmaSouls.java @@ -250,6 +250,15 @@ private static Stream streamWaypoints() { return SOUL_WAYPOINTS.values().stream().flatMap(zone -> zone.values().stream()); } + private static String canonicalProfileName(String profile) { + if (Character.isUpperCase(profile.charAt(0))) { + // profile is a normal profile name, reverse it into a rift profile name + return new StringBuilder(profile).reverse().toString(); + } else { + return profile; + } + } + private static class EnigmaSoul extends ProfileAwareWaypoint { public final RiftZone zone; public final String name; @@ -265,21 +274,18 @@ public boolean shouldRender() { return super.shouldRender() || SkyblockerConfigManager.get().otherLocations.rift.highlightFoundEnigmaSouls; } - @Override - public void setFound() { - setFound(Utils.getProfile()); - } - @Override public void setFound(String profile) { + profile = canonicalProfileName(profile); LOGGER.debug("[Skyblocker] Set enigma soul found for {}: {}/{}", profile, zone.displayName(), name); super.setFound(profile); } @Override - public void setMissing() { - LOGGER.debug("[Skyblocker] Set enigma soul missing: {}/{}", zone.displayName(), name); - super.setMissing(); + public void setMissing(String profile) { + profile = canonicalProfileName(profile); + LOGGER.debug("[Skyblocker] Set enigma soul missing for {}: {}/{}", profile, zone.displayName(), name); + super.setMissing(profile); } } 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 bcc2be08af1..12e9ece4869 100644 --- a/src/main/java/de/hysky/skyblocker/utils/waypoint/ProfileAwareWaypoint.java +++ b/src/main/java/de/hysky/skyblocker/utils/waypoint/ProfileAwareWaypoint.java @@ -24,7 +24,7 @@ public boolean shouldRender() { @Override public void setFound() { - foundProfiles.add(Utils.getProfile()); + setFound(Utils.getProfile()); } public void setFound(String profile) { @@ -33,7 +33,11 @@ public void setFound(String profile) { @Override public void setMissing() { - foundProfiles.remove(Utils.getProfile()); + setMissing(Utils.getProfile()); + } + + public void setMissing(String profile) { + foundProfiles.remove(profile); } @Override