nodes/save_io.pyΒΆ

Part of GDQuest Open RPG.

 1"""JSON save / load for the save shrine."""
 2
 3from __future__ import annotations
 4
 5import json
 6import os
 7from pathlib import Path
 8from typing import Any
 9
10_SAVE_DIR_NAME = "saves"
11_SAVE_FILE_NAME = "open_rpg.json"
12
13
14class SaveStore:
15    """Atomic JSON save with one rotated .bak."""
16
17    def __init__(self, path: Path | None = None) -> None:
18        if path is None:
19            base = Path.cwd() / _SAVE_DIR_NAME
20            path = base / _SAVE_FILE_NAME
21        self.path = path
22
23    def save(self, data: dict[str, Any]) -> None:
24        try:
25            self.path.parent.mkdir(parents=True, exist_ok=True)
26            tmp = self.path.with_suffix(".tmp")
27            tmp.write_text(json.dumps(data, indent=2))
28            if self.path.exists():
29                bak = self.path.with_suffix(".bak")
30                if bak.exists():
31                    bak.unlink()
32                os.replace(self.path, bak)
33            os.replace(tmp, self.path)
34        except OSError:
35            pass
36
37    def load(self) -> dict[str, Any] | None:
38        try:
39            if not self.path.exists():
40                return None
41            return json.loads(self.path.read_text())
42        except (OSError, json.JSONDecodeError):
43            return None