aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKevin <92656833+kevinthegreat1@users.noreply.github.com>2024-08-04 14:00:38 +0800
committerGitHub <noreply@github.com>2024-08-04 14:00:38 +0800
commitbb356d2eff2ca7dff29dfa6cebf8bda941db28b0 (patch)
tree84b15191d06da70807a79e8aafaf76c5af8a7164 /src
parent9b4ca8ccb61154117f163774ab4d4aff8f6c5e50 (diff)
parent20370896eaacb73d8c26a3a88575fc7bd58aff94 (diff)
downloadSkyblocker-bb356d2eff2ca7dff29dfa6cebf8bda941db28b0.tar.gz
Skyblocker-bb356d2eff2ca7dff29dfa6cebf8bda941db28b0.tar.bz2
Skyblocker-bb356d2eff2ca7dff29dfa6cebf8bda941db28b0.zip
Merge pull request #849 from olim88/treasure-chest-highlighter
Treasure Chest Highlighter for crystal hollows
Diffstat (limited to 'src')
-rw-r--r--src/main/java/de/hysky/skyblocker/SkyblockerMod.java1
-rw-r--r--src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java27
-rw-r--r--src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java8
-rw-r--r--src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java3
-rw-r--r--src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java6
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsChestHighlighter.java178
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java14
-rw-r--r--src/main/resources/assets/skyblocker/lang/en_us.json4
8 files changed, 233 insertions, 8 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
index b1d25a01..d5b8204f 100644
--- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
+++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java
@@ -134,6 +134,7 @@ public class SkyblockerMod implements ClientModInitializer {
LowerSensitivity.init();
CrystalsLocationsManager.init();
WishingCompassSolver.init();
+ CrystalsChestHighlighter.init();
MetalDetector.init();
ChatMessageListener.init();
Shortcuts.init();
diff --git a/src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java
index 796a6105..74be78cb 100644
--- a/src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java
+++ b/src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java
@@ -4,17 +4,16 @@ import de.hysky.skyblocker.config.ConfigUtils;
import de.hysky.skyblocker.config.SkyblockerConfig;
import de.hysky.skyblocker.config.configs.MiningConfig;
import de.hysky.skyblocker.skyblock.dwarven.CrystalsHudConfigScreen;
-import dev.isxander.yacl3.api.ButtonOption;
-import dev.isxander.yacl3.api.ConfigCategory;
-import dev.isxander.yacl3.api.Option;
-import dev.isxander.yacl3.api.OptionDescription;
-import dev.isxander.yacl3.api.OptionGroup;
import de.hysky.skyblocker.skyblock.dwarven.DwarvenHudConfigScreen;
+import dev.isxander.yacl3.api.*;
+import dev.isxander.yacl3.api.controller.ColorControllerBuilder;
import dev.isxander.yacl3.api.controller.FloatFieldControllerBuilder;
import dev.isxander.yacl3.api.controller.IntegerSliderControllerBuilder;
import net.minecraft.client.MinecraftClient;
import net.minecraft.text.Text;
+import java.awt.*;
+
public class MiningCategory {
public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig config) {
@@ -111,7 +110,23 @@ public class MiningCategory {
newValue -> config.mining.crystalHollows.nucleusWaypoints = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
- .build())
+ .option(Option.<Boolean>createBuilder()
+ .name(Text.translatable("skyblocker.config.mining.crystalHollows.chestHighlighter"))
+ .description(OptionDescription.of(Text.translatable("skyblocker.config.mining.crystalHollows.chestHighlighter.@Tooltip")))
+ .binding(defaults.mining.crystalHollows.chestHighlighter,
+ () -> config.mining.crystalHollows.chestHighlighter,
+ newValue -> config.mining.crystalHollows.chestHighlighter = newValue)
+ .controller(ConfigUtils::createBooleanController)
+ .build())
+ .option(Option.<Color>createBuilder()
+ .name(Text.translatable("skyblocker.config.mining.crystalHollows.chestHighlighter.color"))
+ .description(OptionDescription.of(Text.translatable("skyblocker.config.mining.crystalHollows.chestHighlighter.color.@Tooltip")))
+ .binding(defaults.mining.crystalHollows.chestHighlightColor,
+ () -> config.mining.crystalHollows.chestHighlightColor,
+ newValue -> config.mining.crystalHollows.chestHighlightColor = newValue)
+ .controller(v -> ColorControllerBuilder.create(v).allowAlpha(true))
+ .build())
+ .build())
//Crystal Hollows Map
.group(OptionGroup.createBuilder()
diff --git a/src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java
index dcf70f24..5236f1eb 100644
--- a/src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java
+++ b/src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java
@@ -2,6 +2,8 @@ package de.hysky.skyblocker.config.configs;
import dev.isxander.yacl3.config.v2.api.SerialEntry;
+import java.awt.*;
+
public class MiningConfig {
@SerialEntry
public boolean enableDrillFuel = true;
@@ -67,6 +69,12 @@ public class MiningConfig {
@SerialEntry
public boolean nucleusWaypoints = false;
+
+ @SerialEntry
+ public boolean chestHighlighter = true;
+
+ @SerialEntry
+ public Color chestHighlightColor = new Color(0, 0, 255, 128);
}
public static class CrystalsHud {
diff --git a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java
index c0cd8b7b..4e263015 100644
--- a/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixins/ClientPlayNetworkHandlerMixin.java
@@ -10,6 +10,7 @@ import de.hysky.skyblocker.skyblock.crimson.dojo.DojoManager;
import de.hysky.skyblocker.skyblock.dungeon.DungeonScore;
import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager;
import de.hysky.skyblocker.skyblock.dwarven.WishingCompassSolver;
+import de.hysky.skyblocker.skyblock.dwarven.CrystalsChestHighlighter;
import de.hysky.skyblocker.skyblock.end.BeaconHighlighter;
import de.hysky.skyblocker.skyblock.end.EnderNodes;
import de.hysky.skyblocker.skyblock.end.TheEnd;
@@ -79,6 +80,7 @@ public abstract class ClientPlayNetworkHandlerMixin {
@Inject(method = "onPlaySound", at = @At("RETURN"))
private void skyblocker$onPlaySound(PlaySoundS2CPacket packet, CallbackInfo ci) {
FishingHelper.onSound(packet);
+ CrystalsChestHighlighter.onSound(packet);
}
@WrapWithCondition(method = "warnOnUnknownPayload", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V", remap = false))
@@ -100,6 +102,7 @@ public abstract class ClientPlayNetworkHandlerMixin {
private void skyblocker$onParticle(ParticleS2CPacket packet, CallbackInfo ci) {
MythologicalRitual.onParticle(packet);
DojoManager.onParticle(packet);
+ CrystalsChestHighlighter.onParticle(packet);
EnderNodes.onParticle(packet);
WishingCompassSolver.onParticle(packet);
}
diff --git a/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java b/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java
index a2d7887b..fdc199e8 100644
--- a/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java
+++ b/src/main/java/de/hysky/skyblocker/mixins/ClientWorldMixin.java
@@ -2,6 +2,7 @@ package de.hysky.skyblocker.mixins;
import de.hysky.skyblocker.skyblock.crimson.dojo.DojoManager;
import de.hysky.skyblocker.skyblock.dungeon.device.SimonSays;
+import de.hysky.skyblocker.skyblock.dwarven.CrystalsChestHighlighter;
import de.hysky.skyblocker.utils.Utils;
import net.minecraft.block.BlockState;
import net.minecraft.client.world.ClientWorld;
@@ -25,7 +26,10 @@ public class ClientWorldMixin {
if (Utils.isInCrimson()) {
DojoManager.onBlockUpdate(pos.toImmutable(), state);
}
-
+ else if (Utils.isInCrystalHollows()) {
+ CrystalsChestHighlighter.onBlockUpdate(pos.toImmutable(), state);
+ }
SimonSays.onBlockUpdate(pos, state);
+
}
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsChestHighlighter.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsChestHighlighter.java
new file mode 100644
index 00000000..85d17e5f
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/CrystalsChestHighlighter.java
@@ -0,0 +1,178 @@
+package de.hysky.skyblocker.skyblock.dwarven;
+
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.utils.Utils;
+import de.hysky.skyblocker.utils.render.RenderHelper;
+import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;
+import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents;
+import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
+import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
+import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
+import net.minecraft.block.BlockState;
+import net.minecraft.block.Blocks;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.network.packet.s2c.play.ParticleS2CPacket;
+import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket;
+import net.minecraft.particle.ParticleTypes;
+import net.minecraft.text.Text;
+import net.minecraft.util.hit.BlockHitResult;
+import net.minecraft.util.hit.HitResult;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Box;
+import net.minecraft.util.math.Vec3d;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CrystalsChestHighlighter {
+
+ private static final MinecraftClient CLIENT = MinecraftClient.getInstance();
+ private static final String CHEST_SPAWN_MESSAGE = "You uncovered a treasure chest!";
+ private static final long MAX_PARTICLE_LIFE_TIME = 250;
+ private static final Vec3d LOCK_HIGHLIGHT_SIZE = new Vec3d(0.1, 0.1, 0.1);
+
+ private static int waitingForChest = 0;
+ private static final List<BlockPos> activeChests = new ArrayList<>();
+ private static final Object2LongOpenHashMap<Vec3d> activeParticles = new Object2LongOpenHashMap<>();
+ private static int currentLockCount = 0;
+ private static int neededLockCount = 0;
+
+ public static void init() {
+ ClientReceiveMessageEvents.GAME.register(CrystalsChestHighlighter::extractLocationFromMessage);
+ WorldRenderEvents.AFTER_TRANSLUCENT.register(CrystalsChestHighlighter::render);
+ ClientPlayConnectionEvents.JOIN.register((_handler, _sender, _client) -> reset());
+ }
+
+ private static void reset() {
+ waitingForChest = 0;
+ activeChests.clear();
+ activeParticles.clear();
+ currentLockCount = 0;
+ }
+
+ private static void extractLocationFromMessage(Text text, boolean b) {
+ if (!Utils.isInCrystalHollows() || !SkyblockerConfigManager.get().mining.crystalHollows.chestHighlighter) {
+ return;
+ }
+ //if a chest is spawned add chest to look for
+ if (text.getString().matches(CHEST_SPAWN_MESSAGE)) {
+ waitingForChest += 1;
+ }
+ }
+
+ /**
+ * When a block is updated in the crystal hollows if looking for a chest see if it's a chest and if so add to active. or remove active chests from where air is placed
+ *
+ * @param pos location of block update
+ * @param state the new state of the block
+ */
+ public static void onBlockUpdate(BlockPos pos, BlockState state) {
+ if (!SkyblockerConfigManager.get().mining.crystalHollows.chestHighlighter || CLIENT.player == null) {
+ return;
+ }
+ if (waitingForChest > 0 && state.isOf(Blocks.CHEST)) {
+ //make sure it is not too far from the player (more than 10 blocks away)
+ if (pos.getSquaredDistance(CLIENT.player.getPos()) > 100) {
+ return;
+ }
+ activeChests.add(pos);
+ currentLockCount = 0;
+ waitingForChest -= 1;
+ } else if (state.isAir() && activeChests.contains(pos)) {
+ currentLockCount = 0;
+ activeChests.remove(pos);
+ }
+ }
+
+ /**
+ * When a particle is spawned add that particle to active particles if correct for lock picking
+ *
+ * @param packet particle spawn packet
+ */
+ public static void onParticle(ParticleS2CPacket packet) {
+ if (!Utils.isInCrystalHollows() || !SkyblockerConfigManager.get().mining.crystalHollows.chestHighlighter) {
+ return;
+ }
+ if (ParticleTypes.CRIT.equals(packet.getParameters().getType())) {
+ activeParticles.put(new Vec3d(packet.getX(), packet.getY(), packet.getZ()), System.currentTimeMillis());
+ }
+ }
+
+ /**
+ * Updates {@link CrystalsChestHighlighter#currentLockCount} and clears {@link CrystalsChestHighlighter#activeParticles} based on lock pick related sound events.
+ *
+ * @param packet sound packet
+ */
+ public static void onSound(PlaySoundS2CPacket packet) {
+ if (!Utils.isInCrystalHollows() || !SkyblockerConfigManager.get().mining.crystalHollows.chestHighlighter) {
+ return;
+ }
+ String path = packet.getSound().value().getId().getPath();
+ //lock picked sound
+ if (path.equals("entity.experience_orb.pickup") && packet.getPitch() == 1) {
+ currentLockCount += 1;
+ activeParticles.clear();
+ //lock pick fail sound
+ } else if (path.equals("entity.villager.no")) {
+ currentLockCount = 0;
+ activeParticles.clear();
+ //lock pick finish sound
+ } else if (path.equals("block.chest.open")) {
+ //set the needed lock count to the current, so we know how many locks a chest has
+ neededLockCount = currentLockCount;
+ activeParticles.clear();
+ }
+ }
+
+ /**
+ * If enabled, renders a box around active treasure chests, taking the color from the config.
+ * Additionally, calculates and displaces the highlight to indicate lock-picking spots on chests.
+ * Finally, renders text showing how many lock picks the player has done
+ *
+ * @param context context
+ */
+ private static void render(WorldRenderContext context) {
+ if (!Utils.isInCrystalHollows() || !SkyblockerConfigManager.get().mining.crystalHollows.chestHighlighter) {
+ return;
+ }
+ //render chest outline
+ float[] color = SkyblockerConfigManager.get().mining.crystalHollows.chestHighlightColor.getComponents(new float[]{0, 0, 0, 0});
+ for (BlockPos chest : activeChests) {
+ RenderHelper.renderOutline(context, Box.of(chest.toCenterPos().subtract(0, 0.0625, 0), 0.885, 0.885, 0.885), color, color[3], 3, false);
+ }
+
+ //render lock picking if player is looking at chest that is in the active chests list
+ if (CLIENT.player == null) {
+ return;
+ }
+ HitResult target = CLIENT.crosshairTarget;
+ if (target instanceof BlockHitResult blockHitResult && activeChests.contains(blockHitResult.getBlockPos())) {
+ Vec3d chestPos = blockHitResult.getBlockPos().toCenterPos();
+
+ if (!activeParticles.isEmpty()) {
+ //the player is looking at a chest use active particle to highlight correct spot
+ Vec3d highlightSpot = Vec3d.ZERO;
+
+ //if to old remove particle
+ activeParticles.entrySet().removeIf(e -> System.currentTimeMillis() - e.getValue() > MAX_PARTICLE_LIFE_TIME);
+
+ //add up all particle within range of active block
+ for (Vec3d particlePos : activeParticles.keySet()) {
+ if (particlePos.squaredDistanceTo(chestPos) <= 0.75) {
+ highlightSpot = highlightSpot.add(particlePos);
+ }
+ }
+
+ //render the spot
+ highlightSpot = highlightSpot.multiply((double) 1 / activeParticles.size()).subtract(LOCK_HIGHLIGHT_SIZE.multiply(0.5));
+ RenderHelper.renderFilled(context, highlightSpot, LOCK_HIGHLIGHT_SIZE, color, color[3], true);
+ }
+
+ //render total text if needed is more than 0
+ if (neededLockCount <= 0) {
+ return;
+ }
+ RenderHelper.renderText(context, Text.literal(Math.min(currentLockCount, neededLockCount) + "/" + neededLockCount).withColor(SkyblockerConfigManager.get().mining.crystalHollows.chestHighlightColor.getRGB()), chestPos, true);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java b/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java
index 20d8157a..ad5811f1 100644
--- a/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java
+++ b/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java
@@ -119,6 +119,16 @@ public class RenderHelper {
* This does not use renderer since renderer draws outline using debug lines with a fixed width.
*/
public static void renderOutline(WorldRenderContext context, Box box, float[] colorComponents, float lineWidth, boolean throughWalls) {
+ renderOutline(context, box, colorComponents, 1f, lineWidth, throughWalls);
+ }
+
+ /**
+ * Renders the outline of a box with the specified color components and line width.
+ * This does not use renderer since renderer draws outline using debug lines with a fixed width.
+ *
+ * @param alpha the transparency of the lines for the box
+ */
+ public static void renderOutline(WorldRenderContext context, Box box, float[] colorComponents, float alpha, float lineWidth, boolean throughWalls) {
if (FrustumUtils.isVisible(box)) {
MatrixStack matrices = context.matrixStack();
Vec3d camera = context.camera().getPos();
@@ -126,6 +136,7 @@ public class RenderHelper {
RenderSystem.setShader(GameRenderer::getRenderTypeLinesProgram);
RenderSystem.setShaderColor(1f, 1f, 1f, 1f);
+ RenderSystem.enableBlend();
RenderSystem.lineWidth(lineWidth);
RenderSystem.disableCull();
RenderSystem.enableDepthTest();
@@ -135,12 +146,13 @@ public class RenderHelper {
matrices.translate(-camera.getX(), -camera.getY(), -camera.getZ());
BufferBuilder buffer = tessellator.begin(DrawMode.LINES, VertexFormats.LINES);
- WorldRenderer.drawBox(matrices, buffer, box, colorComponents[0], colorComponents[1], colorComponents[2], 1f);
+ WorldRenderer.drawBox(matrices, buffer, box, colorComponents[0], colorComponents[1], colorComponents[2], alpha);
BufferRenderer.drawWithGlobalProgram(buffer.end());
matrices.pop();
RenderSystem.lineWidth(1f);
RenderSystem.enableCull();
+ RenderSystem.disableBlend();
RenderSystem.disableDepthTest();
RenderSystem.depthFunc(GL11.GL_LEQUAL);
}
diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json
index 72b89464..3707bab9 100644
--- a/src/main/resources/assets/skyblocker/lang/en_us.json
+++ b/src/main/resources/assets/skyblocker/lang/en_us.json
@@ -486,6 +486,10 @@
"skyblocker.config.mining.crystalHollows.metalDetectorHelper.@Tooltip": "Helper for the metal detector puzzle in the Mines of Divan.",
"skyblocker.config.mining.crystalHollows.nucleusWaypoints": "Nucleus Waypoints",
"skyblocker.config.mining.crystalHollows.nucleusWaypoints.@Tooltip": "Show waypoints to the Nucleus in the Crystal Hollows.",
+ "skyblocker.config.mining.crystalHollows.chestHighlighter": "Treasure Chest Highlighter",
+ "skyblocker.config.mining.crystalHollows.chestHighlighter.@Tooltip": "Highlight found treasure chests and lock pick locations when powder mining.",
+ "skyblocker.config.mining.crystalHollows.chestHighlighter.color": "Chest Highlight Color",
+ "skyblocker.config.mining.crystalHollows.chestHighlighter.color.@Tooltip": "What color the treasure chests / lock pick should be highlighted.",
"skyblocker.config.mining.crystalsHud": "Crystal Hollows Map",
"skyblocker.config.mining.crystalsHud.enabled": "Enabled",