aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java2
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java17
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/FairySouls.java112
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Trivia.java31
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/shortcut/Shortcuts.java2
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/spidersden/Relics.java141
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/utils/PosUtils.java14
-rw-r--r--src/main/resources/assets/skyblocker/lang/en_us.json4
-rw-r--r--src/main/resources/assets/skyblocker/spidersden/relics.json149
9 files changed, 406 insertions, 66 deletions
diff --git a/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java b/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java
index b630e5f5..b28ad3d4 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.quicknav.QuickNav;
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 class SkyblockerMod implements ClientModInitializer {
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 58fc690c..d6e3f0fe 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 class SkyblockerConfig implements ConfigData {
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 class SkyblockerConfig implements ConfigData {
public static class FairySouls {
public boolean enableFairySoulsHelper = false;
public boolean highlightFoundSouls = true;
+ @ConfigEntry.Gui.Tooltip()
public boolean highlightOnlyNearbySouls = false;
}
@@ -438,6 +438,10 @@ public class SkyblockerConfig implements ConfigData {
@ConfigEntry.Gui.CollapsibleObject()
public Barn barn = new Barn();
+ @ConfigEntry.Category("spidersden")
+ @ConfigEntry.Gui.CollapsibleObject()
+ public SpidersDen spidersden = new SpidersDen();
+
@ConfigEntry.Category("dungeons")
@ConfigEntry.Gui.CollapsibleObject()
public Dungeons dungeons = new Dungeons();
@@ -561,6 +565,17 @@ public class SkyblockerConfig implements ConfigData {
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 e6b75152..f1de63e5 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.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.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;
@@ -45,11 +49,19 @@ public class FairySouls {
return fairySoulsLoaded.thenRunAsync(runnable);
}
- public static int getFairySoulsSize(@Nullable String location) {
+ public static int getFairySoulsAmount(@Nullable String location) {
return location == null ? maxSouls : fairySouls.get(location).size();
}
public static void init() {
+ loadFairySouls();
+ ClientLifecycleEvents.CLIENT_STOPPING.register(FairySouls::saveFairySouls);
+ ClientReceiveMessageEvents.GAME.register(FairySouls::onChatMessage);
+ WorldRenderEvents.AFTER_TRANSLUCENT.register(FairySouls::render);
+ ClientCommandRegistrationCallback.EVENT.register(FairySouls::registerCommands);
+ }
+
+ 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()));
@@ -62,53 +74,39 @@ public class FairySouls {
}
ImmutableSet.Builder<BlockPos> 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()));
+ reader.close();
+ LOGGER.info("[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<String, JsonElement> foundFairiesForProfileJson : JsonParser.parseReader(reader).getAsJsonObject().asMap().entrySet()) {
Map<String, Set<BlockPos>> foundFairiesForProfile = new HashMap<>();
for (Map.Entry<String, JsonElement> foundFairiesForLocationJson : foundFairiesForProfileJson.getValue().getAsJsonObject().asMap().entrySet()) {
Set<BlockPos> 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.info("[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) {
+ private static void saveFairySouls(MinecraftClient client) {
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(SkyblockerMod.CONFIG_DIR.resolve("found_fairy_souls.json").toFile()));
JsonObject foundFairiesJson = new JsonObject();
@@ -117,7 +115,7 @@ public class FairySouls {
for (Map.Entry<String, Set<BlockPos>> 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,12 +123,35 @@ public class FairySouls {
}
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<FabricClientCommandSource> 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 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();
+ }
+ }
+
+ private static void render(WorldRenderContext context) {
SkyblockerConfig.FairySouls fairySoulsConfig = SkyblockerConfig.get().general.fairySouls;
if (fairySoulsConfig.enableFairySoulsHelper && fairySoulsLoaded.isDone() && fairySouls.containsKey(Utils.getLocationRaw())) {
@@ -157,35 +178,28 @@ public class FairySouls {
return !foundFairiesForProfileAndLocation.contains(fairySoulPos);
}
- public 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();
- }
- }
-
private static void markClosestFairyFound() {
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)
- .min(Comparator.comparingDouble(fairySoulPos -> fairySoulPos.getSquaredDistance(player.getPos())))
- .filter(fairySoulPos -> fairySoulPos.getSquaredDistance(player.getPos()) <= 16)
- .ifPresent(fairySoulPos -> {
- initializeFoundFairiesForCurrentProfileAndLocation();
- foundFairies.get(Utils.getProfile()).get(Utils.getLocationRaw()).add(fairySoulPos);
- });
+ .filter(FairySouls::isFairySoulNotFound)
+ .min(Comparator.comparingDouble(fairySoulPos -> fairySoulPos.getSquaredDistance(player.getPos())))
+ .filter(fairySoulPos -> fairySoulPos.getSquaredDistance(player.getPos()) <= 16)
+ .ifPresent(fairySoulPos -> {
+ initializeFoundFairiesForCurrentProfileAndLocation();
+ foundFairies.get(Utils.getProfile()).get(Utils.getLocationRaw()).add(fairySoulPos);
+ });
}
- public static void markAllFairiesFound() {
+ 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<String, Set<BlockPos>> foundFairiesForProfile = foundFairies.get(Utils.getProfile());
if (foundFairiesForProfile != null) {
foundFairiesForProfile.remove(Utils.getLocationRaw());
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Trivia.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Trivia.java
index 8497041b..f1b886c2 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Trivia.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Trivia.java
@@ -1,9 +1,9 @@
package me.xmrvizzy.skyblocker.skyblock.dungeon;
import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
+import me.xmrvizzy.skyblocker.skyblock.FairySouls;
import me.xmrvizzy.skyblocker.utils.chat.ChatFilterResult;
import me.xmrvizzy.skyblocker.utils.chat.ChatPatternListener;
-import me.xmrvizzy.skyblocker.skyblock.FairySouls;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.text.Text;
@@ -77,24 +77,25 @@ public class Trivia extends ChatPatternListener {
answers.put("Which of these enemies does not spawn in the Spider's Den?", new String[]{"Zombie Spider", "Cave Spider", "Wither Skeleton", "Dashing Spooder", "Broodfather", "Night Spider"});
answers.put("Which of these monsters only spawns at night?", new String[]{"Zombie Villager", "Ghast"});
answers.put("Which of these is not a dragon in The End?", new String[]{"Zoomer Dragon", "Weak Dragon", "Stonk Dragon", "Holy Dragon", "Boomer Dragon", "Booger Dragon", "Older Dragon", "Elder Dragon", "Stable Dragon", "Professor Dragon"});
+
FairySouls.runAsyncAfterFairySoulsLoad(() -> {
- answers.put("How many total Fairy Souls are there?", getFairySoulsSizeString(null));
- answers.put("How many Fairy Souls are there in Spider's Den?", getFairySoulsSizeString("combat_1"));
- answers.put("How many Fairy Souls are there in The End?", getFairySoulsSizeString("combat_3"));
- answers.put("How many Fairy Souls are there in The Farming Islands?", getFairySoulsSizeString("farming_1"));
- answers.put("How many Fairy Souls are there in Crimson Isle?", getFairySoulsSizeString("crimson_isle"));
- answers.put("How many Fairy Souls are there in The Park?", getFairySoulsSizeString("foraging_1"));
- answers.put("How many Fairy Souls are there in Jerry's Workshop?", getFairySoulsSizeString("winter"));
- answers.put("How many Fairy Souls are there in Hub?", getFairySoulsSizeString("hub"));
- answers.put("How many Fairy Souls are there in The Hub?", getFairySoulsSizeString("hub"));
- answers.put("How many Fairy Souls are there in Deep Caverns?", getFairySoulsSizeString("mining_2"));
- answers.put("How many Fairy Souls are there in Gold Mine?", getFairySoulsSizeString("mining_1"));
- answers.put("How many Fairy Souls are there in Dungeon Hub?", getFairySoulsSizeString("dungeon_hub"));
+ answers.put("How many total Fairy Souls are there?", getFairySoulsAmountString(null));
+ answers.put("How many Fairy Souls are there in Spider's Den?", getFairySoulsAmountString("combat_1"));
+ answers.put("How many Fairy Souls are there in The End?", getFairySoulsAmountString("combat_3"));
+ answers.put("How many Fairy Souls are there in The Farming Islands?", getFairySoulsAmountString("farming_1"));
+ answers.put("How many Fairy Souls are there in Crimson Isle?", getFairySoulsAmountString("crimson_isle"));
+ answers.put("How many Fairy Souls are there in The Park?", getFairySoulsAmountString("foraging_1"));
+ answers.put("How many Fairy Souls are there in Jerry's Workshop?", getFairySoulsAmountString("winter"));
+ answers.put("How many Fairy Souls are there in Hub?", getFairySoulsAmountString("hub"));
+ answers.put("How many Fairy Souls are there in The Hub?", getFairySoulsAmountString("hub"));
+ answers.put("How many Fairy Souls are there in Deep Caverns?", getFairySoulsAmountString("mining_2"));
+ answers.put("How many Fairy Souls are there in Gold Mine?", getFairySoulsAmountString("mining_1"));
+ answers.put("How many Fairy Souls are there in Dungeon Hub?", getFairySoulsAmountString("dungeon_hub"));
});
}
@NotNull
- private static String[] getFairySoulsSizeString(@Nullable String location) {
- return new String[]{"%d Fairy Souls".formatted(FairySouls.getFairySoulsSize(location))};
+ private static String[] getFairySoulsAmountString(@Nullable String location) {
+ return new String[]{"%d Fairy Souls".formatted(FairySouls.getFairySoulsAmount(location))};
}
}
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 89329c6c..14bc1db4 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 @@ public class Shortcuts {
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 00000000..6f7f1ee6
--- /dev/null
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/spidersden/Relics.java
@@ -0,0 +1,141 @@
+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 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.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.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.*;
+
+public class Relics {
+ private static final Logger LOGGER = LoggerFactory.getLogger(Relics.class);
+ private static int totalRelics = 0;
+ private static final List<BlockPos> relics = new ArrayList<>();
+ private static final Map<String, Set<BlockPos>> foundRelics = new HashMap<>();
+
+ public static void init() {
+ ClientLifecycleEvents.CLIENT_STARTED.register(Relics::onClientStarted);
+ ClientLifecycleEvents.CLIENT_STOPPING.register(Relics::onClientStopping);
+ ClientReceiveMessageEvents.GAME.register(Relics::onChatMessage);
+ WorldRenderEvents.AFTER_TRANSLUCENT.register(Relics::render);
+ }
+
+ private static void onClientStarted(MinecraftClient client) {
+ try {
+ BufferedReader reader = client.getResourceManager().openAsReader(new Identifier(SkyblockerMod.NAMESPACE, "spidersden/relics.json"));
+ for (Map.Entry<String, JsonElement> 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()));
+ }
+ }
+ }
+ reader.close();
+ 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<String, JsonElement> profileJson : JsonParser.parseReader(reader).getAsJsonObject().asMap().entrySet()) {
+ Set<BlockPos> foundRelicsForProfile = new HashSet<>();
+ for (JsonElement foundRelicsJson : profileJson.getValue().getAsJsonArray().asList()) {
+ foundRelicsForProfile.add(PosUtils.parsePosString(foundRelicsJson.getAsString()));
+ }
+ foundRelics.put(profileJson.getKey(), foundRelicsForProfile);
+ }
+ reader.close();
+ LOGGER.info("[Skyblocker] Loaded found relics");
+ } catch (FileNotFoundException ignored) {
+ } catch (IOException e) {
+ LOGGER.error("[Skyblocker] Failed to load found relics", e);
+ }
+ }
+
+ private static void onClientStopping(MinecraftClient client) {
+ try {
+ BufferedWriter writer = new BufferedWriter(new FileWriter(SkyblockerMod.CONFIG_DIR.resolve("found_relics.json").toFile()));
+ JsonObject json = new JsonObject();
+ for (Map.Entry<String, Set<BlockPos>> 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);
+ writer.close();
+ LOGGER.info("[Skyblocker] Saved found relics");
+ } catch (IOException e) {
+ LOGGER.error("[Skyblocker] Failed to write found relics to file", e);
+ }
+ }
+
+ 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 render(WorldRenderContext context) {
+ SkyblockerConfig.Relics config = SkyblockerConfig.get().locations.spidersden.relics;
+
+ if (config.enableRelicsHelper && Utils.getLocationRaw().equals("combat_1")) {
+ for (BlockPos fairySoulPos : relics) {
+ boolean isRelicFound = isRelicFound(fairySoulPos);
+ if (isRelicFound && !config.highlightFoundRelics) {
+ continue;
+ }
+ float[] colorComponents = isRelicFound ? DyeColor.BROWN.getColorComponents() : DyeColor.YELLOW.getColorComponents();
+ RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, fairySoulPos, colorComponents, 0.5F);
+ }
+ }
+ }
+
+ private static boolean isRelicFound(BlockPos pos) {
+ Set<BlockPos> foundRelicsForProfile = foundRelics.get(Utils.getProfile());
+ if (foundRelicsForProfile == null) {
+ return false;
+ }
+ return foundRelicsForProfile.contains(pos);
+ }
+
+ private static void markClosestRelicFound() {
+ 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((relicPos) -> !Relics.isRelicFound(relicPos))
+ .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);
+ });
+ }
+}
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 00000000..4f32292c
--- /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 cdaa7602..d8d10507 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",
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 00000000..4610423b
--- /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 <https://www.fandom.com/licensing>"
+ },
+ "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
+ }
+ ]
+}