diff --git a/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java b/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java index b630e5f5c1..b28ad3d4ad 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java +++ b/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java @@ -13,6 +13,7 @@ import me.xmrvizzy.skyblocker.skyblock.rift.TheRift; import me.xmrvizzy.skyblocker.skyblock.shortcut.Shortcuts; import me.xmrvizzy.skyblocker.skyblock.special.SpecialEffects; +import me.xmrvizzy.skyblocker.skyblock.spidersden.Relics; import me.xmrvizzy.skyblocker.skyblock.tabhud.TabHud; import me.xmrvizzy.skyblocker.skyblock.tabhud.screenbuilder.ScreenMaster; import me.xmrvizzy.skyblocker.skyblock.tabhud.util.PlayerListMgr; @@ -74,6 +75,7 @@ public void onInitializeClient() { ItemRegistry.init(); NEURepo.init(); FairySouls.init(); + Relics.init(); BackpackPreview.init(); QuickNav.init(); DwarvenHud.init(); diff --git a/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java b/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java index 58fc690c25..476af0a80b 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java +++ b/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java @@ -278,7 +278,6 @@ public static class BarPositions { public BarPosition defenceBarPosition = BarPosition.LAYER1; @ConfigEntry.Gui.EnumHandler(option = ConfigEntry.Gui.EnumHandler.EnumDisplayOption.BUTTON) public BarPosition experienceBarPosition = BarPosition.LAYER1; - } public enum BarPosition { @@ -315,6 +314,7 @@ public static class Fishing { public static class FairySouls { public boolean enableFairySoulsHelper = false; public boolean highlightFoundSouls = true; + @ConfigEntry.Gui.Tooltip() public boolean highlightOnlyNearbySouls = false; } @@ -449,6 +449,10 @@ public static class Locations { @ConfigEntry.Category("rift") @ConfigEntry.Gui.CollapsibleObject() public Rift rift = new Rift(); + + @ConfigEntry.Category("spidersden") + @ConfigEntry.Gui.CollapsibleObject() + public SpidersDen spidersDen = new SpidersDen(); } public static class Dungeons { @@ -561,6 +565,17 @@ public static class Rift { public int mcGrubberStacks = 0; } + public static class SpidersDen { + @ConfigEntry.Category("relics") + @ConfigEntry.Gui.CollapsibleObject() + public Relics relics = new Relics(); + } + + public static class Relics { + public boolean enableRelicsHelper = false; + public boolean highlightFoundRelics = true; + } + public static class Slayer { @ConfigEntry.Category("vampire") @ConfigEntry.Gui.CollapsibleObject() diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/FairySouls.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/FairySouls.java index e6b7515299..fcd6be7aa6 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/FairySouls.java +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/FairySouls.java @@ -5,17 +5,21 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import com.mojang.brigadier.CommandDispatcher; import me.xmrvizzy.skyblocker.SkyblockerMod; import me.xmrvizzy.skyblocker.config.SkyblockerConfig; import me.xmrvizzy.skyblocker.utils.NEURepo; +import me.xmrvizzy.skyblocker.utils.PosUtils; import me.xmrvizzy.skyblocker.utils.Utils; import me.xmrvizzy.skyblocker.utils.render.RenderHelper; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.minecraft.client.MinecraftClient; +import net.minecraft.command.CommandRegistryAccess; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.text.Text; import net.minecraft.util.DyeColor; @@ -37,6 +41,7 @@ public class FairySouls { private static final Map> fairySouls = new HashMap<>(); private static final Map>> foundFairies = new HashMap<>(); + @SuppressWarnings("UnusedReturnValue") public static CompletableFuture runAsyncAfterFairySoulsLoad(Runnable runnable) { if (fairySoulsLoaded == null) { LOGGER.error("Fairy Souls have not being initialized yet! Please ensure the Fairy Souls module is initialized before modules calling this method in SkyblockerMod#onInitializeClient. This error can be safely ignore in a test environment."); @@ -50,9 +55,16 @@ public static int getFairySoulsSize(@Nullable String location) { } public static void init() { + loadFairySouls(); + ClientLifecycleEvents.CLIENT_STOPPING.register(FairySouls::saveFoundFairySouls); + ClientCommandRegistrationCallback.EVENT.register(FairySouls::registerCommands); + WorldRenderEvents.AFTER_TRANSLUCENT.register(FairySouls::render); + ClientReceiveMessageEvents.GAME.register(FairySouls::onChatMessage); + } + + private static void loadFairySouls() { fairySoulsLoaded = NEURepo.runAsyncAfterLoad(() -> { - try { - BufferedReader reader = new BufferedReader(new FileReader(NEURepo.LOCAL_REPO_DIR.resolve("constants").resolve("fairy_souls.json").toFile())); + try (BufferedReader reader = new BufferedReader(new FileReader(NEURepo.LOCAL_REPO_DIR.resolve("constants").resolve("fairy_souls.json").toFile()))) { for (Map.Entry fairySoulJson : JsonParser.parseReader(reader).getAsJsonObject().asMap().entrySet()) { if (fairySoulJson.getKey().equals("//") || fairySoulJson.getKey().equals("Max Souls")) { if (fairySoulJson.getKey().equals("Max Souls")) { @@ -62,62 +74,44 @@ public static void init() { } ImmutableSet.Builder fairySoulsForLocation = ImmutableSet.builder(); for (JsonElement fairySoul : fairySoulJson.getValue().getAsJsonArray().asList()) { - fairySoulsForLocation.add(parseBlockPos(fairySoul)); + fairySoulsForLocation.add(PosUtils.parsePosString(fairySoul.getAsString())); } fairySouls.put(fairySoulJson.getKey(), fairySoulsForLocation.build()); } - reader = new BufferedReader(new FileReader(SkyblockerMod.CONFIG_DIR.resolve("found_fairy_souls.json").toFile())); + LOGGER.debug("[Skyblocker] Loaded fairy soul locations"); + } catch (IOException e) { + LOGGER.error("[Skyblocker] Failed to load fairy soul locations", e); + } + + try (BufferedReader reader = new BufferedReader(new FileReader(SkyblockerMod.CONFIG_DIR.resolve("found_fairy_souls.json").toFile()))) { for (Map.Entry foundFairiesForProfileJson : JsonParser.parseReader(reader).getAsJsonObject().asMap().entrySet()) { Map> foundFairiesForProfile = new HashMap<>(); for (Map.Entry foundFairiesForLocationJson : foundFairiesForProfileJson.getValue().getAsJsonObject().asMap().entrySet()) { Set foundFairiesForLocation = new HashSet<>(); for (JsonElement foundFairy : foundFairiesForLocationJson.getValue().getAsJsonArray().asList()) { - foundFairiesForLocation.add(parseBlockPos(foundFairy)); + foundFairiesForLocation.add(PosUtils.parsePosString(foundFairy.getAsString())); } foundFairiesForProfile.put(foundFairiesForLocationJson.getKey(), foundFairiesForLocation); } foundFairies.put(foundFairiesForProfileJson.getKey(), foundFairiesForProfile); } - reader.close(); + LOGGER.debug("[Skyblocker] Loaded found fairy souls"); + } catch (FileNotFoundException ignored) { } catch (IOException e) { - LOGGER.error("Failed to load found fairy souls", e); - } catch (Exception e) { - LOGGER.error("Encountered unknown exception loading fairy souls", e); + LOGGER.error("[Skyblocker] Failed to load found fairy souls", e); } }); - - ClientLifecycleEvents.CLIENT_STOPPING.register(FairySouls::saveFoundFairySouls); - WorldRenderEvents.AFTER_TRANSLUCENT.register(FairySouls::render); - ClientReceiveMessageEvents.GAME.register(FairySouls::onChatMessage); - ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(literal(SkyblockerMod.NAMESPACE) - .then(literal("fairySouls") - .then(literal("markAllInCurrentIslandFound").executes(context -> { - FairySouls.markAllFairiesFound(); - context.getSource().sendFeedback(Text.translatable("skyblocker.fairySouls.markAllFound")); - return 1; - })) - .then(literal("markAllInCurrentIslandMissing").executes(context -> { - FairySouls.markAllFairiesNotFound(); - context.getSource().sendFeedback(Text.translatable("skyblocker.fairySouls.markAllMissing")); - return 1; - }))))); } - private static BlockPos parseBlockPos(JsonElement posJson) { - String[] posArray = posJson.getAsString().split(","); - return new BlockPos(Integer.parseInt(posArray[0]), Integer.parseInt(posArray[1]), Integer.parseInt(posArray[2])); - } - - public static void saveFoundFairySouls(MinecraftClient client) { - try { - BufferedWriter writer = new BufferedWriter(new FileWriter(SkyblockerMod.CONFIG_DIR.resolve("found_fairy_souls.json").toFile())); + private static void saveFoundFairySouls(MinecraftClient client) { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(SkyblockerMod.CONFIG_DIR.resolve("found_fairy_souls.json").toFile()))) { JsonObject foundFairiesJson = new JsonObject(); for (Map.Entry>> foundFairiesForProfile : foundFairies.entrySet()) { JsonObject foundFairiesForProfileJson = new JsonObject(); for (Map.Entry> foundFairiesForLocation : foundFairiesForProfile.getValue().entrySet()) { JsonArray foundFairiesForLocationJson = new JsonArray(); for (BlockPos foundFairy : foundFairiesForLocation.getValue()) { - foundFairiesForLocationJson.add(foundFairy.getX() + "," + foundFairy.getY() + "," + foundFairy.getZ()); + foundFairiesForLocationJson.add(PosUtils.getPosString(foundFairy)); } foundFairiesForProfileJson.add(foundFairiesForLocation.getKey(), foundFairiesForLocationJson); } @@ -125,17 +119,33 @@ public static void saveFoundFairySouls(MinecraftClient client) { } SkyblockerMod.GSON.toJson(foundFairiesJson, writer); writer.close(); + LOGGER.info("[Skyblocker] Saved found fairy souls"); } catch (IOException e) { - LOGGER.error("Failed to write found fairy souls to file."); + LOGGER.error("[Skyblocker] Failed to write found fairy souls to file", e); } } - public static void render(WorldRenderContext context) { + private static void registerCommands(CommandDispatcher dispatcher, CommandRegistryAccess registryAccess) { + dispatcher.register(literal(SkyblockerMod.NAMESPACE) + .then(literal("fairySouls") + .then(literal("markAllInCurrentIslandFound").executes(context -> { + FairySouls.markAllFairiesOnCurrentIslandFound(); + context.getSource().sendFeedback(Text.translatable("skyblocker.fairySouls.markAllFound")); + return 1; + })) + .then(literal("markAllInCurrentIslandMissing").executes(context -> { + FairySouls.markAllFairiesOnCurrentIslandMissing(); + context.getSource().sendFeedback(Text.translatable("skyblocker.fairySouls.markAllMissing")); + return 1; + })))); + } + + private static void render(WorldRenderContext context) { SkyblockerConfig.FairySouls fairySoulsConfig = SkyblockerConfig.get().general.fairySouls; if (fairySoulsConfig.enableFairySoulsHelper && fairySoulsLoaded.isDone() && fairySouls.containsKey(Utils.getLocationRaw())) { for (BlockPos fairySoulPos : fairySouls.get(Utils.getLocationRaw())) { - boolean fairySoulNotFound = isFairySoulNotFound(fairySoulPos); + boolean fairySoulNotFound = isFairySoulMissing(fairySoulPos); if (!fairySoulsConfig.highlightFoundSouls && !fairySoulNotFound || fairySoulsConfig.highlightOnlyNearbySouls && fairySoulPos.getSquaredDistance(context.camera().getPos()) > 2500) { continue; } @@ -145,19 +155,7 @@ public static void render(WorldRenderContext context) { } } - private static boolean isFairySoulNotFound(BlockPos fairySoulPos) { - Map> foundFairiesForProfile = foundFairies.get(Utils.getProfile()); - if (foundFairiesForProfile == null) { - return true; - } - Set foundFairiesForProfileAndLocation = foundFairiesForProfile.get(Utils.getLocationRaw()); - if (foundFairiesForProfileAndLocation == null) { - return true; - } - return !foundFairiesForProfileAndLocation.contains(fairySoulPos); - } - - public static void onChatMessage(Text text, boolean overlay) { + private static void onChatMessage(Text text, boolean overlay) { String message = text.getString(); if (message.equals("You have already found that Fairy Soul!") || message.equals("§d§lSOUL! §fYou found a §dFairy Soul§f!")) { markClosestFairyFound(); @@ -165,13 +163,14 @@ public static void onChatMessage(Text text, boolean overlay) { } private static void markClosestFairyFound() { + if (!fairySoulsLoaded.isDone()) return; PlayerEntity player = MinecraftClient.getInstance().player; if (player == null) { - LOGGER.warn("Failed to mark closest fairy soul as found because player is null."); + LOGGER.warn("[Skyblocker] Failed to mark closest fairy soul as found because player is null"); return; } fairySouls.get(Utils.getLocationRaw()).stream() - .filter(FairySouls::isFairySoulNotFound) + .filter(FairySouls::isFairySoulMissing) .min(Comparator.comparingDouble(fairySoulPos -> fairySoulPos.getSquaredDistance(player.getPos()))) .filter(fairySoulPos -> fairySoulPos.getSquaredDistance(player.getPos()) <= 16) .ifPresent(fairySoulPos -> { @@ -180,12 +179,24 @@ private static void markClosestFairyFound() { }); } - public static void markAllFairiesFound() { + private static boolean isFairySoulMissing(BlockPos fairySoulPos) { + Map> foundFairiesForProfile = foundFairies.get(Utils.getProfile()); + if (foundFairiesForProfile == null) { + return true; + } + Set foundFairiesForProfileAndLocation = foundFairiesForProfile.get(Utils.getLocationRaw()); + if (foundFairiesForProfileAndLocation == null) { + return true; + } + return !foundFairiesForProfileAndLocation.contains(fairySoulPos); + } + + public static void markAllFairiesOnCurrentIslandFound() { initializeFoundFairiesForCurrentProfileAndLocation(); foundFairies.get(Utils.getProfile()).get(Utils.getLocationRaw()).addAll(fairySouls.get(Utils.getLocationRaw())); } - public static void markAllFairiesNotFound() { + public static void markAllFairiesOnCurrentIslandMissing() { Map> foundFairiesForProfile = foundFairies.get(Utils.getProfile()); if (foundFairiesForProfile != null) { foundFairiesForProfile.remove(Utils.getLocationRaw()); diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/shortcut/Shortcuts.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/shortcut/Shortcuts.java index 89329c6c08..14bc1db4c5 100644 --- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/shortcut/Shortcuts.java +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/shortcut/Shortcuts.java @@ -63,7 +63,7 @@ protected static void loadShortcuts() { LOGGER.info("[Skyblocker] Loaded {} command shortcuts and {} command argument shortcuts", commands.size(), commandArgs.size()); } catch (FileNotFoundException e) { registerDefaultShortcuts(); - LOGGER.warn("[Skyblocker] Shortcuts file not found, using default shortcuts. This is normal when using for the first time.", e); + LOGGER.warn("[Skyblocker] Shortcuts file not found, using default shortcuts. This is normal when using for the first time."); } catch (IOException e) { LOGGER.error("[Skyblocker] Failed to load shortcuts file", e); } diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/spidersden/Relics.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/spidersden/Relics.java new file mode 100644 index 0000000000..12ce07150d --- /dev/null +++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/spidersden/Relics.java @@ -0,0 +1,170 @@ +package me.xmrvizzy.skyblocker.skyblock.spidersden; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.mojang.brigadier.CommandDispatcher; +import me.xmrvizzy.skyblocker.SkyblockerMod; +import me.xmrvizzy.skyblocker.config.SkyblockerConfig; +import me.xmrvizzy.skyblocker.utils.PosUtils; +import me.xmrvizzy.skyblocker.utils.Utils; +import me.xmrvizzy.skyblocker.utils.render.RenderHelper; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; +import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; +import net.minecraft.client.MinecraftClient; +import net.minecraft.command.CommandRegistryAccess; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.DyeColor; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.*; +import java.util.*; +import java.util.concurrent.CompletableFuture; + +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; + +public class Relics { + private static final Logger LOGGER = LoggerFactory.getLogger(Relics.class); + private static CompletableFuture relicsLoaded; + @SuppressWarnings({"unused", "FieldCanBeLocal"}) + private static int totalRelics = 0; + private static final List relics = new ArrayList<>(); + private static final Map> foundRelics = new HashMap<>(); + + public static void init() { + ClientLifecycleEvents.CLIENT_STARTED.register(Relics::loadRelics); + ClientLifecycleEvents.CLIENT_STOPPING.register(Relics::saveFoundRelics); + ClientCommandRegistrationCallback.EVENT.register(Relics::registerCommands); + WorldRenderEvents.AFTER_TRANSLUCENT.register(Relics::render); + ClientReceiveMessageEvents.GAME.register(Relics::onChatMessage); + } + + private static void loadRelics(MinecraftClient client) { + relicsLoaded = CompletableFuture.runAsync(() -> { + try (BufferedReader reader = client.getResourceManager().openAsReader(new Identifier(SkyblockerMod.NAMESPACE, "spidersden/relics.json"))) { + for (Map.Entry json : JsonParser.parseReader(reader).getAsJsonObject().asMap().entrySet()) { + if (json.getKey().equals("total")) { + totalRelics = json.getValue().getAsInt(); + } else if (json.getKey().equals("locations")) { + for (JsonElement locationJson : json.getValue().getAsJsonArray().asList()) { + JsonObject posData = locationJson.getAsJsonObject(); + relics.add(new BlockPos(posData.get("x").getAsInt(), posData.get("y").getAsInt(), posData.get("z").getAsInt())); + } + } + } + LOGGER.info("[Skyblocker] Loaded relics locations"); + } catch (IOException e) { + LOGGER.error("[Skyblocker] Failed to load relics locations", e); + } + + try (BufferedReader reader = new BufferedReader(new FileReader(SkyblockerMod.CONFIG_DIR.resolve("found_relics.json").toFile()))) { + for (Map.Entry profileJson : JsonParser.parseReader(reader).getAsJsonObject().asMap().entrySet()) { + Set foundRelicsForProfile = new HashSet<>(); + for (JsonElement foundRelicsJson : profileJson.getValue().getAsJsonArray().asList()) { + foundRelicsForProfile.add(PosUtils.parsePosString(foundRelicsJson.getAsString())); + } + foundRelics.put(profileJson.getKey(), foundRelicsForProfile); + } + LOGGER.debug("[Skyblocker] Loaded found relics"); + } catch (FileNotFoundException ignored) { + } catch (IOException e) { + LOGGER.error("[Skyblocker] Failed to load found relics", e); + } + }); + } + + private static void saveFoundRelics(MinecraftClient client) { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(SkyblockerMod.CONFIG_DIR.resolve("found_relics.json").toFile()))) { + JsonObject json = new JsonObject(); + for (Map.Entry> foundRelicsForProfile : foundRelics.entrySet()) { + JsonArray foundRelicsJson = new JsonArray(); + for (BlockPos foundRelic : foundRelicsForProfile.getValue()) { + foundRelicsJson.add(PosUtils.getPosString(foundRelic)); + } + json.add(foundRelicsForProfile.getKey(), foundRelicsJson); + } + SkyblockerMod.GSON.toJson(json, writer); + LOGGER.debug("[Skyblocker] Saved found relics"); + } catch (IOException e) { + LOGGER.error("[Skyblocker] Failed to write found relics to file", e); + } + } + + private static void registerCommands(CommandDispatcher dispatcher, CommandRegistryAccess registryAccess) { + dispatcher.register(literal(SkyblockerMod.NAMESPACE) + .then(literal("relics") + .then(literal("markAllFound").executes(context -> { + Relics.markAllFound(); + context.getSource().sendFeedback(Text.translatable("skyblocker.relics.markAllFound")); + return 1; + })) + .then(literal("markAllMissing").executes(context -> { + Relics.markAllMissing(); + context.getSource().sendFeedback(Text.translatable("skyblocker.relics.markAllMissing")); + return 1; + })))); + } + + private static void render(WorldRenderContext context) { + SkyblockerConfig.Relics config = SkyblockerConfig.get().locations.spidersDen.relics; + + if (config.enableRelicsHelper && relicsLoaded.isDone() && Utils.getLocationRaw().equals("combat_1")) { + for (BlockPos fairySoulPos : relics) { + boolean isRelicMissing = isRelicMissing(fairySoulPos); + if (!isRelicMissing && !config.highlightFoundRelics) continue; + float[] colorComponents = isRelicMissing ? DyeColor.YELLOW.getColorComponents() : DyeColor.BROWN.getColorComponents(); + RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, fairySoulPos, colorComponents, 0.5F); + } + } + } + + private static void onChatMessage(Text text, boolean overlay) { + String message = text.getString(); + if (message.equals("You've already found this relic!") || message.startsWith("+10,000 Coins! (") && message.endsWith("/28 Relics)")) { + markClosestRelicFound(); + } + } + + private static void markClosestRelicFound() { + if (!relicsLoaded.isDone()) return; + PlayerEntity player = MinecraftClient.getInstance().player; + if (player == null) { + LOGGER.warn("[Skyblocker] Failed to mark closest relic as found because player is null"); + return; + } + relics.stream() + .filter(Relics::isRelicMissing) + .min(Comparator.comparingDouble(relicPos -> relicPos.getSquaredDistance(player.getPos()))) + .filter(relicPos -> relicPos.getSquaredDistance(player.getPos()) <= 16) + .ifPresent(relicPos -> { + foundRelics.computeIfAbsent(Utils.getProfile(), profileKey -> new HashSet<>()); + foundRelics.get(Utils.getProfile()).add(relicPos); + }); + } + + private static boolean isRelicMissing(BlockPos relicPos) { + Set foundRelicsForProfile = foundRelics.get(Utils.getProfile()); + return foundRelicsForProfile == null || !foundRelicsForProfile.contains(relicPos); + } + + private static void markAllFound() { + foundRelics.computeIfAbsent(Utils.getProfile(), profileKey -> new HashSet<>()); + foundRelics.get(Utils.getProfile()).addAll(relics); + } + + private static void markAllMissing() { + Set foundRelicsForProfile = foundRelics.get(Utils.getProfile()); + if (foundRelicsForProfile != null) { + foundRelicsForProfile.clear(); + } + } +} diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/PosUtils.java b/src/main/java/me/xmrvizzy/skyblocker/utils/PosUtils.java new file mode 100644 index 0000000000..4f32292c6b --- /dev/null +++ b/src/main/java/me/xmrvizzy/skyblocker/utils/PosUtils.java @@ -0,0 +1,14 @@ +package me.xmrvizzy.skyblocker.utils; + +import net.minecraft.util.math.BlockPos; + +public final class PosUtils { + public static BlockPos parsePosString(String posData) { + String[] posArray = posData.split(","); + return new BlockPos(Integer.parseInt(posArray[0]), Integer.parseInt(posArray[1]), Integer.parseInt(posArray[2])); + } + + public static String getPosString(BlockPos blockPos) { + return blockPos.getX() + "," + blockPos.getY() + "," + blockPos.getZ(); + } +} diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index cdaa760249..273cbb31d5 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -209,6 +209,10 @@ "text.autoconfig.skyblocker.option.locations.barn": "Barn", "text.autoconfig.skyblocker.option.locations.barn.solveHungryHiker": "Solve Hungry Hiker", "text.autoconfig.skyblocker.option.locations.barn.solveTreasureHunter": "Solve Treasure Hunter", + "text.autoconfig.skyblocker.option.locations.spidersDen": "Spider's Den", + "text.autoconfig.skyblocker.option.locations.spidersDen.relics": "Hidden Relics Helper", + "text.autoconfig.skyblocker.option.locations.spidersDen.relics.enableRelicsHelper": "Enable Hidden Relics Helper", + "text.autoconfig.skyblocker.option.locations.spidersDen.relics.highlightFoundRelics": "Highlight found relics", "text.autoconfig.skyblocker.option.locations.dungeons": "Dungeons", "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints": "Dungeon Secret Waypoints", "text.autoconfig.skyblocker.option.locations.dungeons.secretWaypoints.enableSecretWaypoints": "Enable Dungeon Secret Waypoints", @@ -326,8 +330,10 @@ "skyblocker.rift.iceNow": "Ice now!", "skyblocker.rift.mania": "Mania!", "skyblocker.rift.stakeNow": "Stake now!", - "skyblocker.fairySouls.markAllFound": "Marked all fairy souls in the current island as found", - "skyblocker.fairySouls.markAllMissing": "Marked all fairy souls in the current island as missing", + "skyblocker.fairySouls.markAllFound": "§b[§6Skyblocker§b] §rMarked all fairy souls in the current island as found", + "skyblocker.fairySouls.markAllMissing": "§b[§6Skyblocker§b] §rMarked all fairy souls in the current island as missing", + "skyblocker.relics.markAllFound": "§b[§6Skyblocker§b] §rMarked all relics as found", + "skyblocker.relics.markAllMissing": "§b[§6Skyblocker§b] §rMarked all relics as missing", "skyblocker.shortcuts.config": "Shortcuts Config", "skyblocker.shortcuts.notLoaded": "§c§lShortcuts not loaded yet", "skyblocker.shortcuts.command.target": "Target Command", diff --git a/src/main/resources/assets/skyblocker/spidersden/relics.json b/src/main/resources/assets/skyblocker/spidersden/relics.json new file mode 100644 index 0000000000..4610423b43 --- /dev/null +++ b/src/main/resources/assets/skyblocker/spidersden/relics.json @@ -0,0 +1,149 @@ +{ + "source": { + "link": "https://hypixel-skyblock.fandom.com/wiki/Relics", + "license": "CC-BY-SA " + }, + "total": 28, + "locations": [ + { + "x": -342, + "y": 122, + "z": -253 + }, + { + "x": -384, + "y": 89, + "z": -225 + }, + { + "x": -274, + "y": 100, + "z": -178 + }, + { + "x": -178, + "y": 136, + "z": -297 + }, + { + "x": -147, + "y": 83, + "z": -335 + }, + { + "x": -188, + "y": 80, + "z": -346 + }, + { + "x": -206, + "y": 63, + "z": -301 + }, + { + "x": -342, + "y": 89, + "z": -221 + }, + { + "x": -355, + "y": 86, + "z": -213 + }, + { + "x": -372, + "y": 89, + "z": -242 + }, + { + "x": -354, + "y": 73, + "z": -285 + }, + { + "x": -317, + "y": 69, + "z": -273 + }, + { + "x": -296, + "y": 37, + "z": -270 + }, + { + "x": -275, + "y": 64, + "z": -272 + }, + { + "x": -303, + "y": 71, + "z": -318 + }, + { + "x": -311, + "y": 69, + "z": -251 + }, + { + "x": -348, + "y": 65, + "z": -202 + }, + { + "x": -328, + "y": 50, + "z": -238 + }, + { + "x": -313, + "y": 58, + "z": -250 + }, + { + "x": -300, + "y": 51, + "z": -254 + }, + { + "x": -284, + "y": 49, + "z": -234 + }, + { + "x": -300, + "y": 50, + "z": -218 + }, + { + "x": -236, + "y": 51, + "z": -239 + }, + { + "x": -183, + "y": 51, + "z": -252 + }, + { + "x": -217, + "y": 58, + "z": -304 + }, + { + "x": -272, + "y": 48, + "z": -291 + }, + { + "x": -225, + "y": 70, + "z": -316 + }, + { + "x": -254, + "y": 57, + "z": -279 + } + ] +}