koro 2.0.0rc3__py3-none-any.whl → 2.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
koro/slot/save.py CHANGED
@@ -1,137 +1,138 @@
1
- from enum import Enum, unique
2
- from io import BytesIO
3
- from operator import index as ix
4
- from os.path import basename, dirname, join
5
- from typing import TYPE_CHECKING, Annotated, Any, Literal, SupportsIndex
6
- from collections.abc import Mapping, Sequence
7
-
8
- from ..stage import Stage
9
-
10
- from . import Slot
11
- from .xml import XmlSlot
12
-
13
- if TYPE_CHECKING:
14
- from _typeshed import StrOrBytesPath
15
- else:
16
- StrOrBytesPath = Any
17
-
18
-
19
- __all__ = ["EditorPage", "get_slots", "SaveSlot"]
20
-
21
-
22
- @unique
23
- class EditorPage(Enum):
24
- ORIGINAL = 0
25
- FRIEND = 1
26
- HUDSON = 2
27
-
28
-
29
- class SaveSlot(Slot):
30
- __match_args__ = ("path", "page", "index")
31
- __slots__ = ("_offset", "_path")
32
-
33
- _offset: Literal[8, 156392, 312776, 469160]
34
- _path: str | bytes
35
-
36
- def __init__(
37
- self,
38
- path: StrOrBytesPath,
39
- page: EditorPage,
40
- index: Annotated[
41
- SupportsIndex,
42
- Literal[
43
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
44
- ],
45
- ],
46
- ) -> None:
47
- index = ix(index) - 1
48
- if index in range(0, 20):
49
- self._offset = 8 + 156864 * (index & 3) # type: ignore[assignment]
50
- self._path = join(path, f"ed{(index >> 2) + 5 * page.value:02}.dat") # type: ignore[arg-type]
51
- else:
52
- raise ValueError("index must be between 1 and 20")
53
-
54
- def __bool__(self) -> bool:
55
- try:
56
- with open(self._path, "rb") as f:
57
- f.seek(self._offset)
58
- return f.read(1) != b"\x00"
59
- except FileNotFoundError:
60
- return False
61
-
62
- def __eq__(self, other: Any, /) -> bool:
63
- if isinstance(other, SaveSlot):
64
- return self._path == other._path and self._offset == other._offset
65
- else:
66
- return NotImplemented
67
-
68
- def __hash__(self) -> int:
69
- return hash((self._offset, self._path))
70
-
71
- @property
72
- def index(
73
- self,
74
- ) -> Literal[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]:
75
- return (int(basename(self._path)[2:4]) % 5 >> 2 | self._offset // 156864) + 1 # type: ignore[return-value]
76
-
77
- def load(self) -> Stage | None:
78
- try:
79
- with open(self._path, "rb") as f:
80
- f.seek(self._offset)
81
- with BytesIO() as b:
82
- block: bytearray = bytearray()
83
- while True:
84
- block.clear()
85
- f.readinto1(block)
86
- if len(b.getbuffer()) + len(block) > 156864:
87
- del block[156864 - len(b.getbuffer()) :]
88
- if block[-1]:
89
- b.write(block)
90
- else:
91
- while block:
92
- if block[len(block) >> 1]:
93
- b.write(block[: (len(block) >> 1) + 1])
94
- del block[: (len(block) >> 1) + 1]
95
- else:
96
- del block[len(block) >> 1 :]
97
- data: bytes = b.getvalue()
98
- if data:
99
- return XmlSlot.deserialize(data)
100
- else:
101
- return None
102
- except FileNotFoundError:
103
- return None
104
-
105
- @property
106
- def page(self) -> EditorPage:
107
- return EditorPage(int(basename(self._path)[2:4]) // 5)
108
-
109
- @property
110
- def path(self) -> StrOrBytesPath:
111
- return dirname(self._path)
112
-
113
- def __repr__(self) -> str:
114
- return f"{type(self).__name__}({self.path!r}, {self.page!r}, {self.index!r})"
115
-
116
- def save(self, data: Stage | None) -> None:
117
- binary: bytes = b"" if data is None else XmlSlot.serialize(data)
118
- if len(binary) > 156864:
119
- raise ValueError("serialized level data is too large to save")
120
- try:
121
- with open(self._path, "xb") as f:
122
- f.write(bytes(638976))
123
- if data is None:
124
- return
125
- except FileExistsError:
126
- pass
127
- with open(self._path, "r+b") as f:
128
- f.seek(self._offset)
129
- f.write(binary)
130
- f.write(bytes(156864 - len(binary)))
131
-
132
-
133
- def get_slots(save: StrOrBytesPath, /) -> Mapping[EditorPage, Sequence[SaveSlot]]:
134
- return {
135
- page: tuple(SaveSlot(save, page, i) for i in range(1, 21))
136
- for page in EditorPage
137
- }
1
+ from enum import Enum, unique
2
+ from io import BytesIO
3
+ from operator import index as ix
4
+ from os.path import basename, dirname, join
5
+ from typing import TYPE_CHECKING, Annotated, Any, Literal, SupportsIndex
6
+ from collections.abc import Mapping, Sequence
7
+
8
+ from ..stage import Stage
9
+
10
+ from . import Slot
11
+ from .xml import XmlSlot
12
+
13
+ if TYPE_CHECKING:
14
+ from _typeshed import StrOrBytesPath
15
+ else:
16
+ StrOrBytesPath = Any
17
+
18
+
19
+ __all__ = ["EditorPage", "get_slots", "SaveSlot"]
20
+
21
+
22
+ @unique
23
+ class EditorPage(Enum):
24
+ ORIGINAL = 0
25
+ FRIEND = 1
26
+ HUDSON = 2
27
+
28
+
29
+ class SaveSlot(Slot):
30
+ __match_args__ = ("path", "page", "index")
31
+ __slots__ = ("_offset", "_path")
32
+
33
+ _offset: Literal[8, 156392, 312776, 469160]
34
+ _path: str | bytes
35
+
36
+ def __init__(
37
+ self,
38
+ path: StrOrBytesPath,
39
+ page: EditorPage,
40
+ index: Annotated[
41
+ SupportsIndex,
42
+ Literal[
43
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
44
+ ],
45
+ ],
46
+ ) -> None:
47
+ index = ix(index) - 1
48
+ if index in range(0, 20):
49
+ self._offset = 8 + 156864 * (index & 3) # type: ignore[assignment]
50
+ self._path = join(path, f"ed{(index >> 2) + 5 * page.value:02}.dat") # type: ignore[arg-type]
51
+ else:
52
+ raise ValueError("index must be between 1 and 20")
53
+
54
+ def __bool__(self) -> bool:
55
+ try:
56
+ with open(self._path, "rb") as f:
57
+ f.seek(self._offset)
58
+ return f.read(1) != b"\x00"
59
+ except FileNotFoundError:
60
+ return False
61
+
62
+ def __eq__(self, other: Any, /) -> bool:
63
+ if isinstance(other, SaveSlot):
64
+ return self._path == other._path and self._offset == other._offset
65
+ else:
66
+ return NotImplemented
67
+
68
+ def __hash__(self) -> int:
69
+ return hash((self._offset, self._path))
70
+
71
+ @property
72
+ def index(
73
+ self,
74
+ ) -> Literal[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]:
75
+ return (int(basename(self._path)[2:4]) % 5 >> 2 | self._offset // 156864) + 1 # type: ignore[return-value]
76
+
77
+ def load(self) -> Stage | None:
78
+ try:
79
+ with open(self._path, "rb") as f:
80
+ f.seek(self._offset)
81
+ with BytesIO() as b:
82
+ block: bytearray = bytearray()
83
+ while True:
84
+ block.clear()
85
+ block.extend(f.read1())
86
+ print(block)
87
+ if len(b.getbuffer()) + len(block) > 156864:
88
+ del block[156864 - len(b.getbuffer()) :]
89
+ if block[-1]:
90
+ b.write(block)
91
+ else:
92
+ while block:
93
+ if block[len(block) >> 1]:
94
+ b.write(block[: (len(block) >> 1) + 1])
95
+ del block[: (len(block) >> 1) + 1]
96
+ else:
97
+ del block[len(block) >> 1 :]
98
+ data: bytes = b.getvalue()
99
+ if data:
100
+ return XmlSlot.deserialize(data)
101
+ else:
102
+ return None
103
+ except FileNotFoundError:
104
+ return None
105
+
106
+ @property
107
+ def page(self) -> EditorPage:
108
+ return EditorPage(int(basename(self._path)[2:4]) // 5)
109
+
110
+ @property
111
+ def path(self) -> StrOrBytesPath:
112
+ return dirname(self._path)
113
+
114
+ def __repr__(self) -> str:
115
+ return f"{type(self).__name__}({self.path!r}, {self.page!r}, {self.index!r})"
116
+
117
+ def save(self, data: Stage | None) -> None:
118
+ binary: bytes = b"" if data is None else XmlSlot.serialize(data)
119
+ if len(binary) > 156864:
120
+ raise ValueError("serialized stage data is too large to save")
121
+ try:
122
+ with open(self._path, "xb") as f:
123
+ f.write(bytes(638976))
124
+ if data is None:
125
+ return
126
+ except FileExistsError:
127
+ pass
128
+ with open(self._path, "r+b") as f:
129
+ f.seek(self._offset)
130
+ f.write(binary)
131
+ f.write(bytes(156864 - len(binary)))
132
+
133
+
134
+ def get_slots(save: StrOrBytesPath, /) -> Mapping[EditorPage, Sequence[SaveSlot]]:
135
+ return {
136
+ page: tuple(SaveSlot(save, page, i) for i in range(1, 21))
137
+ for page in EditorPage
138
+ }