diff options
author | Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> | 2023-07-16 16:13:22 +0800 |
---|---|---|
committer | Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> | 2023-08-30 22:49:52 -0400 |
commit | 58616218d5d0c5359bdc1d84f226a0a1b08a71b2 (patch) | |
tree | 2ab2428483b7c2a43b2a500317e91524523bb09b /src/main | |
parent | dde565cd0fd822386fd4a6fe0663a65c3c6c629b (diff) | |
download | Skyblocker-58616218d5d0c5359bdc1d84f226a0a1b08a71b2.tar.gz Skyblocker-58616218d5d0c5359bdc1d84f226a0a1b08a71b2.tar.bz2 Skyblocker-58616218d5d0c5359bdc1d84f226a0a1b08a71b2.zip |
Add room position utils and physical room position parsing
Diffstat (limited to 'src/main')
4 files changed, 149 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; + } + } +} diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 86054ba4..90dfa3b9 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -283,6 +283,8 @@ "skyblocker.updaterepository.failed": "§b[§6Skyblocker§b] §cUpdating local repository failed. Remove files manually and restart game.", + "skyblocker.dungeons.secrets.physicalEntranceNotFound": "§b[§6Skyblocker§b] §cDungeon Entrance Room coordinates not found. Please go back to the green Entrance Room.", + "skyblocker.fishing.reelNow": "Reel in now!", "skyblocker.rift.healNow": "Heal now!", "skyblocker.rift.iceNow": "Ice now!", |