Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fairy Souls Helper #167

Merged
merged 11 commits into from
Jun 24, 2023
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ dependencies {
// https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit used pull data from the NEU item repo
include(implementation("org.eclipse.jgit:org.eclipse.jgit:6.4.0.202211300538-r"))

// Renderer (https://github.com/0x3C50/Renderer)
include modImplementation("com.github.0x3C50:Renderer:${project.renderer_version}")

include(modImplementation ("meteordevelopment:discord-ipc:1.1"))
}

Expand Down
2 changes: 2 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ clothconfig_version=11.0.99
mod_menu_version=7.0.1
## REI (https://www.curseforge.com/minecraft/mc-mods/roughly-enough-items/files)
rei_version=12.0.625
## Renderer (https://github.com/0x3C50/Renderer)
renderer_version = master-SNAPSHOT

# Mod Properties
mod_version = 1.10.0
Expand Down
26 changes: 14 additions & 12 deletions src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package me.xmrvizzy.skyblocker;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import me.xmrvizzy.skyblocker.chat.ChatMessageListener;
import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
import me.xmrvizzy.skyblocker.discord.DiscordRPCManager;
import me.xmrvizzy.skyblocker.gui.ContainerSolverManager;
import me.xmrvizzy.skyblocker.skyblock.BackpackPreview;
import me.xmrvizzy.skyblocker.skyblock.FishingHelper;
import me.xmrvizzy.skyblocker.skyblock.HotbarSlotLock;
import me.xmrvizzy.skyblocker.skyblock.StatusBarTracker;
import me.xmrvizzy.skyblocker.skyblock.api.RepositoryUpdate;
import me.xmrvizzy.skyblocker.skyblock.*;
import me.xmrvizzy.skyblocker.skyblock.api.StatsCommand;
import me.xmrvizzy.skyblocker.skyblock.dungeon.DungeonBlaze;
import me.xmrvizzy.skyblocker.skyblock.dungeon.DungeonMap;
Expand All @@ -20,21 +18,23 @@
import me.xmrvizzy.skyblocker.skyblock.quicknav.QuickNav;
import me.xmrvizzy.skyblocker.skyblock.tabhud.TabHud;
import me.xmrvizzy.skyblocker.skyblock.tabhud.util.PlayerListMgr;
import me.xmrvizzy.skyblocker.utils.MessageScheduler;
import me.xmrvizzy.skyblocker.utils.Scheduler;
import me.xmrvizzy.skyblocker.utils.UpdateChecker;
import me.xmrvizzy.skyblocker.utils.Utils;
import me.xmrvizzy.skyblocker.utils.*;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.MinecraftClient;

import java.nio.file.Path;

