aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/de/hysky/skyblocker/skyblock/FairySouls.java
diff options
context:
space:
mode:
authorYasin <a.piri@hotmail.de>2023-10-09 12:58:02 +0200
committerYasin <a.piri@hotmail.de>2023-10-09 12:58:02 +0200
commitbd3f0329d0e391bd84b5f9e3ff207d9dd9815853 (patch)
tree2fd1d1ef625f57acc2e4916c967d8d2393844798 /src/main/java/de/hysky/skyblocker/skyblock/FairySouls.java
parent2315b90da8117f28f66348927afdb621ee4fc815 (diff)
downloadSkyblocker-bd3f0329d0e391bd84b5f9e3ff207d9dd9815853.tar.gz
Skyblocker-bd3f0329d0e391bd84b5f9e3ff207d9dd9815853.tar.bz2
Skyblocker-bd3f0329d0e391bd84b5f9e3ff207d9dd9815853.zip
new pr because fixing merge conflict would take too long
Diffstat (limited to 'src/main/java/de/hysky/skyblocker/skyblock/FairySouls.java')
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/FairySouls.java215
1 files changed, 215 insertions, 0 deletions
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/FairySouls.java b/src/main/java/de/hysky/skyblocker/skyblock/FairySouls.java
new file mode 100644
index 00000000..24465e06
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/FairySouls.java
@@ -0,0 +1,215 @@
+package de.hysky.skyblocker.skyblock;
+
+import com.google.common.collect.ImmutableSet;
+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 de.hysky.skyblocker.SkyblockerMod;
+import de.hysky.skyblocker.config.SkyblockerConfig;
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.utils.NEURepo;
+import de.hysky.skyblocker.utils.PosUtils;
+import de.hysky.skyblocker.utils.Utils;
+import de.hysky.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.math.BlockPos;
+import org.jetbrains.annotations.Nullable;
+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 FairySouls {
+ private static final Logger LOGGER = LoggerFactory.getLogger(FairySouls.class);
+ private static CompletableFuture<Void> fairySoulsLoaded;
+ private static int maxSouls = 0;
+ private static final Map<String, Set<BlockPos>> fairySouls = new HashMap<>();
+ private static final Map<String, Map<String, Set<BlockPos>>> foundFairies = new HashMap<>();
+
+ @SuppressWarnings("UnusedReturnValue")
+ public static CompletableFuture<Void> 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.");
+ return CompletableFuture.completedFuture(null);
+ }
+ return fairySoulsLoaded.thenRunAsync(runnable);
+ }
+
+ public static int getFairySoulsSize(@Nullable String location) {
+ return location == null ? maxSouls : fairySouls.get(location).size();
+ }
+
+ 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()))) {
+ for (Map.Entry<String, JsonElement> fairySoulJson : JsonParser.parseReader(reader).getAsJsonObject().asMap().entrySet()) {
+ if (fairySoulJson.getKey().equals("//") || fairySoulJson.getKey().equals("Max Souls")) {
+ if (fairySoulJson.getKey().equals("Max Souls")) {
+ maxSouls = fairySoulJson.getValue().getAsInt();
+ }
+ continue;
+ }
+ ImmutableSet.Builder<BlockPos> fairySoulsForLocation = ImmutableSet.builder();
+ for (JsonElement fairySoul : fairySoulJson.getValue().getAsJsonArray().asList()) {
+ fairySoulsForLocation.add(PosUtils.parsePosString(fairySoul.getAsString()));
+ }
+ fairySouls.put(fairySoulJson.getKey(), fairySoulsForLocation.build());
+ }
+ 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<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(PosUtils.parsePosString(foundFairy.getAsString()));
+ }
+ foundFairiesForProfile.put(foundFairiesForLocationJson.getKey(), foundFairiesForLocation);
+ }
+ foundFairies.put(foundFairiesForProfileJson.getKey(), foundFairiesForProfile);
+ }
+ LOGGER.debug("[Skyblocker] Loaded found fairy souls");
+ } catch (FileNotFoundException ignored) {
+ } catch (IOException e) {
+ LOGGER.error("[Skyblocker] Failed to load found fairy souls", e);
+ }
+ });
+ }
+
+ 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<String, Map<String, Set<BlockPos>>> foundFairiesForProfile : foundFairies.entrySet()) {
+ JsonObject foundFairiesForProfileJson = new JsonObject();
+ for (Map.Entry<String, Set<BlockPos>> foundFairiesForLocation : foundFairiesForProfile.getValue().entrySet()) {
+ JsonArray foundFairiesForLocationJson = new JsonArray();
+ for (BlockPos foundFairy : foundFairiesForLocation.getValue()) {
+ foundFairiesForLocationJson.add(PosUtils.getPosString(foundFairy));
+ }
+ foundFairiesForProfileJson.add(foundFairiesForLocation.getKey(), foundFairiesForLocationJson);
+ }
+ foundFairiesJson.add(foundFairiesForProfile.getKey(), foundFairiesForProfileJson);
+ }
+ SkyblockerMod.GSON.toJson(foundFairiesJson, writer);
+ writer.close();
+ LOGGER.info("[Skyblocker] Saved found fairy souls");
+ } catch (IOException e) {
+ LOGGER.error("[Skyblocker] Failed to write found fairy souls to file", e);
+ }
+ }
+
+ 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 render(WorldRenderContext context) {
+ SkyblockerConfig.FairySouls fairySoulsConfig = SkyblockerConfigManager.get().general.fairySouls;
+
+ if (fairySoulsConfig.enableFairySoulsHelper && fairySoulsLoaded.isDone() && fairySouls.containsKey(Utils.getLocationRaw())) {
+ for (BlockPos fairySoulPos : fairySouls.get(Utils.getLocationRaw())) {
+ boolean fairySoulNotFound = isFairySoulMissing(fairySoulPos);
+ if (!fairySoulsConfig.highlightFoundSouls && !fairySoulNotFound || fairySoulsConfig.highlightOnlyNearbySouls && fairySoulPos.getSquaredDistance(context.camera().getPos()) > 2500) {
+ continue;
+ }
+ float[] colorComponents = fairySoulNotFound ? DyeColor.GREEN.getColorComponents() : DyeColor.RED.getColorComponents();
+ RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, fairySoulPos, colorComponents, 0.5F);
+ }
+ }
+ }
+
+ 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 markClosestFairyFound() {
+ if (!fairySoulsLoaded.isDone()) return;
+ PlayerEntity player = MinecraftClient.getInstance().player;
+ if (player == null) {
+ LOGGER.warn("[Skyblocker] Failed to mark closest fairy soul as found because player is null");
+ return;
+ }
+ fairySouls.get(Utils.getLocationRaw()).stream()
+ .filter(FairySouls::isFairySoulMissing)
+ .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);
+ });
+ }
+
+ private static boolean isFairySoulMissing(BlockPos fairySoulPos) {
+ Map<String, Set<BlockPos>> foundFairiesForProfile = foundFairies.get(Utils.getProfile());
+ if (foundFairiesForProfile == null) {
+ return true;
+ }
+ Set<BlockPos> 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 markAllFairiesOnCurrentIslandMissing() {
+ Map<String, Set<BlockPos>> foundFairiesForProfile = foundFairies.get(Utils.getProfile());
+ if (foundFairiesForProfile != null) {
+ foundFairiesForProfile.remove(Utils.getLocationRaw());
+ }
+ }
+
+ private static void initializeFoundFairiesForCurrentProfileAndLocation() {
+ initializeFoundFairiesForProfileAndLocation(Utils.getProfile(), Utils.getLocationRaw());
+ }
+
+ private static void initializeFoundFairiesForProfileAndLocation(String profile, String location) {
+ foundFairies.computeIfAbsent(profile, profileKey -> new HashMap<>());
+ foundFairies.get(profile).computeIfAbsent(location, locationKey -> new HashSet<>());
+ }
+}