Skip to content

Commit ba13ced

Browse files
feat(ravengard): compose dungeon maps from genuine hypixel room art
Each catalog room's map art is cropped from the crypt segment images, which align with the blueprint world at exactly one pixel per block, rotated to all four placements and packed as bitmap font grids with per-cell data pixels. The minimap and tab map now place these room shaped glyphs for discovered rooms at one pixel per block, replacing the flat placeholder squares, so generated dungeons render with the same map styling as the pre-made crypt.
1 parent 10fd7db commit ba13ced

4 files changed

Lines changed: 102 additions & 44 deletions

File tree

configuration/ravengard/dungeon_map_glyphs.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package net.swofty.type.ravengarddungeon.game;
2+
3+
import com.google.gson.Gson;
4+
import com.google.gson.reflect.TypeToken;
5+
6+
import java.io.FileReader;
7+
import java.util.List;
8+
import java.util.Map;
9+
10+
public final class DungeonMapGlyphs {
11+
public record RoomArt(int cols, int rows, int w, int h, List<List<Integer>> tiles) {
12+
}
13+
14+
private static Map<String, Map<String, RoomArt>> byRoom;
15+
16+
private DungeonMapGlyphs() {
17+
}
18+
19+
public static synchronized Map<String, Map<String, RoomArt>> load() {
20+
if (byRoom == null) {
21+
try (FileReader reader = new FileReader("./configuration/ravengard/dungeon_map_glyphs.json")) {
22+
byRoom = new Gson().fromJson(reader,
23+
new TypeToken<Map<String, Map<String, RoomArt>>>() {}.getType());
24+
} catch (Exception exception) {
25+
org.tinylog.Logger.error(exception, "Failed to load dungeon map glyphs");
26+
byRoom = Map.of();
27+
}
28+
}
29+
return byRoom;
30+
}
31+
32+
public static RoomArt artFor(String roomId, int rotationDegrees) {
33+
Map<String, RoomArt> rotations = load().get(roomId);
34+
return rotations == null ? null : rotations.get(String.valueOf(rotationDegrees));
35+
}
36+
}

type.ravengarddungeon/src/main/java/net/swofty/type/ravengarddungeon/game/DungeonMinimapIcons.java

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
package net.swofty.type.ravengarddungeon.game;
22

33
import net.kyori.adventure.text.Component;
4+
import net.kyori.adventure.text.format.ShadowColor;
45
import net.kyori.adventure.text.format.TextColor;
56
import net.swofty.type.ravengardgeneric.hud.RavengardHudComposer;
67
import net.swofty.type.ravengardgeneric.hud.RavengardHudState;
78

89
import java.util.UUID;
910

