Skip to content

Commit c2be292

Browse files
refactor(dungeons): GameDungeon hierarchy and clean ravengard layout api
Introduces GameDungeon as the shared base of both generators, renames SkyBlockDungeon to CatacombsDungeon extending it, and rebuilds the ravengard side as RavengardDungeon extending the same base. Directions and rotations become enums with the rotation math on them, the catalog moves to lombok accessors with serialized name mappings instead of hand-rolled getters over cryptic fields, and the layout, alignment and render code drops the abbreviated locals for descriptive names throughout.
1 parent 33e0ad6 commit c2be292

17 files changed

Lines changed: 437 additions & 473 deletions

dungeons/src/main/java/net/swofty/dungeons/SkyBlockDungeon.java renamed to dungeons/src/main/java/net/swofty/dungeons/CatacombsDungeon.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,16 @@
99
import java.util.Map;
1010
import java.util.concurrent.CountDownLatch;
1111

12-
public class SkyBlockDungeon {
12+
public class CatacombsDungeon extends GameDungeon {
13+
@Override
14+
public int getRoomCount() {
15+
return rooms.size();
16+
}
17+
1318
private Map<Map.Entry<Integer, Integer>, DungeonRoom> rooms = new HashMap<>();
1419
private List<DungeonDoor> doors = new ArrayList<>();
1520

16-
public SkyBlockDungeon setRoom(int x, int y, DungeonRoom room) {
21+
public CatacombsDungeon setRoom(int x, int y, DungeonRoom room) {
1722
rooms.put(Map.entry(x, y), room);
1823
return this;
1924
}

dungeons/src/main/java/net/swofty/dungeons/DungeonUtilities.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public static Stream<Map.Entry<Integer, Integer>> loopOverDungeonRooms(DungeonsD
1414
.map(i -> Map.entry(i % data.getWidth(), i / data.getHeight()));
1515
}
1616

17-
public static List<int[]> getFreeNeighbours(int x, int y, SkyBlockDungeon dungeon, DungeonsData data) {
17+
public static List<int[]> getFreeNeighbours(int x, int y, CatacombsDungeon dungeon, DungeonsData data) {
1818
List<int[]> freeNeighbours = new ArrayList<>();
1919
if (x > 0 && dungeon.getRoom(x - 1, y).getStage() == 0) freeNeighbours.add(new int[]{x - 1, y});
2020
if (y > 0 && dungeon.getRoom(x, y - 1).getStage() == 0) freeNeighbours.add(new int[]{x, y - 1});
@@ -25,7 +25,7 @@ public static List<int[]> getFreeNeighbours(int x, int y, SkyBlockDungeon dungeo
2525
return freeNeighbours;
2626
}
2727

28-
public static List<int[]> getAdjacentBaseRooms(int x, int y, SkyBlockDungeon dungeon, DungeonsData data) {
28+
public static List<int[]> getAdjacentBaseRooms(int x, int y, CatacombsDungeon dungeon, DungeonsData data) {
2929
List<int[]> neighbours = new ArrayList<>();
3030
if (x > 0 && dungeon.getRoom(x - 1, y).getRoomType() == DungeonRoomType.BASE)
3131
neighbours.add(new int[]{x - 1, y});
@@ -105,7 +105,7 @@ private static List<int[]> reconstructPath(Map<String, int[]> cameFrom, int star
105105
return path;
106106
}
107107

108-
public static void asyncPrintDungeon(SkyBlockDungeon dungeon) {
108+
public static void asyncPrintDungeon(CatacombsDungeon dungeon) {
109109
Thread.startVirtualThread(() -> {
110110
System.out.println(dungeon);
111111
});

dungeons/src/main/java/net/swofty/dungeons/DungeonsTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ static void main(String[] args) {
88
.with(DungeonRoomType.MINI_BOSS, new DungeonsData.RoomData(1, 1));
99

1010
GeneratorService generatorService = DungeonsAPI.getGeneratorService(data);
11-
SkyBlockDungeon dungeon = generatorService.generate().join();
11+
CatacombsDungeon dungeon = generatorService.generate().join();
1212

1313
System.out.println("Generated dungeon: \n" + dungeon);
1414
System.out.println(System.currentTimeMillis() - generatorService.getGenerationStartTime());
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package net.swofty.dungeons;
2+
3+
public abstract class GameDungeon {
4+
public abstract int getRoomCount();
5+
6+
@Override
7+
public abstract String toString();
8+
}

dungeons/src/main/java/net/swofty/dungeons/GeneratorService.java

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ public class GeneratorService {
1515
private final DungeonsData data;
1616
@Getter
1717
private GenerationStage currentStage = GenerationStage.INITIALIZATION;
18-
private CompletableFuture<SkyBlockDungeon> generationFuture;
18+
private CompletableFuture<CatacombsDungeon> generationFuture;
1919
@Getter
2020
private long generationStartTime;
2121

22-
public CompletableFuture<SkyBlockDungeon> generate() {
23-
CompletableFuture<SkyBlockDungeon> future = new CompletableFuture<>();
22+
public CompletableFuture<CatacombsDungeon> generate() {
23+
CompletableFuture<CatacombsDungeon> future = new CompletableFuture<>();
2424
generationFuture = future;
2525
generationStartTime = System.currentTimeMillis();
2626

@@ -58,29 +58,29 @@ public CompletableFuture<SkyBlockDungeon> generate() {
5858
return new int[]{fairyX, fairyY};
5959
});
6060

61-
SkyBlockDungeon dungeon = new SkyBlockDungeon();
61+
CatacombsDungeon dungeon = new CatacombsDungeon();
6262
DungeonUtilities.loopOverDungeonRooms(data).forEach(values -> {
6363
int width = values.getKey();
6464
int height = values.getValue();
6565

66-
dungeon.setRoom(width, height, SkyBlockDungeon.DungeonRoom.ofBase());
66+
dungeon.setRoom(width, height, CatacombsDungeon.DungeonRoom.ofBase());
6767
});
6868

6969
final int[] fairyPositions = {0, 0};
7070
// Not async, we need this done before generating the critical path
7171
fairyPosition.thenAccept(fairyPos -> {
7272
fairyPositions[0] = fairyPos[0];
7373
fairyPositions[1] = fairyPos[1];
74-
dungeon.setRoom(fairyPositions[0], fairyPositions[1], new SkyBlockDungeon.DungeonRoom(DungeonRoomType.FAIRY));
74+
dungeon.setRoom(fairyPositions[0], fairyPositions[1], new CatacombsDungeon.DungeonRoom(DungeonRoomType.FAIRY));
7575
});
7676

7777
// We can use the entranceAndExits future to get the entrance and exit points
7878
entranceAndExits.thenAcceptAsync(entranceAndExit -> {
7979
int entranceX = entranceAndExit[0];
8080
int exitX = entranceAndExit[1];
8181

82-
dungeon.setRoom(entranceX, 0, new SkyBlockDungeon.DungeonRoom(DungeonRoomType.ENTRANCE));
83-
dungeon.setRoom(exitX, data.getHeight() - 1, new SkyBlockDungeon.DungeonRoom(DungeonRoomType.EXIT));
82+
dungeon.setRoom(entranceX, 0, new CatacombsDungeon.DungeonRoom(DungeonRoomType.ENTRANCE));
83+
dungeon.setRoom(exitX, data.getHeight() - 1, new CatacombsDungeon.DungeonRoom(DungeonRoomType.EXIT));
8484

8585
// Move to critical path generation
8686
currentStage = GenerationStage.CRITICAL_PATH;
@@ -178,12 +178,12 @@ public CompletableFuture<SkyBlockDungeon> generate() {
178178
// add a chance to connect them with a door
179179
for (int y = 0; y < data.getHeight(); y++) {
180180
for (int x = 0; x < data.getWidth(); x++) {
181-
SkyBlockDungeon.DungeonRoom room = dungeon.getRoom(x, y);
181+
CatacombsDungeon.DungeonRoom room = dungeon.getRoom(x, y);
182182
if (room.getRoomType() != DungeonRoomType.BASE) continue; // Skip if room already has a type
183183

184184
List<int[]> adjacentBases = DungeonUtilities.getAdjacentBaseRooms(x, y, dungeon, data);
185185
for (int[] adjacent : adjacentBases) {
186-
SkyBlockDungeon.DungeonRoom adjacentRoom = dungeon.getRoom(adjacent[0], adjacent[1]);
186+
CatacombsDungeon.DungeonRoom adjacentRoom = dungeon.getRoom(adjacent[0], adjacent[1]);
187187
if (adjacentRoom.getRoomType() != DungeonRoomType.BASE) continue; // Skip if adjacent room already has a type
188188
if (adjacentRoom.getStage() != room.getStage()) continue; // Skip if adjacent room is not the same stage
189189

@@ -201,7 +201,7 @@ public CompletableFuture<SkyBlockDungeon> generate() {
201201
return future;
202202
}
203203

204-
public void assignRoomsAsync(Map<DungeonRoomType, Integer> roomAmounts, SkyBlockDungeon dungeon) {
204+
public void assignRoomsAsync(Map<DungeonRoomType, Integer> roomAmounts, CatacombsDungeon dungeon) {
205205
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
206206

207207
List<CompletableFuture<Void>> futures = new ArrayList<>();
@@ -212,7 +212,7 @@ public void assignRoomsAsync(Map<DungeonRoomType, Integer> roomAmounts, SkyBlock
212212
while (roomsAssigned.get() < amount) {
213213
for (int y = 0; y < data.getHeight(); y++) {
214214
for (int x = 0; x < data.getWidth(); x++) {
215-
SkyBlockDungeon.DungeonRoom room = dungeon.getRoom(x, y);
215+
CatacombsDungeon.DungeonRoom room = dungeon.getRoom(x, y);
216216
if (room.getRoomType() != DungeonRoomType.BASE) continue; // Skip if room already has a type
217217
if (room.isCritical()) continue; // Skip if room is critical
218218

@@ -252,14 +252,14 @@ public void assignRoomsAsync(Map<DungeonRoomType, Integer> roomAmounts, SkyBlock
252252
executor.shutdown(); // Don't forget to shut down the executor
253253
}
254254

255-
public void assignCorridors(SkyBlockDungeon dungeon) {
255+
public void assignCorridors(CatacombsDungeon dungeon) {
256256
Random random = new Random();
257257
int corridorID = 1;
258258
boolean[][] visited = new boolean[data.getWidth()][data.getHeight()]; // Track visited rooms
259259

260260
for (int y = 0; y < data.getHeight(); y++) {
261261
for (int x = 0; x < data.getWidth(); x++) {
262-
SkyBlockDungeon.DungeonRoom initialRoom = dungeon.getRoom(x, y);
262+
CatacombsDungeon.DungeonRoom initialRoom = dungeon.getRoom(x, y);
263263
if (!visited[x][y] && initialRoom.getRoomType() == DungeonRoomType.BASE) {
264264
List<int[]> potentialCorridorSet = new ArrayList<>();
265265
Queue<int[]> queue = new LinkedList<>();
@@ -273,14 +273,14 @@ public void assignCorridors(SkyBlockDungeon dungeon) {
273273
if (visited[curX][curY]) continue;
274274
visited[curX][curY] = true;
275275

276-
SkyBlockDungeon.DungeonRoom currentRoom = dungeon.getRoom(curX, curY);
276+
CatacombsDungeon.DungeonRoom currentRoom = dungeon.getRoom(curX, curY);
277277
if (currentRoom.getRoomType() == DungeonRoomType.BASE && currentRoom.getStage() == currentStage) {
278278
potentialCorridorSet.add(current);
279279

280280
// Check adjacent base rooms of the same stage for potential inclusion
281281
List<int[]> adjacents = DungeonUtilities.getAdjacentBaseRooms(curX, curY, dungeon, data);
282282
for (int[] adj : adjacents) {
283-
SkyBlockDungeon.DungeonRoom adjRoom = dungeon.getRoom(adj[0], adj[1]);
283+
CatacombsDungeon.DungeonRoom adjRoom = dungeon.getRoom(adj[0], adj[1]);
284284
if (!visited[adj[0]][adj[1]] && adjRoom.getStage() == currentStage && random.nextBoolean()) {
285285
queue.offer(adj);
286286
}
@@ -291,7 +291,7 @@ public void assignCorridors(SkyBlockDungeon dungeon) {
291291
// Validate and assign corridor ID only if the set connects two or more rooms
292292
if (potentialCorridorSet.size() > 1) {
293293
for (int[] coords : potentialCorridorSet) {
294-
SkyBlockDungeon.DungeonRoom room = dungeon.getRoom(coords[0], coords[1]);
294+
CatacombsDungeon.DungeonRoom room = dungeon.getRoom(coords[0], coords[1]);
295295
room.setCorridorNumber(corridorID); // Assign corridor ID
296296
dungeon.setRoom(coords[0], coords[1], room);
297297
}

dungeons/src/main/java/net/swofty/dungeons/catacombs/CatacombsAPI.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import lombok.AccessLevel;
44
import lombok.NoArgsConstructor;
55
import net.swofty.dungeons.GeneratorService;
6-
import net.swofty.dungeons.SkyBlockDungeon;
6+
import net.swofty.dungeons.CatacombsDungeon;
77
import net.swofty.dungeons.catacombs.classes.DungeonClassDefinition;
88
import net.swofty.dungeons.catacombs.classes.DungeonClassRegistry;
99
import net.swofty.dungeons.catacombs.classes.DungeonClassType;
@@ -85,7 +85,7 @@ public static GeneratorService generator(CatacombsFloorDefinition definition) {
8585
return CatacombsGenerator.generator(definition);
8686
}
8787

88-
public static DungeonMapRenderResult renderMap(SkyBlockDungeon dungeon, Path outputPath) throws IOException {
88+
public static DungeonMapRenderResult renderMap(CatacombsDungeon dungeon, Path outputPath) throws IOException {
8989
return MAP_RENDERER.renderPng(dungeon, outputPath);
9090
}
9191

dungeons/src/main/java/net/swofty/dungeons/catacombs/instance/CatacombsInstance.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package net.swofty.dungeons.catacombs.instance;
22

3-
import net.swofty.dungeons.SkyBlockDungeon;
3+
import net.swofty.dungeons.CatacombsDungeon;
44
import net.swofty.dungeons.catacombs.CatacombsFloorDefinition;
55
import net.swofty.dungeons.catacombs.boss.state.BossFightController;
66
import net.swofty.dungeons.catacombs.kit.DungeonClassKit;
@@ -13,7 +13,7 @@
1313
public record CatacombsInstance(
1414
UUID id,
1515
CatacombsFloorDefinition floor,
16-
SkyBlockDungeon dungeon,
16+
CatacombsDungeon dungeon,
1717
CatacombsRunState runState,
1818
BossFightController bossFight,
1919
Map<UUID, DungeonClassKit> kits,

dungeons/src/main/java/net/swofty/dungeons/catacombs/instance/CatacombsInstanceService.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package net.swofty.dungeons.catacombs.instance;
22

33
import net.swofty.dungeons.DungeonRoomType;
4-
import net.swofty.dungeons.SkyBlockDungeon;
4+
import net.swofty.dungeons.CatacombsDungeon;
55
import net.swofty.dungeons.catacombs.CatacombsAPI;
66
import net.swofty.dungeons.catacombs.CatacombsFloorDefinition;
77
import net.swofty.dungeons.catacombs.boss.state.BossFightController;
@@ -22,7 +22,7 @@ public final class CatacombsInstanceService {
2222
public CatacombsInstance create(CatacombsFloorDefinition floor,
2323
Map<UUID, DungeonClassKit> kits,
2424
Path mapOutput) throws IOException {
25-
SkyBlockDungeon dungeon = CatacombsAPI.generator(floor).generate().join();
25+
CatacombsDungeon dungeon = CatacombsAPI.generator(floor).generate().join();
2626
Map<Integer, DungeonRoomEncounter> encounters = encounters(floor, dungeon);
2727
CatacombsRunState runState = CatacombsRunState.start(new CatacombsRunConfig(
2828
floor,
@@ -39,10 +39,10 @@ public CatacombsInstance create(CatacombsFloorDefinition floor,
3939
new BossFightController(floor.boss()), kits, encounters, renderedMap);
4040
}
4141

42-
private Map<Integer, DungeonRoomEncounter> encounters(CatacombsFloorDefinition floor, SkyBlockDungeon dungeon) {
42+
private Map<Integer, DungeonRoomEncounter> encounters(CatacombsFloorDefinition floor, CatacombsDungeon dungeon) {
4343
Map<Integer, DungeonRoomEncounter> encounters = new HashMap<>();
4444
int roomId = 0;
45-
for (SkyBlockDungeon.DungeonRoom room : dungeon.getRooms().values()) {
45+
for (CatacombsDungeon.DungeonRoom room : dungeon.getRooms().values()) {
4646
List<DungeonMobDefinition> mobs = switch (room.getRoomType()) {
4747
case MINI_BOSS -> CatacombsAPI.mobs(floor.floor(), DungeonMobRole.MINIBOSS).stream().limit(1).toList();
4848
case PUZZLE -> CatacombsAPI.mobs(floor.floor(), DungeonMobRole.PUZZLE).stream().limit(1).toList();
@@ -61,7 +61,7 @@ private Map<Integer, DungeonRoomEncounter> encounters(CatacombsFloorDefinition f
6161
return encounters;
6262
}
6363

64-
private int estimateSecrets(CatacombsFloorDefinition floor, SkyBlockDungeon dungeon) {
64+
private int estimateSecrets(CatacombsFloorDefinition floor, CatacombsDungeon dungeon) {
6565
int baseRooms = (int) dungeon.getRooms().values().stream()
6666
.filter(room -> room.getRoomType() == DungeonRoomType.BASE)
6767
.count();

dungeons/src/main/java/net/swofty/dungeons/catacombs/map/DungeonMapRenderer.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package net.swofty.dungeons.catacombs.map;
22

3-
import net.swofty.dungeons.SkyBlockDungeon;
3+
import net.swofty.dungeons.CatacombsDungeon;
44

55
import javax.imageio.ImageIO;
66
import java.awt.BasicStroke;
@@ -18,7 +18,7 @@ public final class DungeonMapRenderer {
1818
private static final int GAP = 14;
1919
private static final int PADDING = 24;
2020

21-
public DungeonMapRenderResult renderPng(SkyBlockDungeon dungeon, Path outputPath) throws IOException {
21+
public DungeonMapRenderResult renderPng(CatacombsDungeon dungeon, Path outputPath) throws IOException {
2222
int maxX = dungeon.getRooms().keySet().stream().mapToInt(Map.Entry::getKey).max().orElse(0);
2323
int maxY = dungeon.getRooms().keySet().stream().mapToInt(Map.Entry::getValue).max().orElse(0);
2424
int width = PADDING * 2 + (maxX + 1) * TILE + maxX * GAP;
@@ -30,7 +30,7 @@ public DungeonMapRenderResult renderPng(SkyBlockDungeon dungeon, Path outputPath
3030
graphics.fillRect(0, 0, width, height);
3131
graphics.setStroke(new BasicStroke(6, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
3232
graphics.setColor(new Color(0xD9C7A7));
33-
for (SkyBlockDungeon.DungeonDoor door : dungeon.getDoorConnections()) {
33+
for (CatacombsDungeon.DungeonDoor door : dungeon.getDoorConnections()) {
3434
int x1 = center(door.x1());
3535
int y1 = center(door.y1());
3636
int x2 = center(door.x2());
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package net.swofty.dungeons.ravengard;
2+
3+
import com.google.gson.annotations.SerializedName;
4+
5+
public enum Direction {
6+
@SerializedName("north") NORTH,
7+
@SerializedName("east") EAST,
8+
@SerializedName("south") SOUTH,
9+
@SerializedName("west") WEST;
10+
11+
public Direction getOpposite() {
12+
return values()[(ordinal() + 2) % 4];
13+
}
14+
15+
public Direction rotated(Rotation rotation) {
16+
return values()[(ordinal() + rotation.getQuarterTurns()) % 4];
17+
}
18+
19+
public boolean isHorizontalAxis() {
20+
return this == EAST || this == WEST;
21+
}
22+
}

0 commit comments

Comments
 (0)