koro 1.0.8__py3-none-any.whl → 1.1.0__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/file/__init__.py +4 -0
- koro/file/bin.py +178 -0
- koro/file/dir.py +28 -20
- koro/file/lvl.py +10 -2
- koro/file/zip.py +74 -27
- koro/item/__init__.py +3 -0
- koro/item/group.py +2 -0
- koro/item/level.py +9 -1
- koro/item/save.py +2 -0
- {koro-1.0.8.dist-info → koro-1.1.0.dist-info}/METADATA +1 -1
- koro-1.1.0.dist-info/RECORD +15 -0
- {koro-1.0.8.dist-info → koro-1.1.0.dist-info}/WHEEL +1 -1
- koro-1.0.8.dist-info/RECORD +0 -14
- {koro-1.0.8.dist-info → koro-1.1.0.dist-info}/LICENSE +0 -0
- {koro-1.0.8.dist-info → koro-1.1.0.dist-info}/top_level.txt +0 -0
koro/file/__init__.py
CHANGED
koro/file/bin.py
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
from itertools import chain
|
2
|
+
from typing import Final
|
3
|
+
|
4
|
+
from ..item.level import Level, LevelNotFoundError
|
5
|
+
from . import Location
|
6
|
+
|
7
|
+
__all__ = ["BinLevel", "BinLevelNotFoundError"]
|
8
|
+
|
9
|
+
|
10
|
+
class BinLevelNotFoundError(FileNotFoundError, LevelNotFoundError):
|
11
|
+
pass
|
12
|
+
|
13
|
+
|
14
|
+
class BinLevel(Location, Level):
|
15
|
+
__slots__ = ()
|
16
|
+
|
17
|
+
@staticmethod
|
18
|
+
def compress(data: bytes, /) -> bytes:
|
19
|
+
"""Compress the given level data into the game's format."""
|
20
|
+
buffer: bytearray = bytearray(1024)
|
21
|
+
buffer_index: int = 958
|
22
|
+
chunk: bytearray
|
23
|
+
data_index: int = 0
|
24
|
+
output: Final[bytearray] = bytearray(
|
25
|
+
b"\x00\x00\x00\x01\x00\x00\x00\x08"
|
26
|
+
+ len(data).to_bytes(4, byteorder="big")
|
27
|
+
+ b"\x00\x00\x00\x01"
|
28
|
+
)
|
29
|
+
reference_indices: list[int]
|
30
|
+
test_buffer: bytearray
|
31
|
+
test_length: int
|
32
|
+
test_reference_indicies: list[int]
|
33
|
+
while data_index < len(data):
|
34
|
+
chunk = bytearray(b"\x00")
|
35
|
+
for _ in range(8):
|
36
|
+
if data_index >= len(data):
|
37
|
+
output.extend(chunk)
|
38
|
+
return output
|
39
|
+
if len(data) - data_index <= 2:
|
40
|
+
buffer[buffer_index] = data[data_index]
|
41
|
+
buffer_index = buffer_index + 1 & 1023
|
42
|
+
chunk[0] = chunk[0] >> 1 | 128
|
43
|
+
chunk.append(data[data_index])
|
44
|
+
data_index += 1
|
45
|
+
continue
|
46
|
+
reference_indices = []
|
47
|
+
for i in chain(range(buffer_index, 1024), range(buffer_index)):
|
48
|
+
if data[data_index] == buffer[i]:
|
49
|
+
reference_indices.append(i)
|
50
|
+
if not reference_indices:
|
51
|
+
buffer[buffer_index] = data[data_index]
|
52
|
+
buffer_index = buffer_index + 1 & 1023
|
53
|
+
chunk[0] = chunk[0] >> 1 | 128
|
54
|
+
chunk.append(data[data_index])
|
55
|
+
data_index += 1
|
56
|
+
continue
|
57
|
+
test_buffer = buffer.copy()
|
58
|
+
test_buffer[buffer_index] = data[data_index]
|
59
|
+
for i in reference_indices.copy():
|
60
|
+
if data[data_index + 1] != test_buffer[i - 1023]:
|
61
|
+
reference_indices.remove(i)
|
62
|
+
if not reference_indices:
|
63
|
+
buffer[buffer_index] = data[data_index]
|
64
|
+
buffer_index = buffer_index + 1 & 1023
|
65
|
+
chunk[0] = chunk[0] >> 1 | 128
|
66
|
+
chunk.append(data[data_index])
|
67
|
+
data_index += 1
|
68
|
+
continue
|
69
|
+
test_buffer[buffer_index - 1023] = data[data_index + 1]
|
70
|
+
for i in reference_indices.copy():
|
71
|
+
if data[data_index + 2] != test_buffer[i - 1022]:
|
72
|
+
reference_indices.remove(i)
|
73
|
+
if not reference_indices:
|
74
|
+
buffer[buffer_index] = data[data_index]
|
75
|
+
buffer_index = buffer_index + 1 & 1023
|
76
|
+
chunk[0] = chunk[0] >> 1 | 128
|
77
|
+
chunk.append(data[data_index])
|
78
|
+
data_index += 1
|
79
|
+
continue
|
80
|
+
test_length = 4
|
81
|
+
test_reference_indicies = reference_indices.copy()
|
82
|
+
while test_length <= min(66, len(data) - data_index):
|
83
|
+
test_buffer[buffer_index + test_length - 1025] = data[
|
84
|
+
data_index + test_length - 1
|
85
|
+
]
|
86
|
+
for i in test_reference_indicies.copy():
|
87
|
+
if (
|
88
|
+
data[data_index + test_length - 1]
|
89
|
+
!= test_buffer[i + test_length - 1025]
|
90
|
+
):
|
91
|
+
test_reference_indicies.remove(i)
|
92
|
+
if test_reference_indicies:
|
93
|
+
reference_indices = test_reference_indicies.copy()
|
94
|
+
else:
|
95
|
+
break
|
96
|
+
test_length += 1
|
97
|
+
chunk[0] >>= 1
|
98
|
+
test_length -= 1
|
99
|
+
if buffer_index + test_length >= 1024:
|
100
|
+
buffer[buffer_index:] = data[
|
101
|
+
data_index : data_index + 1024 - buffer_index
|
102
|
+
]
|
103
|
+
buffer[: buffer_index + test_length - 1024] = data[
|
104
|
+
data_index + 1024 - buffer_index : data_index + test_length
|
105
|
+
]
|
106
|
+
else:
|
107
|
+
buffer[buffer_index : buffer_index + test_length] = data[
|
108
|
+
data_index : data_index + test_length
|
109
|
+
]
|
110
|
+
buffer_index = buffer_index + test_length & 1023
|
111
|
+
chunk.extend(
|
112
|
+
(
|
113
|
+
reference_indices[0] & 255,
|
114
|
+
reference_indices[0] >> 2 & 192 | test_length - 3,
|
115
|
+
)
|
116
|
+
)
|
117
|
+
data_index += test_length
|
118
|
+
output.extend(chunk)
|
119
|
+
return output + b"\x00"
|
120
|
+
|
121
|
+
@staticmethod
|
122
|
+
def decompress(data: bytes, /) -> bytes:
|
123
|
+
"""Decompress the given data into raw level data."""
|
124
|
+
buffer: Final[bytearray] = bytearray(1024)
|
125
|
+
buffer_index: int = 958
|
126
|
+
handle: int | bytearray
|
127
|
+
flags: int
|
128
|
+
offset: int
|
129
|
+
raw: Final[bytearray] = bytearray(data[:15:-1])
|
130
|
+
ref: bytes
|
131
|
+
result: Final[bytearray] = bytearray()
|
132
|
+
result_size: Final[int] = int.from_bytes(data[8:12], byteorder="big")
|
133
|
+
while len(result) < result_size:
|
134
|
+
flags = raw.pop()
|
135
|
+
for _ in range(8):
|
136
|
+
if flags & 1:
|
137
|
+
handle = raw.pop()
|
138
|
+
buffer[buffer_index] = handle
|
139
|
+
buffer_index = buffer_index + 1 & 1023
|
140
|
+
result.append(handle)
|
141
|
+
else:
|
142
|
+
if len(raw) < 2:
|
143
|
+
return result
|
144
|
+
ref = bytes((raw.pop() for _ in range(2)))
|
145
|
+
offset = (ref[1] << 2 & 768) + ref[0]
|
146
|
+
handle = bytearray()
|
147
|
+
for i in range((ref[1] & 63) + 3):
|
148
|
+
handle.append(buffer[offset + i - 1024])
|
149
|
+
buffer[buffer_index] = handle[-1]
|
150
|
+
buffer_index = buffer_index + 1 & 1023
|
151
|
+
result.extend(handle)
|
152
|
+
flags >>= 1
|
153
|
+
return result.replace(b"<EDITUSER> 3 </EDITUSER>", b"<EDITUSER> 2 </EDITUSER>")
|
154
|
+
|
155
|
+
def delete(self) -> None:
|
156
|
+
try:
|
157
|
+
return super().delete()
|
158
|
+
except FileNotFoundError as e:
|
159
|
+
raise BinLevelNotFoundError(*e.args)
|
160
|
+
|
161
|
+
def __len__(self) -> int:
|
162
|
+
try:
|
163
|
+
with open(self.path, "rb") as f:
|
164
|
+
f.seek(8)
|
165
|
+
return int.from_bytes(f.read(4), byteorder="big")
|
166
|
+
except FileNotFoundError as e:
|
167
|
+
BinLevelNotFoundError(*e.args)
|
168
|
+
|
169
|
+
def read(self) -> bytes:
|
170
|
+
try:
|
171
|
+
with open(self.path, "rb") as f:
|
172
|
+
return self.decompress(f.read())
|
173
|
+
except FileNotFoundError as e:
|
174
|
+
raise BinLevelNotFoundError(*e.args)
|
175
|
+
|
176
|
+
def write(self, new_content: bytes, /) -> None:
|
177
|
+
with open(self.path, "wb") as f:
|
178
|
+
f.write(self.compress(new_content))
|
koro/file/dir.py
CHANGED
@@ -7,14 +7,19 @@ from typing import Final, Optional, SupportsIndex, TypeGuard, overload
|
|
7
7
|
from ..item.group import Group
|
8
8
|
from ..item.level import Level, LevelNotFoundError
|
9
9
|
from ..item.save import Page, Save
|
10
|
-
|
11
10
|
from . import Location
|
12
11
|
|
12
|
+
__all__ = ["DirGroup", "DirLevel", "DirLevelNotFoundError", "DirSave"]
|
13
|
+
|
13
14
|
_BLOCK_SIZE: Final[int] = 2048
|
14
15
|
_EMPTY_BLOCK: Final[bytes] = b"\x00" * _BLOCK_SIZE
|
15
16
|
_LEVEL_ALLOCATION_SIZE: Final[int] = 156864
|
16
17
|
|
17
18
|
|
19
|
+
class DirLevelNotFoundError(LevelNotFoundError):
|
20
|
+
pass
|
21
|
+
|
22
|
+
|
18
23
|
class DirLevel(Level):
|
19
24
|
__match_args__ = ("path", "page", "id")
|
20
25
|
__slots__ = ("_offset", "_path")
|
@@ -45,7 +50,7 @@ class DirLevel(Level):
|
|
45
50
|
f.write(_EMPTY_BLOCK)
|
46
51
|
more = f.read(1) != b"\x00"
|
47
52
|
else:
|
48
|
-
raise
|
53
|
+
raise DirLevelNotFoundError
|
49
54
|
|
50
55
|
def __eq__(self, other: object, /) -> bool:
|
51
56
|
return (
|
@@ -62,23 +67,26 @@ class DirLevel(Level):
|
|
62
67
|
return int(self._path[-5]) % 5 << 2 | self._offset // _LEVEL_ALLOCATION_SIZE
|
63
68
|
|
64
69
|
def __len__(self) -> int:
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
70
|
+
if self:
|
71
|
+
with open(self._path, "rb") as f:
|
72
|
+
f.seek(self._offset)
|
73
|
+
block: Final[bytearray] = bytearray(f.read(_BLOCK_SIZE))
|
74
|
+
block_offset: int = 0
|
75
|
+
while block[-1]:
|
76
|
+
f.readinto(block)
|
77
|
+
block_offset += _BLOCK_SIZE
|
78
|
+
hi: int = _BLOCK_SIZE - 1
|
79
|
+
lo: int = 0
|
80
|
+
test: int
|
81
|
+
while hi != lo:
|
82
|
+
test = (hi - lo >> 1) + lo
|
83
|
+
if block[test]:
|
84
|
+
lo = test + 1
|
85
|
+
else:
|
86
|
+
hi = test
|
87
|
+
return block_offset + hi
|
88
|
+
else:
|
89
|
+
raise DirLevelNotFoundError
|
82
90
|
|
83
91
|
@property
|
84
92
|
def page(self) -> Page:
|
@@ -108,7 +116,7 @@ class DirLevel(Level):
|
|
108
116
|
hi = test
|
109
117
|
return bytes(result + block[:hi])
|
110
118
|
else:
|
111
|
-
raise
|
119
|
+
raise DirLevelNotFoundError
|
112
120
|
|
113
121
|
def __repr__(self) -> str:
|
114
122
|
return f"{type(self).__name__}({self.path!r}, {self.page!r}, {self.id!r})"
|
koro/file/lvl.py
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
from os.path import getsize
|
2
|
+
from warnings import warn
|
2
3
|
|
3
4
|
from ..item.level import Level, LevelNotFoundError
|
4
|
-
|
5
5
|
from . import Location
|
6
6
|
|
7
|
-
__all__ = ["LvlLevel"]
|
7
|
+
__all__ = ["LvlLevel", "LvlLevelNotFoundError"]
|
8
8
|
|
9
9
|
|
10
10
|
class LvlLevelNotFoundError(FileNotFoundError, LevelNotFoundError):
|
@@ -14,6 +14,14 @@ class LvlLevelNotFoundError(FileNotFoundError, LevelNotFoundError):
|
|
14
14
|
class LvlLevel(Location, Level):
|
15
15
|
__slots__ = ()
|
16
16
|
|
17
|
+
def __init__(self, path: str, /) -> None:
|
18
|
+
super().__init__(path)
|
19
|
+
warn(
|
20
|
+
FutureWarning(
|
21
|
+
"The LVL format for storing level data is deprecated. Level data should be converted to the BIN format using BinLevel for better compression and compatibility."
|
22
|
+
)
|
23
|
+
)
|
24
|
+
|
17
25
|
def delete(self) -> None:
|
18
26
|
try:
|
19
27
|
return super().delete()
|
koro/file/zip.py
CHANGED
@@ -4,17 +4,22 @@ from operator import index
|
|
4
4
|
from os.path import abspath
|
5
5
|
from re import fullmatch
|
6
6
|
from typing import Final, Optional, SupportsIndex, TypeGuard, overload
|
7
|
+
from warnings import warn
|
7
8
|
from zipfile import ZipFile, ZipInfo
|
8
9
|
|
9
10
|
from ..item.group import Group
|
10
11
|
from ..item.level import Level, LevelNotFoundError
|
11
|
-
|
12
12
|
from . import Location
|
13
|
+
from .bin import BinLevel
|
13
14
|
|
14
|
-
__all__ = ["ZipGroup", "ZipLevel"]
|
15
|
+
__all__ = ["ZipGroup", "ZipLevel", "ZipLevelNotFoundError"]
|
15
16
|
|
16
17
|
|
17
18
|
def _id_to_fn(id: SupportsIndex, /) -> str:
|
19
|
+
return f"{str(index(id) + 1).zfill(2)}.bin"
|
20
|
+
|
21
|
+
|
22
|
+
def _id_to_old_fn(id: SupportsIndex, /) -> str:
|
18
23
|
return f"{str(index(id) + 1).zfill(2)}.lvl"
|
19
24
|
|
20
25
|
|
@@ -43,11 +48,12 @@ class ZipLevel(Level):
|
|
43
48
|
|
44
49
|
def delete(self) -> None:
|
45
50
|
with ZipFile(self.path) as a:
|
46
|
-
if self.fn not in a.namelist():
|
51
|
+
if self.fn not in a.namelist() and self.old_fn not in a.namelist():
|
47
52
|
raise ZipLevelNotFoundError
|
48
53
|
contents: Final[dict[ZipInfo, bytes]] = {}
|
49
54
|
for info in filterfalse(
|
50
|
-
lambda info: info.filename == self.fn
|
55
|
+
lambda info: info.filename == self.fn or info.filename == self.old_fn,
|
56
|
+
a.infolist(),
|
51
57
|
):
|
52
58
|
contents[info] = a.read(info)
|
53
59
|
with ZipFile(self.path, "w") as a:
|
@@ -73,22 +79,38 @@ class ZipLevel(Level):
|
|
73
79
|
return self._id
|
74
80
|
|
75
81
|
def __len__(self) -> int:
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
82
|
+
with ZipFile(self.path) as a:
|
83
|
+
try:
|
84
|
+
a.getinfo(self.fn)
|
85
|
+
except KeyError:
|
86
|
+
try:
|
87
|
+
return a.getinfo(self.old_fn).file_size
|
88
|
+
except KeyError:
|
89
|
+
raise ZipLevelNotFoundError
|
90
|
+
else:
|
91
|
+
return int.from_bytes(a.read(self.fn)[8:12], byteorder="big")
|
92
|
+
|
93
|
+
@property
|
94
|
+
def old_fn(self) -> str:
|
95
|
+
return _id_to_old_fn(self.id)
|
81
96
|
|
82
97
|
@property
|
83
98
|
def path(self) -> str:
|
84
99
|
return self._path
|
85
100
|
|
86
101
|
def read(self) -> bytes:
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
102
|
+
with ZipFile(self.path) as a:
|
103
|
+
try:
|
104
|
+
a.getinfo(self.fn)
|
105
|
+
except KeyError:
|
106
|
+
try:
|
107
|
+
a.getinfo(self.old_fn)
|
108
|
+
except KeyError:
|
109
|
+
raise ZipLevelNotFoundError
|
110
|
+
else:
|
111
|
+
return a.read(self.old_fn)
|
112
|
+
else:
|
113
|
+
return BinLevel.decompress(a.read(self.fn))
|
92
114
|
|
93
115
|
def __repr__(self) -> str:
|
94
116
|
return f"{type(self).__name__}({self.path!r}, {self.id!r})"
|
@@ -97,18 +119,31 @@ class ZipLevel(Level):
|
|
97
119
|
contents: Final[dict[ZipInfo, bytes]] = {}
|
98
120
|
with ZipFile(self.path, "a") as a:
|
99
121
|
for info in filterfalse(
|
100
|
-
lambda info: info.filename == self.fn
|
122
|
+
lambda info: info.filename == self.fn or info.filename == self.old_fn,
|
123
|
+
a.infolist(),
|
101
124
|
):
|
102
125
|
contents[info] = a.read(info)
|
103
126
|
with ZipFile(self.path, "w") as a:
|
104
127
|
for x in contents.items():
|
105
128
|
a.writestr(*x)
|
106
|
-
a.writestr(self.fn, new_content)
|
129
|
+
a.writestr(self.fn, BinLevel.compress(new_content))
|
107
130
|
|
108
131
|
|
109
|
-
class ZipGroup(Group[ZipLevel]
|
132
|
+
class ZipGroup(Location, Group[ZipLevel]):
|
110
133
|
__slots__ = ()
|
111
134
|
|
135
|
+
def __init__(self, path: str) -> None:
|
136
|
+
super().__init__(path)
|
137
|
+
with ZipFile(self.path) as a:
|
138
|
+
for id in range(20):
|
139
|
+
if _id_to_old_fn(id) in a.namelist():
|
140
|
+
warn(
|
141
|
+
FutureWarning(
|
142
|
+
"This ZipGroup contains levels using the deprecated LVL format. Update this file by writing to it or by using the update function."
|
143
|
+
)
|
144
|
+
)
|
145
|
+
break
|
146
|
+
|
112
147
|
def __contains__(self, value: object, /) -> TypeGuard[ZipLevel]:
|
113
148
|
return isinstance(value, ZipLevel) and value.path == self.path
|
114
149
|
|
@@ -139,28 +174,40 @@ class ZipGroup(Group[ZipLevel], Location):
|
|
139
174
|
else:
|
140
175
|
raise ValueError
|
141
176
|
|
142
|
-
def init(self) -> None:
|
143
|
-
with ZipFile(self.path, "x") as a:
|
144
|
-
pass
|
145
|
-
|
146
177
|
def fill_mask(self) -> Sequence[bool]:
|
147
178
|
with ZipFile(self.path) as a:
|
148
|
-
return [
|
179
|
+
return [
|
180
|
+
_id_to_fn(i) in a.namelist() or _id_to_old_fn in a.namelist()
|
181
|
+
for i in range(20)
|
182
|
+
]
|
149
183
|
|
150
184
|
def read(self) -> Iterable[Optional[bytes]]:
|
151
185
|
with ZipFile(self.path) as a:
|
152
|
-
name_list: Final[list[str]] = a.namelist()
|
153
186
|
return [
|
154
|
-
a.read(
|
155
|
-
|
187
|
+
BinLevel.decompress(a.read(_id_to_fn(id)))
|
188
|
+
if _id_to_fn(id) in a.namelist()
|
189
|
+
else a.read(_id_to_old_fn(id))
|
190
|
+
if _id_to_old_fn(id) in a.namelist()
|
191
|
+
else None
|
192
|
+
for id in range(20)
|
156
193
|
]
|
157
194
|
|
195
|
+
def update(self) -> None:
|
196
|
+
self.write(self.read())
|
197
|
+
warn(
|
198
|
+
FutureWarning(
|
199
|
+
"This function will be removed alongside support for the LVL format, and exists soley as a convienient way of converting existing ZIP files to the new BIN format."
|
200
|
+
)
|
201
|
+
)
|
202
|
+
|
158
203
|
def write(self, new_content: Iterable[Optional[bytes]], /) -> None:
|
159
204
|
contents: Final[dict[ZipInfo, bytes]] = {}
|
160
205
|
if self:
|
161
206
|
with ZipFile(self.path) as a:
|
162
207
|
for info in filterfalse(
|
163
|
-
lambda info: fullmatch(
|
208
|
+
lambda info: fullmatch(
|
209
|
+
r"(0[1-9]|1\d|20)\.(bin|lvl)", info.filename
|
210
|
+
),
|
164
211
|
a.infolist(),
|
165
212
|
):
|
166
213
|
contents[info] = a.read(info)
|
@@ -170,4 +217,4 @@ class ZipGroup(Group[ZipLevel], Location):
|
|
170
217
|
for id, content in filterfalse(
|
171
218
|
lambda x: x[1] is None, enumerate(new_content)
|
172
219
|
):
|
173
|
-
a.writestr(_id_to_fn(id), content)
|
220
|
+
a.writestr(_id_to_fn(id), BinLevel.compress(content))
|
koro/item/__init__.py
CHANGED
koro/item/group.py
CHANGED
koro/item/level.py
CHANGED
@@ -3,6 +3,9 @@ from collections.abc import Sized
|
|
3
3
|
from dataclasses import dataclass
|
4
4
|
from enum import Enum, unique
|
5
5
|
from typing import Final
|
6
|
+
from warnings import warn
|
7
|
+
|
8
|
+
__all__ = ["Level", "LevelNotFoundError", "LevelStatistics", "Theme"]
|
6
9
|
|
7
10
|
|
8
11
|
@unique
|
@@ -73,10 +76,15 @@ class Level(ABC, Sized):
|
|
73
76
|
|
74
77
|
def encode(self) -> bytes:
|
75
78
|
"""Return a bytes object that when written to a file can overwrite an official level."""
|
79
|
+
warn(
|
80
|
+
FutureWarning(
|
81
|
+
"The use of this function is deprecated as the new BIN format is compatible with the official levels and can be substituted into the game directly."
|
82
|
+
)
|
83
|
+
)
|
76
84
|
data: Final[bytearray] = bytearray(self.read())
|
77
85
|
header: Final[bytes] = (
|
78
86
|
b"\x00\x00\x00\x01\x00\x00\x00\x08"
|
79
|
-
+ len(data).to_bytes(4, "big")
|
87
|
+
+ len(data).to_bytes(4, byteorder="big")
|
80
88
|
+ b"\x00\x00\x00\x01"
|
81
89
|
)
|
82
90
|
i: int = 0
|
koro/item/save.py
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
koro/__init__.py,sha256=clmcgzd33gY_tOC3U5U-010NYVZZrC-9Og6AYAovIjo,176
|
2
|
+
koro/file/__init__.py,sha256=rrsPxeKSG6WXprbO-xDZR1E9GdQ2xuzPvoZ08C3QSQc,1038
|
3
|
+
koro/file/bin.py,sha256=2rV6BQN-6HH-ilV8WpInI5xWjds9Mo3_4kzQLEDPmqU,7482
|
4
|
+
koro/file/dir.py,sha256=pnMQJAQRlzcm_MC14goDeKlQ3llKhywM1FdADHM8xds,6632
|
5
|
+
koro/file/lvl.py,sha256=lrVpQyZFj1JlVPYx-OkcCne8VdjHCWQIuOX0pls1Dto,1130
|
6
|
+
koro/file/zip.py,sha256=hFV3rnro0pTeg7mpoKEvQnO-Oo93_DgnxJQCJupkVI8,7332
|
7
|
+
koro/item/__init__.py,sha256=3RXQS-HSN6EDGLk6sY4xip-oy8JiV31XshsCWVCgie8,65
|
8
|
+
koro/item/group.py,sha256=lwmx_1FMD4LdOxxuqPDN2Dl_8MZD9OJcy259SS8Apzk,1538
|
9
|
+
koro/item/level.py,sha256=KXiOK3RGC72WK4lduf3RO9Cs1zXaJRk0EfJCDndA4bs,3068
|
10
|
+
koro/item/save.py,sha256=LUV79vW3gY__jVVVG1kcYW-wzsGCRlYq126nulbT37Y,607
|
11
|
+
koro-1.1.0.dist-info/LICENSE,sha256=Q2ptU2E48gOsMzhYz_kqVovmJ5d1KzrblLyqD2_-fvY,1235
|
12
|
+
koro-1.1.0.dist-info/METADATA,sha256=5Tt71Gav-Itj_GMxWkdYMaMCxssxWLpHmqiRxdfojY0,628
|
13
|
+
koro-1.1.0.dist-info/WHEEL,sha256=5sUXSg9e4bi7lTLOHcm6QEYwO5TIF1TNbTSVFVjcJcc,92
|
14
|
+
koro-1.1.0.dist-info/top_level.txt,sha256=Msq6ssMwv56hnBQqwaTdJJkxM7x7BZ-3JfQbkepQAEY,5
|
15
|
+
koro-1.1.0.dist-info/RECORD,,
|
koro-1.0.8.dist-info/RECORD
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
koro/__init__.py,sha256=clmcgzd33gY_tOC3U5U-010NYVZZrC-9Og6AYAovIjo,176
|
2
|
-
koro/file/__init__.py,sha256=_UIx5h1YBoheqQeorBV5XrbZXusAOipbFsesqUeLJwk,948
|
3
|
-
koro/file/dir.py,sha256=sxNM_COlADES3oVnlutApXPd2SvWuANRnxMC6RdQ448,6348
|
4
|
-
koro/file/lvl.py,sha256=cxOJGuzzs3yVTAdi-clhXPn1A7-TU3p-FJW3JLZBTyY,752
|
5
|
-
koro/file/zip.py,sha256=hK8XemvmM3dhyNPevCt9lXm0p24HYbzyHp40yA5O5cg,5472
|
6
|
-
koro/item/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
-
koro/item/group.py,sha256=TfiC2okh-fIVPics7VxOWEIP3-8K0ixDBIOl9yTjBkE,1515
|
8
|
-
koro/item/level.py,sha256=opGy-JnytnsXGYEZDQky9bTwAr_oJFq1mrQsOAr6pOs,2723
|
9
|
-
koro/item/save.py,sha256=vwI2b1iUs976ZgTIt3hFxpJajGrGZugDhUxkS7Zl4SE,577
|
10
|
-
koro-1.0.8.dist-info/LICENSE,sha256=Q2ptU2E48gOsMzhYz_kqVovmJ5d1KzrblLyqD2_-fvY,1235
|
11
|
-
koro-1.0.8.dist-info/METADATA,sha256=Vg519VHrxWxDCrFoTmEnBLtQbTXeflX7UvIvmmS-qfA,628
|
12
|
-
koro-1.0.8.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
|
13
|
-
koro-1.0.8.dist-info/top_level.txt,sha256=Msq6ssMwv56hnBQqwaTdJJkxM7x7BZ-3JfQbkepQAEY,5
|
14
|
-
koro-1.0.8.dist-info/RECORD,,
|
File without changes
|
File without changes
|