aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/me/xmrvizzy/skyblocker
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/me/xmrvizzy/skyblocker')
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java69
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java28
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/Room.java87
3 files changed, 156 insertions, 28 deletions
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java
index c9603809..519b365d 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java
@@ -1,5 +1,6 @@
package me.xmrvizzy.skyblocker.skyblock.dungeon.secrets;
+import com.google.gson.JsonObject;
import it.unimi.dsi.fastutil.ints.IntSortedSet;
import net.minecraft.block.MapColor;
import net.minecraft.item.map.MapIcon;
@@ -7,6 +8,7 @@ import net.minecraft.item.map.MapState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
+import net.minecraft.util.math.Vec3i;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.joml.RoundingMode;
@@ -19,6 +21,25 @@ public class DungeonMapUtils {
public static final byte BLACK_COLOR = MapColor.BLACK.getRenderColorByte(MapColor.Brightness.LOWEST);
public static final byte WHITE_COLOR = MapColor.WHITE.getRenderColorByte(MapColor.Brightness.HIGH);
+ public static byte getColor(MapState map, @Nullable Vector2ic pos) {
+ return pos == null ? -1 : getColor(map, pos.x(), pos.y());
+ }
+
+ public static byte getColor(MapState map, int x, int z) {
+ if (x < 0 || z < 0 || x >= 128 || z >= 128) {
+ return -1;
+ }
+ return map.colors[x + (z << 7)];
+ }
+
+ public static boolean isEntranceColor(MapState map, int x, int z) {
+ return getColor(map, x, z) == Room.Type.ENTRANCE.color;
+ }
+
+ public static boolean isEntranceColor(MapState map, @Nullable Vector2ic pos) {
+ return getColor(map, pos) == Room.Type.ENTRANCE.color;
+ }
+
@Nullable
private static Vector2i getMapPlayerPos(MapState map) {
for (MapIcon icon : map.getIcons()) {
@@ -32,15 +53,16 @@ public class DungeonMapUtils {
@Nullable
public static Vector2ic getMapEntrancePos(MapState map) {
Vector2i mapPos = getMapPlayerPos(map);
- if (!isEntranceColor(getColor(map, mapPos))) {
+ DungeonSecrets.LOGGER.info("[Skyblocker] Trying to get dungeon map entrance pos from map player pos at {}", mapPos); // TODO remove
+ if (!isEntranceColor(map, mapPos)) {
return null;
}
// noinspection StatementWithEmptyBody, DataFlowIssue
- while (isEntranceColor(getColor(map, mapPos.sub(1, 0)))) {
+ while (isEntranceColor(map, mapPos.sub(1, 0))) {
}
mapPos.add(1, 0);
//noinspection StatementWithEmptyBody
- while (isEntranceColor(getColor(map, mapPos.sub(0, 1)))) {
+ while (isEntranceColor(map, mapPos.sub(0, 1))) {
}
return mapPos.add(0, 1);
}
@@ -48,7 +70,7 @@ public class DungeonMapUtils {
public static int getMapRoomSize(MapState map, Vector2ic mapEntrancePos) {
int i = -1;
//noinspection StatementWithEmptyBody
- while (isEntranceColor(getColor(map, mapEntrancePos.x() + ++i, mapEntrancePos.y()))) {
+ while (isEntranceColor(map, mapEntrancePos.x() + ++i, mapEntrancePos.y())) {
}
return i;
}
@@ -91,7 +113,7 @@ public class DungeonMapUtils {
@Nullable
public static Vector2ic getPhysicalEntrancePos(MapState map, @NotNull Vec3d playerPos) {
- if (isEntranceColor(getColor(map, getMapPlayerPos(map)))) {
+ if (isEntranceColor(map, getMapPlayerPos(map))) {
return getPhysicalRoomPos(playerPos);
}
return null;
@@ -112,6 +134,15 @@ public class DungeonMapUtils {
return physicalPos.sub(MathHelper.floorMod(physicalPos.x(), 32), MathHelper.floorMod(physicalPos.y(), 32)).sub(8, 8);
}
+ /**
+ * @see #getPhysicalRoomPos(Vec3d)
+ */
+ @NotNull
+ public static Vector2ic getPhysicalRoomPos(@NotNull Vec3i playerPos) {
+ Vector2i physicalPos = new Vector2i(playerPos.getX() + 8.5, playerPos.getZ() + 8.5, RoundingMode.TRUNCATE);
+ return physicalPos.sub(MathHelper.floorMod(physicalPos.x(), 32), MathHelper.floorMod(physicalPos.y(), 32)).sub(8, 8);
+ }
+
public static Vector2ic[] getPhysicalPosFromMap(Vector2ic mapEntrancePos, int mapRoomSize, Vector2ic physicalEntrancePos, Vector2ic... mapPositions) {
for (int i = 0; i < mapPositions.length; i++) {
mapPositions[i] = getPhysicalPosFromMap(mapEntrancePos, mapRoomSize, physicalEntrancePos, mapPositions[i]);
@@ -150,6 +181,19 @@ public class DungeonMapUtils {
};
}
+ public static BlockPos relativeToActual(Vector2ic physicalCornerPos, Room.Direction direction, JsonObject posJson) {
+ return relativeToActual(physicalCornerPos, direction, new BlockPos(posJson.get("x").getAsInt(), posJson.get("y").getAsInt(), posJson.get("z").getAsInt()));
+ }
+
+ public static BlockPos relativeToActual(Vector2ic physicalCornerPos, Room.Direction direction, BlockPos pos) {
+ return switch (direction) {
+ case NW -> new BlockPos(pos.getX() + physicalCornerPos.x(), pos.getY(), pos.getZ() + physicalCornerPos.y());
+ case NE -> new BlockPos(-pos.getZ() + physicalCornerPos.x(), pos.getY(), pos.getX() + physicalCornerPos.y());
+ case SW -> new BlockPos(pos.getZ() + physicalCornerPos.x(), pos.getY(), -pos.getX() + physicalCornerPos.y());
+ case SE -> new BlockPos(-pos.getX() + physicalCornerPos.x(), pos.getY(), -pos.getZ() + physicalCornerPos.y());
+ };
+ }
+
public static Room.Type getRoomType(MapState map, Vector2ic mapPos) {
return switch (getColor(map, mapPos)) {
case 30 -> Room.Type.ENTRANCE;
@@ -195,19 +239,4 @@ public class DungeonMapUtils {
DungeonSecrets.LOGGER.debug("[Skyblocker] Found dungeon room segments: {}", Arrays.toString(segments.toArray()));
return segments.toArray(Vector2ic[]::new);
}
-
- public static byte getColor(MapState map, @Nullable Vector2ic pos) {
- return pos == null ? -1 : getColor(map, pos.x(), pos.y());
- }
-
- public static byte getColor(MapState map, int x, int z) {
- if (x < 0 || z < 0 || x >= 128 || z >= 128) {
- return -1;
- }
- return map.colors[x + (z << 7)];
- }
-
- public static boolean isEntranceColor(byte color) {
- return color == Room.Type.ENTRANCE.color;
- }
}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java
index bcc26f78..03aa0ca7 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java
@@ -6,6 +6,8 @@ import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap;
import me.xmrvizzy.skyblocker.SkyblockerMod;
import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
import me.xmrvizzy.skyblocker.utils.Utils;
+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.client.network.ClientPlayerEntity;
import net.minecraft.item.FilledMapItem;
@@ -79,7 +81,7 @@ public class DungeonSecrets {
*/
private static Vector2ic mapEntrancePos;
/**
- * The width of a room on the map.
+ * The size of a room on the map.
*/
private static int mapRoomSize;
/**
@@ -93,6 +95,14 @@ public class DungeonSecrets {
return roomsLoaded != null && roomsLoaded.isDone();
}
+ public static JsonObject getRoomsJson() {
+ return roomsJson;
+ }
+
+ public static JsonObject getWaypointsJson() {
+ return waypointsJson;
+ }
+
/**
* Loads the dungeon secrets asynchronously from {@code /assets/skyblocker/dungeons}.
* Use {@link #isRoomsLoaded()} to check for completion of loading.
@@ -103,6 +113,7 @@ public class DungeonSecrets {
}
CompletableFuture.runAsync(DungeonSecrets::load);
SkyblockerMod.getInstance().scheduler.scheduleCyclic(DungeonSecrets::update, 10);
+ WorldRenderEvents.AFTER_TRANSLUCENT.register(DungeonSecrets::render);
}
private static void load() {
@@ -174,6 +185,7 @@ public class DungeonSecrets {
}
private static void update() {
+ long startTime = System.currentTimeMillis();
if (!SkyblockerConfig.get().locations.dungeons.secretWaypoints || !Utils.isInDungeons()) {
return;
}
@@ -203,7 +215,7 @@ public class DungeonSecrets {
return;
} else {
currentRoom = newRoom(Room.Type.ENTRANCE, physicalEntrancePos);
- LOGGER.info("[Skyblocker] Started dungeon with map room width {}, map entrance pos {}, player pos {}, and physical entrance pos {}", mapRoomSize, mapEntrancePos, client.player.getPos(), physicalEntrancePos);
+ LOGGER.info("[Skyblocker] Started dungeon with map room size {}, map entrance pos {}, player pos {}, and physical entrance pos {}", mapRoomSize, mapEntrancePos, client.player.getPos(), physicalEntrancePos);
}
}
@@ -217,13 +229,16 @@ public class DungeonSecrets {
if (room == null) {
switch (type) {
case ENTRANCE, PUZZLE, TRAP, MINIBOSS, FAIRY, BLOOD -> room = newRoom(type, physicalPos);
- case ROOM -> room = newRoom(type, DungeonMapUtils.getPhysicalPosFromMap(mapEntrancePos, mapRoomSize, physicalEntrancePos, DungeonMapUtils.getRoomSegments(map, mapPos, mapRoomSize, type.color)));
+ case ROOM ->
+ room = newRoom(type, DungeonMapUtils.getPhysicalPosFromMap(mapEntrancePos, mapRoomSize, physicalEntrancePos, DungeonMapUtils.getRoomSegments(map, mapPos, mapRoomSize, type.color)));
}
}
if (room != null && currentRoom != room) {
currentRoom = room;
}
currentRoom.update();
+ long endTime = System.currentTimeMillis();
+ LOGGER.debug("[Skyblocker] Updated dungeon secrets in {} ms", endTime - startTime); // TODO change to debug
}
/**
@@ -240,4 +255,11 @@ public class DungeonSecrets {
}
return newRoom;
}
+
+ private static void render(WorldRenderContext context) {
+ if (!SkyblockerConfig.get().locations.dungeons.secretWaypoints || !Utils.isInDungeons() || currentRoom.getName() == null) {
+ return;
+ }
+ currentRoom.render(context);
+ }
}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/Room.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/Room.java
index 6eabc027..d722d563 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/Room.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/Room.java
@@ -1,14 +1,19 @@
package me.xmrvizzy.skyblocker.skyblock.dungeon.secrets;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
import it.unimi.dsi.fastutil.ints.IntRBTreeSet;
import it.unimi.dsi.fastutil.ints.IntSortedSet;
import it.unimi.dsi.fastutil.ints.IntSortedSets;
+import me.xmrvizzy.skyblocker.utils.RenderHelper;
+import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import net.minecraft.block.MapColor;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.registry.Registries;
import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.MathHelper;
import org.apache.commons.lang3.tuple.MutableTriple;
import org.apache.commons.lang3.tuple.Triple;
import org.joml.Vector2i;
@@ -29,8 +34,10 @@ public class Room {
private String name;
private Direction direction;
private Vector2ic corner;
+ private final List<Secret> secrets = new ArrayList<>();
public Room(Type type, Vector2ic... physicalPositions) {
+ long startTime = System.currentTimeMillis();
this.type = type;
segments = Set.of(physicalPositions);
IntSortedSet segmentsX = IntSortedSets.unmodifiable(new IntRBTreeSet(segments.stream().mapToInt(Vector2ic::x).toArray()));
@@ -41,13 +48,18 @@ public class Room {
for (Direction direction : getPossibleDirections(segmentsX, segmentsY)) {
possibleRooms.add(MutableTriple.of(direction, DungeonMapUtils.getPhysicalCornerPos(direction, segmentsX, segmentsY), possibleDirectionRooms));
}
- DungeonSecrets.LOGGER.info("Created {}", this); // TODO change to debug
+ long endTime = System.currentTimeMillis();
+ DungeonSecrets.LOGGER.info("Created {} in {} ms", this, endTime - startTime); // TODO change to debug
}
public Type getType() {
return type;
}
+ public String getName() {
+ return name;
+ }
+
@Override
public String toString() {
return "Room{type=" + type + ", shape=" + shape + ", name='" + name + "', direction=" + direction + ", corner=" + corner + ", segments=" + Arrays.toString(segments.toArray()) + "}";
@@ -116,7 +128,8 @@ public class Room {
findRoom = CompletableFuture.runAsync(() -> {
long startTime = System.currentTimeMillis();
for (BlockPos pos : BlockPos.iterate(player.getBlockPos().add(-5, -5, -5), player.getBlockPos().add(5, 5, 5))) {
- if (checkedBlocks.add(pos) && checkBlock(world, pos)) {
+ // TODO Check if pos is outside of room or part of doorway
+ if (segments.contains(DungeonMapUtils.getPhysicalRoomPos(pos)) && notInDoorway(pos) && checkedBlocks.add(pos) && checkBlock(world, pos)) {
reset();
break;
}
@@ -126,6 +139,15 @@ public class Room {
});
}
+ public static boolean notInDoorway(BlockPos pos) {
+ if (pos.getY() < 66 || pos.getY() > 73) {
+ return true;
+ }
+ int x = MathHelper.floorMod(pos.getX() - 8, 32);
+ int z = MathHelper.floorMod(pos.getZ() - 8, 32);
+ return x >= 13 && x <= 17 && (z <= 2 || z >= 28) || z >= 13 && z <= 17 && (x <= 2 || x >= 28);
+ }
+
private boolean checkBlock(ClientWorld world, BlockPos pos) {
byte id = DungeonSecrets.NUMERIC_ID.getByte(Registries.BLOCK.getId(world.getBlockState(pos).getBlock()).toString());
if (id == 0) {
@@ -152,9 +174,8 @@ public class Room {
} else if (matchingRoomsSize == 1) {
for (Triple<Direction, Vector2ic, List<String>> directionRooms : possibleRooms) {
if (directionRooms.getRight().size() == 1) {
- name = directionRooms.getRight().get(0);
- direction = directionRooms.getLeft();
- corner = directionRooms.getMiddle();
+ roomMatched(directionRooms);
+ break;
}
}
DungeonSecrets.LOGGER.info("[Skyblocker] Room {} matched after checking {} block(s)", name, checkedBlocks.size()); // TODO change to debug
@@ -169,6 +190,41 @@ public class Room {
return pos.getX() << 24 | pos.getY() << 16 | pos.getZ() << 8 | id;
}
+ private void roomMatched(Triple<Direction, Vector2ic, List<String>> directionRooms) {
+ name = directionRooms.getRight().get(0);
+ direction = directionRooms.getLeft();
+ corner = directionRooms.getMiddle();
+ for (JsonElement waypointElement : DungeonSecrets.getWaypointsJson().get(name).getAsJsonArray()) {
+ JsonObject waypoint = waypointElement.getAsJsonObject();
+ String name = waypoint.get("secretName").getAsString();
+ int index = Integer.parseInt(Character.isDigit(name.charAt(1)) ? name.substring(0, 2) : name.substring(0, 1));
+ secrets.add(new Secret(index, getCategory(waypoint), DungeonMapUtils.relativeToActual(corner, direction, waypoint), true));
+ }
+ }
+
+ private Category getCategory(JsonObject categoryJson) {
+ return switch (categoryJson.get("category").getAsString()) {
+ case "entrance" -> Category.ENTRANCE;
+ case "superboom" -> Category.SUPERBOOM;
+ case "chest" -> Category.CHEST;
+ case "item" -> Category.ITEM;
+ case "bat" -> Category.BAT;
+ case "wither" -> Category.WITHER;
+ case "lever" -> Category.LEVER;
+ case "fairysoul" -> Category.FAIRYSOUL;
+ case "stonk" -> Category.STONK;
+ default -> Category.DEFAULT;
+ };
+ }
+
+ protected void render(WorldRenderContext context) {
+ for (Secret secret : secrets) {
+ if (secret.missing()) {
+ RenderHelper.renderFilledThroughWallsWithBeaconBeam(context, secret.pos, secret.category.colorComponents, 0.5F);
+ }
+ }
+ }
+
/**
* Resets fields after room matching completes, where either a room is found or none matched.
* These fields are no longer needed and are discarded to save memory.
@@ -217,4 +273,25 @@ public class Room {
public enum Direction {
NW, NE, SW, SE
}
+
+ public record Secret(int index, Category category, BlockPos pos, boolean missing) {
+ }
+
+ public enum Category {
+ ENTRANCE(0, 255, 0),
+ SUPERBOOM(255, 0, 0),
+ CHEST(2, 213, 250),
+ ITEM(2, 64, 250),
+ BAT(142, 66, 0),
+ WITHER(30, 30, 30),
+ LEVER(250, 217, 2),
+ FAIRYSOUL(255, 85, 255),
+ STONK(146, 52, 235),
+ DEFAULT(190, 255, 252);
+ final float[] colorComponents;
+
+ Category(float... colorComponents) {
+ this.colorComponents = colorComponents;
+ }
+ }
}