feat(save): SaveData/SaveSlotInfo/SaveException model
This commit is contained in:
@@ -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<String> visitedRoomIds,
|
||||||
|
int gold,
|
||||||
|
List<String> inventoryItemIds,
|
||||||
|
List<String> flags,
|
||||||
|
Map<String, Integer> questStages,
|
||||||
|
List<String> questCompleted,
|
||||||
|
Map<String, List<String>> roomItemIds,
|
||||||
|
Map<String, Boolean> switchStates
|
||||||
|
) {
|
||||||
|
/** Current on-disk schema version. */
|
||||||
|
public static final int CURRENT_VERSION = 1;
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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) {
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user