/**
* Main class for Skyblocker which initializes features, registers events, and
* manages ticks. This class will be instantiated by Fabric. Do not instantiate
* this class.
*/
public class SkyblockerMod implements ClientModInitializer {
public static final String NAMESPACE = "skyblocker";
public static final Path CONFIG_DIR = FabricLoader.getInstance().getConfigDir().resolve(NAMESPACE);
public static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static SkyblockerMod INSTANCE;

@SuppressWarnings("deprecation")
Expand Down Expand Up @@ -63,12 +63,13 @@ public static SkyblockerMod getInstance() {
@Override
public void onInitializeClient() {
ClientTickEvents.END_CLIENT_TICK.register(this::tick);
Utils.init();
HotbarSlotLock.init();
SkyblockerConfig.init();
PriceInfoTooltip.init();
WikiLookup.init();
ItemRegistry.init();
RepositoryUpdate.init();
NEURepo.init();
BackpackPreview.init();
QuickNav.init();
StatsCommand.init();
Expand All @@ -78,10 +79,11 @@ public void onInitializeClient() {
DiscordRPCManager.init();
LividColor.init();
FishingHelper.init();
FairySouls.init();
TabHud.init();
containerSolverManager.init();
DungeonMap.init();
scheduler.scheduleCyclic(Utils::sbChecker, 20);
containerSolverManager.init();
scheduler.scheduleCyclic(Utils::update, 20);
scheduler.scheduleCyclic(DiscordRPCManager::updateDataAndPresence, 100);
scheduler.scheduleCyclic(DungeonBlaze::update, 4);
scheduler.scheduleCyclic(LividColor::update, 10);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ public static class General {
@ConfigEntry.Gui.CollapsibleObject()
public Fishing fishing = new Fishing();

@ConfigEntry.Category("fairySouls")
@ConfigEntry.Gui.CollapsibleObject()
public FairySouls fairySouls = new FairySouls();

@ConfigEntry.Category("itemList")
@ConfigEntry.Gui.CollapsibleObject()
public ItemList itemList = new ItemList();
Expand Down Expand Up @@ -219,6 +223,10 @@ public static class Fishing {
public boolean enableFishingHelper = true;
}

public static class FairySouls {
public boolean enableFairySoulsHelper = false;
}

public static class Hitbox {
public boolean oldFarmlandHitbox = true;
public boolean oldLeverHitbox = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package me.xmrvizzy.skyblocker.mixin.accessor;

import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.block.entity.BeaconBlockEntityRenderer;
import net.minecraft.client.util.math.MatrixStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;

@Mixin(BeaconBlockEntityRenderer.class)
public interface BeaconBlockEntityRendererInvoker {
@SuppressWarnings("unused")
@Invoker("renderBeam")
static void renderBeam(MatrixStack matrices, VertexConsumerProvider vertexConsumers, float tickDelta, long worldTime, int yOffset, int maxY, float[] color) {
throw new IllegalStateException("Mixin invoker failed to apply.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public static void init() {
}

public static void tick() {
Utils.sbChecker(); // force update isOnSkyblock to prevent crash on disconnect
Utils.update(); // force update isOnSkyblock to prevent crash on disconnect
if (Utils.isOnSkyblock()) {
// save all dirty storages
saveStorage();
Expand Down
175 changes: 175 additions & 0 deletions src/main/java/me/xmrvizzy/skyblocker/skyblock/FairySouls.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
package me.xmrvizzy.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 me.xmrvizzy.skyblocker.SkyblockerMod;
import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
import me.xmrvizzy.skyblocker.utils.NEURepo;
import me.xmrvizzy.skyblocker.utils.RenderHelper;
import me.xmrvizzy.skyblocker.utils.Utils;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
import net.fabricmc.fabric.api.client.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.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 FairySouls {
private static final Logger LOGGER = LoggerFactory.getLogger(FairySouls.class);
private static CompletableFuture<Void> fairySoulsLoaded;
private static final Map<String, Set<BlockPos>> fairySouls = new HashMap<>();
private static final Map<String, Map<String, Set<BlockPos>>> foundFairies = new HashMap<>();

public static void init() {
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")) {
continue;
}
ImmutableSet.Builder<BlockPos> fairySoulsForLocation = ImmutableSet.builder();
for (JsonElement fairySoul : fairySoulJson.getValue().getAsJsonArray().asList()) {
fairySoulsForLocation.add(parseBlockPos(fairySoul));
}
fairySouls.put(fairySoulJson.getKey(), fairySoulsForLocation.build());
}
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));
}
foundFairiesForProfile.put(foundFairiesForLocationJson.getKey(), foundFairiesForLocation);
}
foundFairies.put(foundFairiesForProfileJson.getKey(), foundFairiesForProfile);
}
reader.close();
} catch (IOException e) {
LOGGER.error("Failed to load found fairy souls", e);
} catch (Exception e) {
LOGGER.error("Encountered unknown exception loading 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()));
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(foundFairy.getX() + "," + foundFairy.getY() + "," + foundFairy.getZ());
}
foundFairiesForProfileJson.add(foundFairiesForLocation.getKey(), foundFairiesForLocationJson);
}
foundFairiesJson.add(foundFairiesForProfile.getKey(), foundFairiesForProfileJson);
}
SkyblockerMod.GSON.toJson(foundFairiesJson, writer);
writer.close();
} catch (IOException e) {
LOGGER.error("Failed to write found fairy souls to file.");
}
}

public static void render(WorldRenderContext context) {
if (SkyblockerConfig.get().general.fairySouls.enableFairySoulsHelper && fairySoulsLoaded.isDone() && fairySouls.containsKey(Utils.getLocationRaw())) {
for (BlockPos fairySoul : fairySouls.get(Utils.getLocationRaw())) {
float[] colorComponents = isFairySoulNotFound(fairySoul) ? DyeColor.GREEN.getColorComponents() : DyeColor.RED.getColorComponents();
RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, fairySoul, colorComponents, 0.5F);
}
}
}

private static boolean isFairySoulNotFound(BlockPos fairySoul) {
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(fairySoul);
}

public static void onChatMessage(Text text, boolean overlay) {
String message = text.getString();
if (message.equals("You have already found that Fairy Soul!") || message.equals("SOUL! You found a Fairy Soul!")) {
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.");
return;
}
fairySouls.get(Utils.getLocationRaw()).stream().filter(FairySouls::isFairySoulNotFound).min(Comparator.comparingDouble(fairySoul -> fairySoul.getSquaredDistance(player.getPos()))).ifPresent(fairySoul -> {
initializeFoundFairiesForCurrentProfileAndLocation();
foundFairies.get(Utils.getProfile()).get(Utils.getLocationRaw()).add(fairySoul);
});
}

public static void markAllFairiesFound() {
initializeFoundFairiesForCurrentProfileAndLocation();
foundFairies.get(Utils.getProfile()).get(Utils.getLocationRaw()).addAll(fairySouls.get(Utils.getLocationRaw()));
}

public static void markAllFairiesNotFound() {
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<>());
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ public class LividColor {
private static int tenTicks = 0;

public static void init() {
ClientReceiveMessageEvents.ALLOW_GAME.register((message, overlay) -> {
ClientReceiveMessageEvents.GAME.register((message, overlay) -> {
if (SkyblockerConfig.get().locations.dungeons.lividColor.enableLividColor && message.getString().equals("[BOSS] Livid: I respect you for making it to here, but I'll be your undoing.")) {
tenTicks = 8;
}
return true;
});
}

Expand Down