semesterprojekt: implement full text adventure (phases 1-7)
Walking skeleton through Swing GUI: YAML-driven world (4 rooms, 4 items, 1 NPC), HashMap command dispatch with parser, three-tier item hierarchy (readable / switchable / plain), and end-to-end NPC give/receive flow. 67 tests green.
This commit is contained in:
78
Semesterprojekt/docs/loading-flow.md
Normal file
78
Semesterprojekt/docs/loading-flow.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# Loading-Flow
|
||||
|
||||
Wie aus 4 YAML-Dateien eine spielbare `World` mit aufgelösten Referenzen wird.
|
||||
|
||||
## Phasen
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
P1["<b>Phase 1: YAML → DTOs</b><br/>Jackson liest items.yaml, npcs.yaml,<br/>rooms.yaml, game.yaml in Records.<br/>Nur Daten, IDs als Strings."]
|
||||
P2["<b>Phase 2: Domain-Shells erzeugen</b><br/>Pro DTO ein leeres Domain-Objekt.<br/>itemRegistry, npcRegistry, roomRegistry."]
|
||||
P3["<b>Phase 3: Referenzen auflösen</b><br/>Room: items-ids → Item-Objekte<br/>Room: npcs-ids → Npc-Objekte<br/>Room: exits-Strings → Direction + Room-Ref<br/>Npc: reactions auflösen (gives, consumes)"]
|
||||
P4["<b>Phase 4: Validierung</b><br/>Validierungsregeln aus yaml-schemas.md.<br/>Wirft WorldLoadException bei Verstoss."]
|
||||
P5["<b>Phase 5: Player + World zusammenstellen</b><br/>Player mit startRoom + startGold.<br/>World für den Game-Loop bereit."]
|
||||
|
||||
P1 --> P2 --> P3 --> P4 --> P5
|
||||
```
|
||||
|
||||
## Klassen-Aufteilung
|
||||
|
||||
| Klasse | Verantwortung |
|
||||
|---|---|
|
||||
| `WorldLoader` | Orchestriert die Phasen, public API: `World load()` |
|
||||
| `ReferenceResolver` | Phase 3 isoliert (testbar) |
|
||||
| `WorldValidator` | Phase 4 isoliert (testbar) |
|
||||
| `WorldLoadException` | Eigene RuntimeException mit aussagekräftiger Message |
|
||||
|
||||
## Beispiel-Skizze
|
||||
|
||||
```java
|
||||
public class WorldLoader {
|
||||
|
||||
private final ObjectMapper yaml = new ObjectMapper(new YAMLFactory());
|
||||
|
||||
public World load() {
|
||||
// Phase 1
|
||||
List<ItemDto> itemDtos = readList("/world/items.yaml", ItemDto.class);
|
||||
List<NpcDto> npcDtos = readList("/world/npcs.yaml", NpcDto.class);
|
||||
List<RoomDto> roomDtos = readList("/world/rooms.yaml", RoomDto.class);
|
||||
GameDto gameDto = readSingle("/world/game.yaml", GameDto.class);
|
||||
|
||||
// Phase 2: Registries
|
||||
Map<String, Item> items = itemDtos.stream()
|
||||
.collect(Collectors.toMap(ItemDto::id, ItemFactory::fromDto));
|
||||
Map<String, Npc> npcs = npcDtos.stream()
|
||||
.collect(Collectors.toMap(NpcDto::id, NpcFactory::fromDto));
|
||||
Map<String, Room> rooms = roomDtos.stream()
|
||||
.collect(Collectors.toMap(RoomDto::id, RoomFactory::shellFromDto));
|
||||
|
||||
// Phase 3: Referenzen auflösen
|
||||
ReferenceResolver resolver = new ReferenceResolver(items, npcs, rooms);
|
||||
resolver.resolveRooms(roomDtos);
|
||||
resolver.resolveNpcs(npcDtos);
|
||||
|
||||
// Phase 4: validieren
|
||||
new WorldValidator(items, npcs, rooms, gameDto).validate();
|
||||
|
||||
// Phase 5
|
||||
Player player = new Player(rooms.get(gameDto.startRoom()), gameDto.startGold());
|
||||
return new World(rooms, items, npcs, player, gameDto);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Warum getrennte Phasen?
|
||||
|
||||
- **Testbarkeit:** Resolver und Validator können isoliert mit fertigen DTOs gefüttert werden, ohne YAML auf der Platte
|
||||
- **Fehlerlokalisierung:** „Resolver hat versagt" vs. „Validator hat versagt" sind unterschiedliche Diagnosen
|
||||
- **Zirkuläre Referenzen** (Raum A → Raum B → Raum A) werden problemlos: in Phase 2 sind beide Shells da, Phase 3 verlinkt
|
||||
- **Fail-fast:** Spiel startet nicht mit kaputter Welt — besser als NullPointer beim ersten `go north`
|
||||
|
||||
## Tests pro Phase
|
||||
|
||||
| Test | Inhalt |
|
||||
|---|---|
|
||||
| `WorldLoaderTest` | Happy-Path: lädt Test-Fixtures aus `src/test/resources/world/` |
|
||||
| `ReferenceResolverTest` | DTOs als Eingabe, prüft Auflösung |
|
||||
| `WorldValidatorTest` | Pro Validierungsregel ein Test, der den Fehler triggert |
|
||||
| `WorldValidatorTest.happy()` | Vollständig valide Welt darf nicht werfen |
|
||||
Reference in New Issue
Block a user