aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/me/xmrvizzy/skyblocker/skyblock
diff options
context:
space:
mode:
authorKevinthegreat <92656833+kevinthegreat1@users.noreply.github.com>2023-07-16 16:13:22 +0800
committerKevinthegreat <92656833+kevinthegreat1@users.noreply.github.com>2023-08-30 22:49:52 -0400
commit58616218d5d0c5359bdc1d84f226a0a1b08a71b2 (patch)
tree2ab2428483b7c2a43b2a500317e91524523bb09b /src/main/java/me/xmrvizzy/skyblocker/skyblock
parentdde565cd0fd822386fd4a6fe0663a65c3c6c629b (diff)
downloadSkyblocker-58616218d5d0c5359bdc1d84f226a0a1b08a71b2.tar.gz
Skyblocker-58616218d5d0c5359bdc1d84f226a0a1b08a71b2.tar.bz2
Skyblocker-58616218d5d0c5359bdc1d84f226a0a1b08a71b2.zip
Add room position utils and physical room position parsing
Diffstat (limited to 'src/main/java/me/xmrvizzy/skyblocker/skyblock')
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java129
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java18
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/Room.java27
3 files changed, 147 insertions, 27 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 9d1c7ccb..4ce9be06 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
@@ -3,50 +3,135 @@ package me.xmrvizzy.skyblocker.skyblock.dungeon.secrets;
import net.minecraft.block.MapColor;
import net.minecraft.item.map.MapIcon;
import net.minecraft.item.map.MapState;
+import net.minecraft.util.math.MathHelper;
+import net.minecraft.util.math.Vec3d;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.joml.RoundingMode;
import org.joml.Vector2i;
+import org.joml.Vector2ic;
public class DungeonMapUtils {
- public static final byte ENTRANCE_COLOR = MapColor.DARK_GREEN.getRenderColorByte(MapColor.Brightness.HIGH);
- public static final byte ROOM_COLOR = MapColor.ORANGE.getRenderColorByte(MapColor.Brightness.LOWEST);
- public static final byte PUZZLE_COLOR = MapColor.MAGENTA.getRenderColorByte(MapColor.Brightness.HIGH);
- public static final byte MINIBOSS_COLOR = MapColor.YELLOW.getRenderColorByte(MapColor.Brightness.HIGH);
- public static final byte FAIRY_COLOR = MapColor.PINK.getRenderColorByte(MapColor.Brightness.HIGH);
- public static final byte BLOOD_COLOR = MapColor.BRIGHT_RED.getRenderColorByte(MapColor.Brightness.HIGH);
- public static final byte UNKNOWN_COLOR = MapColor.GRAY.getRenderColorByte(MapColor.Brightness.NORMAL);
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 Vector2i getEntrancePos(MapState map) {
+ @Nullable
+ private static Vector2i getMapPlayerPos(MapState map) {
for (MapIcon icon : map.getIcons()) {
if (icon.getType() == MapIcon.Type.FRAME) {
- int x = (icon.getX() >> 1) + 64;
- int z = (icon.getZ() >> 1) + 64;
- if (getColor(map, x, z) == ENTRANCE_COLOR) {
- while (getColor(map, x - 1, z) == ENTRANCE_COLOR) {
- x--;
- }
- while (getColor(map, x, z - 1) == ENTRANCE_COLOR) {
- z--;
- }
- return new Vector2i(x, z);
- }
+ return new Vector2i((icon.getX() >> 1) + 64, (icon.getZ() >> 1) + 64);
}
}
return null;
}
- public static int getRoomWidth(MapState map, Vector2i entrancePos) {
+ @Nullable
+ public static Vector2ic getMapEntrancePos(MapState map) {
+ Vector2i mapPos = getMapPlayerPos(map);
+ if (!isEntranceColor(getColor(map, mapPos))) {
+ return null;
+ }
+ // noinspection StatementWithEmptyBody, DataFlowIssue
+ while (isEntranceColor(getColor(map, mapPos.sub(1, 0)))) {
+ }
+ //noinspection StatementWithEmptyBody
+ while (isEntranceColor(getColor(map, mapPos.sub(0, 1)))) {
+ }
+ return mapPos;
+ }
+
+ public static int getMapRoomWidth(MapState map, Vector2ic entrancePos) {
int i = 0;
- while (getColor(map, entrancePos.x + i, entrancePos.y) == ENTRANCE_COLOR) {
- i++;
+ //noinspection StatementWithEmptyBody
+ while (isEntranceColor(getColor(map, entrancePos.x() + i++, entrancePos.y()))) {
}
return i;
}
+ /**
+ * Gets the map position of the top left corner of the room the player is in.
+ *
+ * @param map the map
+ * @param entrancePos the map position of the top left corner of the entrance
+ * @param mapRoomWidth the width of a room on the map
+ * @return the map position of the top left corner of the room the player is in
+ * @implNote {@code mapPos} is shifted by 2 so room borders are evenly split.
+ * {@code mapPos} is then shifted by {@code offset} to align the top left most room at (0, 0)
+ * so subtracting the modulo will give the top left corner of the room shifted by {@code offset}.
+ * Finally, {@code mapPos} is shifted back by {@code offset} to its intended position.
+ */
+ @Nullable
+ public static Vector2ic getMapRoomPos(MapState map, Vector2ic entrancePos, int mapRoomWidth) {
+ int mapRoomWidthWithGap = mapRoomWidth + 4;
+ Vector2i mapPos = getMapPlayerPos(map);
+ if (mapPos == null) {
+ return null;
+ }
+ Vector2ic offset = new Vector2i(entrancePos.x() % mapRoomWidthWithGap, entrancePos.y() % mapRoomWidthWithGap);
+ return mapPos.add(2, 2).sub(offset).sub(mapPos.x() % mapRoomWidthWithGap, mapPos.y() % mapRoomWidthWithGap).add(offset);
+ }
+
+ /**
+ * Gets the map position of the top left corner of the room corresponding to the physical position of the northwest corner of a room.
+ *
+ * @param physicalEntrancePos the physical position of the northwest corner of the entrance room
+ * @param mapEntrancePos the map position of the top left corner of the entrance room
+ * @param mapRoomWidth the width of a room on the map
+ * @param physicalPos the physical position of the northwest corner of the room
+ * @return the map position of the top left corner of the room corresponding to the physical position of the northwest corner of a room
+ */
+ public static Vector2ic getMapPosFromPhysical(Vector2ic physicalEntrancePos, Vector2ic mapEntrancePos, int mapRoomWidth, Vector2ic physicalPos) {
+ return new Vector2i(physicalPos).sub(physicalEntrancePos).div(32).mul(mapRoomWidth + 4).add(mapEntrancePos);
+ }
+
+ @Nullable
+ public static Vector2ic getPhysicalEntrancePos(MapState map, @NotNull Vec3d playerPos) {
+ if (isEntranceColor(getColor(map, getMapPlayerPos(map)))) {
+ return getPhysicalRoomPos(playerPos);
+ }
+ return null;
+ }
+
+ /**
+ * Gets the physical position of the northwest corner of the room the player is in. Hypixel Skyblock Dungeons are aligned to a 32 by 32 blocks grid, allowing corners to be calculated through math.
+ *
+ * @param playerPos the position of the player
+ * @return the physical position of the northwest corner of the room the player is in
+ * @implNote {@code physicalPos} is shifted by 0.5 so room borders are evenly split.
+ * {@code physicalPos} is further shifted by 8 because Hypixel offset dungeons by 8 blocks in Skyblock 0.12.3.
+ * Subtracting the modulo gives the northwest corner of the room shifted by 8. Finally, {@code physicalPos} is shifted back by 8 to its intended position.
+ */
+ @NotNull
+ public static Vector2ic getPhysicalRoomPos(@NotNull Vec3d 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);
+ }
+
+ /**
+ * Gets the physical position of the northwest corner of the room corresponding to the map position of the top left corner of a room.
+ *
+ * @param mapEntrancePos the map position of the top left corner of the entrance room
+ * @param mapRoomWidth the width of a room on the map
+ * @param physicalEntrancePos the physical position of the northwest corner of the entrance room
+ * @param mapPos the map position of the top left corner of the room
+ * @return the physical position of the northwest corner of the room corresponding to the map position of the top left corner of a room
+ */
+ public static Vector2ic getPhysicalPosFromMap(Vector2ic mapEntrancePos, int mapRoomWidth, Vector2ic physicalEntrancePos, Vector2ic mapPos) {
+ return new Vector2i(mapPos).sub(mapEntrancePos).div(mapRoomWidth + 4).mul(32).add(physicalEntrancePos);
+ }
+
+ private static byte getColor(MapState map, @Nullable Vector2ic pos) {
+ return pos == null ? -1 : getColor(map, pos.x(), pos.y());
+ }
+
private 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)];
}
+
+ private static boolean isEntranceColor(byte color) {
+ return color == Room.RoomType.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 17446db7..01274ae4 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
@@ -9,9 +9,10 @@ import net.minecraft.item.FilledMapItem;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.item.map.MapState;
+import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
-import org.joml.Vector2i;
+import org.joml.Vector2ic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -43,8 +44,10 @@ public class DungeonSecrets {
private static JsonObject waypointsJson;
@Nullable
private static CompletableFuture<Void> roomsLoaded;
- private static Vector2i mapEntrancePos;
+ private static Vector2ic mapEntrancePos;
private static int mapRoomWidth;
+ private static Vector2ic physicalEntrancePos;
+ private static Room currentRoom;
public static boolean isRoomsLoaded() {
return roomsLoaded != null && roomsLoaded.isDone();
@@ -106,7 +109,7 @@ public class DungeonSecrets {
LOGGER.error("Failed to load dungeon secrets json", e);
}
}, MinecraftClient.getInstance()));
- roomsLoaded = CompletableFuture.allOf(dungeonFutures.toArray(CompletableFuture[]::new)).thenRun(() -> LOGGER.info("Loaded dungeon secrets for {} dungeon(s), {} room shapes, and {} rooms total", ROOMS.size(), ROOMS.values().stream().mapToInt(HashMap::size).sum(), ROOMS.values().stream().map(HashMap::values).flatMap(Collection::stream).mapToInt(HashMap::size).sum()));
+ roomsLoaded = CompletableFuture.allOf(dungeonFutures.toArray(CompletableFuture[]::new)).thenRun(() -> LOGGER.info("[Skyblocker] Loaded dungeon secrets for {} dungeon(s), {} room shapes, and {} rooms total", ROOMS.size(), ROOMS.values().stream().mapToInt(HashMap::size).sum(), ROOMS.values().stream().map(HashMap::values).flatMap(Collection::stream).mapToInt(HashMap::size).sum()));
}
private static HashMap<String, int[]> readRooms(Path roomShape, int resourcePathIndex) {
@@ -146,11 +149,16 @@ public class DungeonSecrets {
if (map == null) {
return;
}
- if (mapEntrancePos == null && (mapEntrancePos = DungeonMapUtils.getEntrancePos(map)) == null) {
+ if (mapEntrancePos == null && (mapEntrancePos = DungeonMapUtils.getMapEntrancePos(map)) == null) {
return;
}
- if (mapRoomWidth == 0 && (mapRoomWidth = DungeonMapUtils.getRoomWidth(map, mapEntrancePos)) == 0) {
+ if (mapRoomWidth == 0 && (mapRoomWidth = DungeonMapUtils.getMapRoomWidth(map, mapEntrancePos)) == 0) {
return;
}
+ if (physicalEntrancePos == null && (physicalEntrancePos = DungeonMapUtils.getPhysicalEntrancePos(map, client.player.getPos())) == null) {
+ client.player.sendMessage(Text.translatable("skyblocker.dungeons.secrets.physicalEntranceNotFound"));
+ return;
+ }
+ LOGGER.info("[Skyblocker] Detected dungeon with map room width {} and entrance at map pos {} and physical pos {}", mapRoomWidth, mapEntrancePos, physicalEntrancePos);
}
}
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
new file mode 100644
index 00000000..0ee7d7f4
--- /dev/null
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/Room.java
@@ -0,0 +1,27 @@
+package me.xmrvizzy.skyblocker.skyblock.dungeon.secrets;
+
+import net.minecraft.block.MapColor;
+
+public class Room {
+ private final RoomType type;
+ private String name;
+
+ public Room(RoomType type) {
+ this.type = type;
+ }
+
+ public enum RoomType {
+ ENTRANCE(MapColor.DARK_GREEN.getRenderColorByte(MapColor.Brightness.HIGH)),
+ ROOM(MapColor.ORANGE.getRenderColorByte(MapColor.Brightness.LOWEST)),
+ PUZZLE(MapColor.MAGENTA.getRenderColorByte(MapColor.Brightness.HIGH)),
+ MINIBOSS(MapColor.YELLOW.getRenderColorByte(MapColor.Brightness.HIGH)),
+ FAIRY(MapColor.PINK.getRenderColorByte(MapColor.Brightness.HIGH)),
+ BLOOD(MapColor.BRIGHT_RED.getRenderColorByte(MapColor.Brightness.HIGH)),
+ UNKNOWN(MapColor.GRAY.getRenderColorByte(MapColor.Brightness.NORMAL));
+ final byte color;
+
+ RoomType(byte color) {
+ this.color = color;
+ }
+ }
+}