aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/de/hysky/skyblocker/skyblock
diff options
context:
space:
mode:
authorKevin <92656833+kevinthegreat1@users.noreply.github.com>2023-11-24 12:01:03 -0800
committerGitHub <noreply@github.com>2023-11-24 15:01:03 -0500
commit6eb95596a26c0dc7275690b0300cf42944d69ac2 (patch)
tree25ccd94f90e843d4f646b69a9ef7e1e8a8a27a08 /src/main/java/de/hysky/skyblocker/skyblock
parentea8f0b1488a79befeb5e82382f84b39b1aac9aae (diff)
downloadSkyblocker-6eb95596a26c0dc7275690b0300cf42944d69ac2.tar.gz
Skyblocker-6eb95596a26c0dc7275690b0300cf42944d69ac2.tar.bz2
Skyblocker-6eb95596a26c0dc7275690b0300cf42944d69ac2.zip
Add Wither & Blood Door Highlight (#429)
Diffstat (limited to 'src/main/java/de/hysky/skyblocker/skyblock')
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java25
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java47
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java63
3 files changed, 123 insertions, 12 deletions
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java
index 73d4a452..01f2c9fc 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java
@@ -3,12 +3,15 @@ package de.hysky.skyblocker.skyblock.dungeon.secrets;
import com.google.gson.JsonObject;
import it.unimi.dsi.fastutil.ints.IntSortedSet;
import it.unimi.dsi.fastutil.objects.ObjectIntPair;
+import net.minecraft.block.BlockState;
+import net.minecraft.block.Blocks;
import net.minecraft.block.MapColor;
import net.minecraft.item.map.MapIcon;
import net.minecraft.item.map.MapState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3i;
+import net.minecraft.world.World;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.joml.RoundingMode;
@@ -271,4 +274,26 @@ public class DungeonMapUtils {
DungeonSecrets.LOGGER.debug("[Skyblocker] Found dungeon room segments: {}", Arrays.toString(segments.toArray()));
return segments.toArray(Vector2ic[]::new);
}
+
+ public static BlockPos getWitherBloodDoorPos(World world, Collection<Vector2ic> physicalPositions) {
+ BlockPos.Mutable doorPos = new BlockPos.Mutable();
+ for (Vector2ic pos : physicalPositions) {
+ if (hasWitherOrBloodDoor(world, pos, doorPos)) {
+ return doorPos;
+ }
+ }
+ return null;
+ }
+
+ private static boolean hasWitherOrBloodDoor(World world, Vector2ic pos, BlockPos.Mutable doorPos) {
+ return isWitherOrBloodDoor(world, doorPos.set(pos.x() - 2, 69, pos.y() + 14)) ||
+ isWitherOrBloodDoor(world, doorPos.set(pos.x() + 14, 69, pos.y() - 2)) ||
+ isWitherOrBloodDoor(world, doorPos.set(pos.x() + 14, 69, pos.y() + 30)) ||
+ isWitherOrBloodDoor(world, doorPos.set(pos.x() + 30, 69, pos.y() + 14));
+ }
+
+ private static boolean isWitherOrBloodDoor(World world, BlockPos pos) {
+ BlockState state = world.getBlockState(pos);
+ return state.isOf(Blocks.COAL_BLOCK) || state.isOf(Blocks.RED_TERRACOTTA);
+ }
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java
index ee517eb8..7f401fdb 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java
@@ -32,6 +32,7 @@ import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.command.argument.BlockPosArgumentType;
import net.minecraft.command.argument.PosArgument;
import net.minecraft.command.argument.TextArgumentType;
+import net.minecraft.entity.Entity;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.AmbientEntity;
@@ -66,6 +67,8 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import java.util.stream.Stream;
import java.util.zip.InflaterInputStream;
@@ -76,6 +79,7 @@ public class DungeonSecrets {
protected static final Logger LOGGER = LoggerFactory.getLogger(DungeonSecrets.class);
private static final String DUNGEONS_PATH = "dungeons";
private static final Path CUSTOM_WAYPOINTS_DIR = SkyblockerMod.CONFIG_DIR.resolve("custom_secret_waypoints.json");
+ private static final Pattern KEY_FOUND = Pattern.compile("^(?:\\[.+] )?(?<name>\\w+) has obtained (?<type>Wither|Blood) Key!$");
/**
* Maps the block identifier string to a custom numeric block id used in dungeon rooms data.
*
@@ -500,25 +504,60 @@ public class DungeonSecrets {
}
/**
- * Renders the secret waypoints in {@link #currentRoom} if {@link #isCurrentRoomMatched()}.
+ * Renders the secret waypoints in {@link #currentRoom} if {@link #shouldProcess()} and {@link #currentRoom} is not null.
*/
private static void render(WorldRenderContext context) {
- if (isCurrentRoomMatched()) {
+ if (shouldProcess() && currentRoom != null) {
currentRoom.render(context);
}
}
/**
- * Calls {@link Room#onChatMessage(String)} on {@link #currentRoom} if the message is an overlay message and {@link #isCurrentRoomMatched()}.
- * Used to detect when all secrets in a room are found.
+ * Calls {@link Room#onChatMessage(String)} on {@link #currentRoom} if the message is an overlay message and {@link #isCurrentRoomMatched()} and processes key obtained messages.
+ * <p>Used to detect when all secrets in a room are found and detect when a wither or blood door is unlocked.
+ * To process key obtained messages, this method checks if door highlight is enabled and if the message matches a key obtained message.
+ * Then, it calls {@link Room#keyFound()} on {@link #currentRoom} if the client's player is the one who obtained the key.
+ * Otherwise, it calls {@link Room#keyFound()} on the room the player who obtained the key is in.
*/
private static void onChatMessage(Text text, boolean overlay) {
+ if (!shouldProcess()) {
+ return;
+ }
+
String message = text.getString();
if (overlay && isCurrentRoomMatched()) {
currentRoom.onChatMessage(message);
}
+ // Process key found messages for door highlight
+ if (SkyblockerConfigManager.get().locations.dungeons.doorHighlight.enableDoorHighlight) {
+ Matcher matcher = KEY_FOUND.matcher(message);
+ if (matcher.matches()) {
+ String name = matcher.group("name");
+ MinecraftClient client = MinecraftClient.getInstance();
+ if (client.player != null && client.player.getGameProfile().getName().equals(name)) {
+ if (currentRoom != null) {
+ currentRoom.keyFound();
+ } else {
+ LOGGER.warn("[Skyblocker Dungeon Door] The current room at the current player {} does not exist", name);
+ }
+ } else if (client.world != null) {
+ Optional<Vec3d> posOptional = client.world.getPlayers().stream().filter(player -> player.getGameProfile().getName().equals(name)).findAny().map(Entity::getPos);
+ if (posOptional.isPresent()) {
+ Room room = getRoomAtPhysical(posOptional.get());
+ if (room != null) {
+ room.keyFound();
+ } else {
+ LOGGER.warn("[Skyblocker Dungeon Door] Failed to find room at player {} with position {}", name, posOptional.get());
+ }
+ } else {
+ LOGGER.warn("[Skyblocker Dungeon Door] Failed to find player {}", name);
+ }
+ }
+ }
+ }
+
if (message.equals("[BOSS] Bonzo: Gratz for making it this far, but I'm basically unbeatable.") || message.equals("[BOSS] Scarf: This is where the journey ends for you, Adventurers.")
|| message.equals("[BOSS] The Professor: I was burdened with terrible news recently...") || message.equals("[BOSS] Thorn: Welcome Adventurers! I am Thorn, the Spirit! And host of the Vegan Trials!")
|| message.equals("[BOSS] Livid: Welcome, you've arrived right on time. I am Livid, the Master of Shadows.") || message.equals("[BOSS] Sadan: So you made it all the way here... Now you wish to defy me? Sadan?!")
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java
index 9b95f146..7797513f 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/Room.java
@@ -6,7 +6,9 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.context.CommandContext;
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.utils.Constants;
+import de.hysky.skyblocker.utils.render.RenderHelper;
import de.hysky.skyblocker.utils.scheduler.Scheduler;
import it.unimi.dsi.fastutil.ints.IntRBTreeSet;
import it.unimi.dsi.fastutil.ints.IntSortedSet;
@@ -27,6 +29,8 @@ import net.minecraft.registry.Registries;
import net.minecraft.text.Text;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Box;
+import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import org.apache.commons.lang3.tuple.MutableTriple;
import org.apache.commons.lang3.tuple.Triple;
@@ -43,10 +47,14 @@ import java.util.regex.Pattern;
public class Room {
private static final Pattern SECRET_INDEX = Pattern.compile("^(\\d+)");
private static final Pattern SECRETS = Pattern.compile("ยง7(\\d{1,2})/(\\d{1,2}) Secrets");
+ private static final Vec3d DOOR_SIZE = new Vec3d(3, 4, 3);
+ private static final float[] RED_COLOR_COMPONENTS = {1, 0, 0};
+ private static final float[] GREEN_COLOR_COMPONENTS = {0, 1, 0};
@NotNull
private final Type type;
@NotNull
private final Set<Vector2ic> segments;
+
/**
* The shape of the room. See {@link #getShape(IntSortedSet, IntSortedSet)}.
*/
@@ -82,6 +90,12 @@ public class Room {
private Direction direction;
private Vector2ic physicalCornerPos;
+ @Nullable
+ private BlockPos doorPos;
+ @Nullable
+ private Box doorBox;
+ private boolean keyFound;
+
public Room(@NotNull Type type, @NotNull Vector2ic... physicalPositions) {
this.type = type;
segments = Set.of(physicalPositions);
@@ -238,7 +252,8 @@ public class Room {
/**
* Updates the room.
* <p></p>
- * This method returns immediately if any of the following conditions are met:
+ * First, this method tries to find a wither door and blood door.
+ * Then, this method returns immediately if any of the following conditions are met:
* <ul>
* <li> The room does not need to be scanned and matched. (When the room is not of type {@link Type.ROOM}, {@link Type.PUZZLE}, or {@link Type.TRAP}. See {@link Type#needsScanning()}) </li>
* <li> The room has been matched or failed to match and is on cooldown. See {@link #matchState}. </li>
@@ -254,14 +269,27 @@ public class Room {
*/
@SuppressWarnings("JavadocReference")
protected void update() {
+ MinecraftClient client = MinecraftClient.getInstance();
+ ClientWorld world = client.world;
+ if (world == null) {
+ return;
+ }
+
+ // Wither and blood door
+ if (SkyblockerConfigManager.get().locations.dungeons.doorHighlight.enableDoorHighlight && doorPos == null) {
+ doorPos = DungeonMapUtils.getWitherBloodDoorPos(world, segments);
+ if (doorPos != null) {
+ doorBox = new Box(doorPos.getX(), doorPos.getY(), doorPos.getZ(), doorPos.getX() + DOOR_SIZE.getX(), doorPos.getY() + DOOR_SIZE.getY(), doorPos.getZ() + DOOR_SIZE.getZ());
+ }
+ }
+
+ // Room scanning and matching
// Logical AND has higher precedence than logical OR
if (!type.needsScanning() || matchState != MatchState.MATCHING && matchState != MatchState.DOUBLE_CHECKING || !DungeonSecrets.isRoomsLoaded() || findRoom != null && !findRoom.isDone()) {
return;
}
- MinecraftClient client = MinecraftClient.getInstance();
ClientPlayerEntity player = client.player;
- ClientWorld world = client.world;
- if (player == null || world == null) {
+ if (player == null) {
return;
}
findRoom = CompletableFuture.runAsync(() -> {
@@ -451,14 +479,29 @@ public class Room {
}
/**
- * Calls {@link SecretWaypoint#render(WorldRenderContext)} on {@link #secretWaypoints all secret waypoints}.
+ * Calls {@link SecretWaypoint#render(WorldRenderContext)} on {@link #secretWaypoints all secret waypoints} and renders a highlight around the wither or blood door, if it exists.
*/
protected void render(WorldRenderContext context) {
- for (SecretWaypoint secretWaypoint : secretWaypoints.values()) {
- if (secretWaypoint.shouldRender()) {
- secretWaypoint.render(context);
+ if (isMatched()) {
+ for (SecretWaypoint secretWaypoint : secretWaypoints.values()) {
+ if (secretWaypoint.shouldRender()) {
+ secretWaypoint.render(context);
+ }
}
}
+
+ if (!SkyblockerConfigManager.get().locations.dungeons.doorHighlight.enableDoorHighlight || doorPos == null) {
+ return;
+ }
+ float[] colorComponents = keyFound ? GREEN_COLOR_COMPONENTS : RED_COLOR_COMPONENTS;
+ switch (SkyblockerConfigManager.get().locations.dungeons.doorHighlight.doorHighlightType) {
+ case HIGHLIGHT -> RenderHelper.renderFilled(context, doorPos, DOOR_SIZE, colorComponents, 0.5f, true);
+ case OUTLINED_HIGHLIGHT -> {
+ RenderHelper.renderFilled(context, doorPos, DOOR_SIZE, colorComponents, 0.5f, true);
+ RenderHelper.renderOutline(context, doorBox, colorComponents, 5, true);
+ }
+ case OUTLINE -> RenderHelper.renderOutline(context, doorBox, colorComponents, 5, true);
+ }
}
/**
@@ -550,6 +593,10 @@ public class Room {
}
}
+ protected void keyFound() {
+ keyFound = true;
+ }
+
public enum Type {
ENTRANCE(MapColor.DARK_GREEN.getRenderColorByte(MapColor.Brightness.HIGH)),
ROOM(MapColor.ORANGE.getRenderColorByte(MapColor.Brightness.LOWEST)),