1011
public final class DungeonMinimapIcons {
11-
private static final double MAP_SCALE = 0.75;
12-
private static final double VISIBLE_RANGE_PIXELS = 124;
13-
private static final double BLOCKS_PER_TILE = 13 / MAP_SCALE;
14-
private static final String TILE_UNSEEN = "\uE131";
15-
private static final String TILE_SEEN = "\uE132";
16-
private static final String TILE_HERE = "\uE133";
12+
private static final int TILE = 13;
13+
private static final double VISIBLE_RANGE_PIXELS = 136;
1714

1815
private DungeonMinimapIcons() {
1916
}
@@ -44,20 +41,38 @@ private static Component render(RavengardHudState state) {
4441
}
4542

4643
Component icons = Component.empty();
47-
for (DungeonInstanceRegistry.DungeonInstance.MapTile tile
48-
: dungeonInstance.getMapTiles(BLOCKS_PER_TILE)) {
49-
double offsetX = (tile.worldX() - state.getWorldX()) * MAP_SCALE;
50-
double offsetZ = (tile.worldZ() - state.getWorldZ()) * MAP_SCALE;
51-
if (Math.abs(offsetX) > VISIBLE_RANGE_PIXELS || Math.abs(offsetZ) > VISIBLE_RANGE_PIXELS) {
44+
var placements = dungeonInstance.getGenerated().dungeon().getPlacements();
45+
for (int index = 0; index < placements.size(); index++) {
46+
if (!dungeonInstance.getVisitedRooms().contains(index)) {
5247
continue;
5348
}
54-
String glyph = tile.roomIndex() == currentRoom ? TILE_HERE
55-
: dungeonInstance.getVisitedRooms().contains(tile.roomIndex()) ? TILE_SEEN
56-
: TILE_UNSEEN;
57-
int packedX = clamp9((int) Math.round((offsetX + 128) * 2));
58-
int packedZ = clamp9((int) Math.round((offsetZ + 128) * 2));
59-
icons = icons.append(Component.text(glyph)
60-
.color(TextColor.color((packedX << 15) | (packedZ << 6))));
49+
var placement = placements.get(index);
50+
DungeonMapGlyphs.RoomArt art = DungeonMapGlyphs.artFor(
51+
placement.room().getId(), placement.rotation().getDegrees());
52+
if (art == null) {
53+
continue;
54+
}
55+
for (int row = 0; row < art.rows(); row++) {
56+
for (int col = 0; col < art.cols(); col++) {
57+
Integer codepoint = art.tiles().get(row).get(col);
58+
if (codepoint == null) {
59+
continue;
60+
}
61+
double tileCenterX = placement.originX() + col * TILE + TILE / 2.0;
62+
double tileCenterZ = placement.originZ() + row * TILE + TILE / 2.0;
63+
double offsetX = tileCenterX - state.getWorldX();
64+
double offsetZ = tileCenterZ - state.getWorldZ();
65+
if (Math.abs(offsetX) > VISIBLE_RANGE_PIXELS
66+
|| Math.abs(offsetZ) > VISIBLE_RANGE_PIXELS) {
67+
continue;
68+
}
69+
int packedX = clamp9((int) Math.round((offsetX + 128) * 2));
70+
int packedZ = clamp9((int) Math.round((offsetZ + 128) * 2));
71+
icons = icons.append(Component.text(Character.toString(codepoint))
72+
.color(TextColor.color((packedX << 15) | (packedZ << 6)))
73+
.shadowColor(ShadowColor.shadowColor(0)));
74+
}
75+
}
6176
}
6277
return icons;
6378
}

type.ravengarddungeon/src/main/java/net/swofty/type/ravengarddungeon/game/DungeonTabMap.java

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,11 @@
88
import net.swofty.type.ravengardgeneric.hud.RavengardHudComposer;
99
import net.swofty.type.ravengardgeneric.hud.RavengardHudState;
1010

11-
import java.util.List;
1211
import java.util.UUID;
1312

1413
public final class DungeonTabMap {
15-
private static final double MAP_SCALE = 0.75;
16-
private static final double BLOCKS_PER_TILE = 13 / MAP_SCALE;
14+
private static final int TILE = 13;
1715
private static final int MAP_CENTER = 256;
18-
private static final String TILE_UNSEEN = "";
19-
private static final String TILE_SEEN = "";
20-
private static final String TILE_HERE = "";
2116
private static final String PLAYER_MARKER = "";
2217
private static final String TEAMMATE_MARKER = "";
2318
private static final double YAW_PER_STEP = 360.0 / 64.0;
@@ -45,30 +40,41 @@ private static Component render(RavengardHudState state) {
4540
return null;
4641
}
4742

48-
List<DungeonInstanceRegistry.DungeonInstance.MapTile> tiles =
49-
dungeonInstance.getMapTiles(BLOCKS_PER_TILE);
50-
if (tiles.isEmpty()) {
51-
return null;
52-
}
43+
var placements = dungeonInstance.getGenerated().dungeon().getPlacements();
5344
double minX = Double.MAX_VALUE, maxX = -Double.MAX_VALUE;
5445
double minZ = Double.MAX_VALUE, maxZ = -Double.MAX_VALUE;
55-
for (DungeonInstanceRegistry.DungeonInstance.MapTile tile : tiles) {
56-
minX = Math.min(minX, tile.worldX());
57-
maxX = Math.max(maxX, tile.worldX());
58-
minZ = Math.min(minZ, tile.worldZ());
59-
maxZ = Math.max(maxZ, tile.worldZ());
46+
for (var placement : placements) {
47+
minX = Math.min(minX, placement.originX());
48+
maxX = Math.max(maxX, placement.originX() + placement.getFootprintWidth());
49+
minZ = Math.min(minZ, placement.originZ());
50+
maxZ = Math.max(maxZ, placement.originZ() + placement.getFootprintDepth());
6051
}
6152
double centerX = (minX + maxX) / 2, centerZ = (minZ + maxZ) / 2;
6253

63-
int currentRoom = dungeonInstance.roomIndexAt(state.getWorldX(), state.getWorldZ());
6454
Component header = Component.empty();
65-
for (DungeonInstanceRegistry.DungeonInstance.MapTile tile : tiles) {
66-
String glyph = tile.roomIndex() == currentRoom ? TILE_HERE
67-
: dungeonInstance.getVisitedRooms().contains(tile.roomIndex()) ? TILE_SEEN
68-
: TILE_UNSEEN;
69-
header = header.append(Component.text(glyph)
70-
.color(TextColor.color(packed(tile.worldX(), tile.worldZ(), centerX, centerZ, 0)))
71-
.shadowColor(ShadowColor.shadowColor(0)));
55+
for (int index = 0; index < placements.size(); index++) {
56+
if (!dungeonInstance.getVisitedRooms().contains(index)) {
57+
continue;
58+
}
59+
var placement = placements.get(index);
60+
DungeonMapGlyphs.RoomArt art = DungeonMapGlyphs.artFor(
61+
placement.room().getId(), placement.rotation().getDegrees());
62+
if (art == null) {
63+
continue;
64+
}
65+
for (int row = 0; row < art.rows(); row++) {
66+
for (int col = 0; col < art.cols(); col++) {
67+
Integer codepoint = art.tiles().get(row).get(col);
68+
if (codepoint == null) {
69+
continue;
70+
}
71+
double tileCenterX = placement.originX() + col * TILE + TILE / 2.0;
72+
double tileCenterZ = placement.originZ() + row * TILE + TILE / 2.0;
73+
header = header.append(Component.text(Character.toString(codepoint))
74+
.color(TextColor.color(packed(tileCenterX, tileCenterZ, centerX, centerZ, 0)))
75+
.shadowColor(ShadowColor.shadowColor(0)));
76+
}
77+
}
7278
}
7379
header = header.append(Component.newline());
7480

@@ -92,8 +98,8 @@ private static Component render(RavengardHudState state) {
9298
}
9399

94100
private static int packed(double worldX, double worldZ, double centerX, double centerZ, int rotation) {
95-
int mapX = clamp9((int) Math.round(MAP_CENTER + (worldX - centerX) * MAP_SCALE));
96-
int mapZ = clamp9((int) Math.round(MAP_CENTER + (worldZ - centerZ) * MAP_SCALE));
101+
int mapX = clamp9((int) Math.round(MAP_CENTER + (worldX - centerX)));
102+
int mapZ = clamp9((int) Math.round(MAP_CENTER + (worldZ - centerZ)));
97103
return (mapX << 15) | (mapZ << 6) | rotation;
98104
}
99105

0 commit comments

Comments
 (0)