From c92c143058f6aa6e9eb0869613600f76e188b1bc Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Mon, 1 Jun 2026 14:29:55 +0200 Subject: [PATCH] feat(save): SaveData/SaveSlotInfo/SaveException model --- .../thb/jeanluc/adventure/save/SaveData.java | 29 +++++++++++++++++++ .../jeanluc/adventure/save/SaveException.java | 18 ++++++++++++ .../jeanluc/adventure/save/SaveSlotInfo.java | 6 ++++ .../jeanluc/adventure/save/SaveDataTest.java | 28 ++++++++++++++++++ 4 files changed, 81 insertions(+) create mode 100644 Semesterprojekt/src/main/java/thb/jeanluc/adventure/save/SaveData.java create mode 100644 Semesterprojekt/src/main/java/thb/jeanluc/adventure/save/SaveException.java create mode 100644 Semesterprojekt/src/main/java/thb/jeanluc/adventure/save/SaveSlotInfo.java create mode 100644 Semesterprojekt/src/test/java/thb/jeanluc/adventure/save/SaveDataTest.java diff --git a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/save/SaveData.java b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/save/SaveData.java new file mode 100644 index 0000000..f6a96fe --- /dev/null +++ b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/save/SaveData.java @@ -0,0 +1,29 @@ +package thb.jeanluc.adventure.save; + +import java.util.List; +import java.util.Map; + +/** + * JSON-serialised snapshot of the mutable game state — a delta laid over the + * world freshly loaded from YAML. Header fields ({@code slotName}, room, + * {@code turn}, {@code savedAtEpochMillis}) double as the slot-list metadata. + */ +public record SaveData( + int schemaVersion, + String worldTitle, + String slotName, + long savedAtEpochMillis, + int turn, + String currentRoomId, + List visitedRoomIds, + int gold, + List inventoryItemIds, + List flags, + Map questStages, + List questCompleted, + Map> roomItemIds, + Map switchStates +) { + /** Current on-disk schema version. */ + public static final int CURRENT_VERSION = 1; +} diff --git a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/save/SaveException.java b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/save/SaveException.java new file mode 100644 index 0000000..190d06b --- /dev/null +++ b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/save/SaveException.java @@ -0,0 +1,18 @@ +package thb.jeanluc.adventure.save; + +/** Thrown when a save cannot be written/read; carries a player-facing message. */ +public class SaveException extends RuntimeException { + + public SaveException(String message, Throwable cause) { + super(message, cause); + } + + public SaveException(String message) { + super(message); + } + + /** Player-facing message (the constructor message is already user-friendly). */ + public String getUserMessage() { + return getMessage(); + } +} diff --git a/Semesterprojekt/src/main/java/thb/jeanluc/adventure/save/SaveSlotInfo.java b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/save/SaveSlotInfo.java new file mode 100644 index 0000000..dd7e186 --- /dev/null +++ b/Semesterprojekt/src/main/java/thb/jeanluc/adventure/save/SaveSlotInfo.java @@ -0,0 +1,6 @@ +package thb.jeanluc.adventure.save; + +/** Lightweight metadata for one save slot, shown in the Load menu. */ +public record SaveSlotInfo(String slug, String slotName, String roomId, + int turn, long savedAtEpochMillis) { +} diff --git a/Semesterprojekt/src/test/java/thb/jeanluc/adventure/save/SaveDataTest.java b/Semesterprojekt/src/test/java/thb/jeanluc/adventure/save/SaveDataTest.java new file mode 100644 index 0000000..95033d3 --- /dev/null +++ b/Semesterprojekt/src/test/java/thb/jeanluc/adventure/save/SaveDataTest.java @@ -0,0 +1,28 @@ +package thb.jeanluc.adventure.save; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class SaveDataTest { + + @Test + void roundTripsThroughJackson() throws Exception { + SaveData data = new SaveData( + 1, "Haunted Manor", "slot-a", 1700000000000L, 7, + "library", List.of("kitchen", "library"), 3, + List.of("key"), List.of("power_on"), + Map.of("restore_power", 1), List.of("intro"), + Map.of("cellar", List.of("shovel")), Map.of("lamp", true)); + ObjectMapper mapper = new ObjectMapper(); + String json = mapper.writeValueAsString(data); + SaveData back = mapper.readValue(json, SaveData.class); + assertThat(back).isEqualTo(data); + assertThat(back.currentRoomId()).isEqualTo("library"); + assertThat(back.switchStates()).containsEntry("lamp", true); + } +}