koro 1.0.4__py3-none-any.whl → 1.0.6__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/zip.py CHANGED
@@ -95,7 +95,7 @@ class ZipLevel(Level):
95
95
 
96
96
  def write(self, new_content: bytes, /) -> None:
97
97
  contents: Final[dict[ZipInfo, bytes]] = {}
98
- with ZipFile(self.path) as a:
98
+ with ZipFile(self.path, "r+") as a:
99
99
  for info in filterfalse(
100
100
  lambda info: info.filename == self.fn, a.infolist()
101
101
  ):
@@ -1,16 +1,16 @@
1
- Metadata-Version: 2.1
2
- Name: koro
3
- Version: 1.0.4
4
- Summary: Tools for manipulating levels made in Marble Saga: Kororinpa
5
- Home-page: https://github.com/DigitalDetective47/koro
6
- Author: DigitalDetective47
7
- Author-email: ninji2701@gmail.com
8
- Project-URL: Bug Tracker, https://github.com/DigitalDetective47/koro/issues
9
- Classifier: Development Status :: 5 - Production/Stable
10
- Classifier: License :: OSI Approved :: The Unlicense (Unlicense)
11
- Classifier: Operating System :: OS Independent
12
- Classifier: Programming Language :: Python :: 3
13
- Classifier: Topic :: Games/Entertainment
14
- Requires-Python: >=3.9
15
- License-File: LICENSE
16
-
1
+ Metadata-Version: 2.1
2
+ Name: koro
3
+ Version: 1.0.6
4
+ Summary: Tools for manipulating levels made in Marble Saga: Kororinpa
5
+ Home-page: https://github.com/DigitalDetective47/koro
6
+ Author: DigitalDetective47
7
+ Author-email: ninji2701@gmail.com
8
+ Project-URL: Bug Tracker, https://github.com/DigitalDetective47/koro/issues
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: License :: OSI Approved :: The Unlicense (Unlicense)
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Topic :: Games/Entertainment
14
+ Requires-Python: >=3.9
15
+ License-File: LICENSE
16
+
@@ -0,0 +1,10 @@
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=YtVOOogOBBM0q2Wq24WJif4AlQRxQgJ1rI6zhaBTA6g,5473
6
+ koro-1.0.6.dist-info/LICENSE,sha256=Q2ptU2E48gOsMzhYz_kqVovmJ5d1KzrblLyqD2_-fvY,1235
7
+ koro-1.0.6.dist-info/METADATA,sha256=uzRQWhxWVFp7mP6QfZfj5PcdJD5G8t0JUqYBGk-ZxBo,628
8
+ koro-1.0.6.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
9
+ koro-1.0.6.dist-info/top_level.txt,sha256=Msq6ssMwv56hnBQqwaTdJJkxM7x7BZ-3JfQbkepQAEY,5
10
+ koro-1.0.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.37.1)
2
+ Generator: bdist_wheel (0.38.4)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
koro/item/__init__.py DELETED
File without changes
koro/item/group.py DELETED
@@ -1,42 +0,0 @@
1
- from abc import ABC
2
- from collections.abc import Iterable, Sequence
3
- from itertools import filterfalse
4
- from typing import Final, Generic, Optional, TypeVar
5
-
6
- from .level import Level, LevelNotFoundError
7
-
8
- _L = TypeVar("_L", bound=Level)
9
-
10
-
11
- class Group(ABC, Generic[_L], Sequence[_L]):
12
- """A group of 20 levels.
13
- Note that levels are 0-indexed within this interface, but 1-indexed in-game.
14
- """
15
-
16
- __slots__ = ()
17
-
18
- def fill_mask(self) -> Sequence[bool]:
19
- """Return which level IDs within this set exist."""
20
- return [bool(l) for l in self]
21
-
22
- def __len__(self) -> int:
23
- return 20
24
-
25
- def read(self) -> Iterable[Optional[bytes]]:
26
- """Read all of the levels within this Group. Empty slots yield None."""
27
- content: Optional[bytes]
28
- result: Final[list[Optional[bytes]]] = []
29
- for level in self:
30
- try:
31
- content = level.read()
32
- except LevelNotFoundError:
33
- content = None
34
- result.append(content)
35
- return result
36
-
37
- def write(self, new_content: Iterable[Optional[bytes]], /) -> None:
38
- """Replace the contents of this Group with the specified new content. None values will empty the slot they correspond to."""
39
- for src, dest in filterfalse(
40
- lambda x: x[0] is None, zip(new_content, self, strict=True)
41
- ):
42
- dest.write(src)
koro/item/level.py DELETED
@@ -1,100 +0,0 @@
1
- from abc import ABC, abstractmethod
2
- from collections.abc import Sized
3
- from dataclasses import dataclass
4
- from enum import Enum, unique
5
- from typing import Final
6
-
7
-
8
- @unique
9
- class Theme(Enum):
10
- THE_EMPTY_LOT = 0
11
- NEIGHBORS_HOUSE = 1
12
- SIZZLIN_DESERT = 2
13
- CHILL_MOUNTAIN = 3
14
- OCEAN_TREASURE = 4
15
- SPACE_STATION = 5
16
- STUMP_TEMPLE = 6
17
- CANDY_ISLAND = 7
18
- HAUNTED_HOUSE = 8
19
- CITY = 9
20
- TUTORIAL = 11
21
- HAUNTED_HOUSE_DARKNESS = 12
22
- NIGHT_CITY = 13
23
-
24
- def __str__(self) -> str:
25
- return (
26
- "The Empty Lot",
27
- "Neighbor's House",
28
- "Sizzlin' Desert",
29
- "Chill Mountain",
30
- "Ocean Treasure",
31
- "Space Station",
32
- "Stump Temple",
33
- "Candy Island",
34
- "Haunted House",
35
- "City",
36
- None,
37
- "Tutorial",
38
- "Haunted House Darkness",
39
- "Night City",
40
- )[self.value]
41
-
42
-
43
- @dataclass(frozen=True, match_args=False, kw_only=True, slots=True)
44
- class LevelStatistics:
45
- crystals: int
46
- filesize: int
47
- theme: Theme
48
-
49
-
50
- class LevelNotFoundError(LookupError):
51
- pass
52
-
53
-
54
- class Level(ABC, Sized):
55
- __slots__ = ()
56
-
57
- def about(self) -> LevelStatistics:
58
- content: Final[bytes] = self.read()
59
- return LevelStatistics(
60
- crystals=content.count(b"<anmtype> 49 </anmtype>"),
61
- filesize=len(content),
62
- theme=Theme(int(content[87:89])),
63
- )
64
-
65
- @abstractmethod
66
- def __bool__(self) -> bool:
67
- """Return whether this level exists."""
68
-
69
- @abstractmethod
70
- def delete(self) -> None:
71
- """Delete this level if it exists, otherwise raise LevelNotFoundError."""
72
- pass
73
-
74
- def encode(self) -> bytes:
75
- """Return a bytes object that when written to a file can overwrite an official level."""
76
- data: Final[bytearray] = bytearray(self.read())
77
- header: Final[bytes] = (
78
- b"\x00\x00\x00\x01\x00\x00\x00\x08"
79
- + len(data).to_bytes(4, "big")
80
- + b"\x00\x00\x00\x01"
81
- )
82
- i: int = 0
83
- while i < len(data):
84
- data.insert(i, 255)
85
- i += 9
86
- return header + data + b"\x00"
87
-
88
- def __len__(self) -> int:
89
- """The file size of this level."""
90
- return len(self.read())
91
-
92
- @abstractmethod
93
- def read(self) -> bytes:
94
- """Return the contents of this level if it exists, otherwise raise LevelNotFoundError."""
95
- pass
96
-
97
- @abstractmethod
98
- def write(self, new_content: bytes, /) -> None:
99
- """Replace the contents of this level, or create it if it doesn't exist."""
100
- pass
koro/item/save.py DELETED
@@ -1,27 +0,0 @@
1
- from abc import ABC
2
- from collections.abc import Iterator, Mapping
3
- from enum import Enum, unique
4
- from typing import Generic, TypeGuard, TypeVar
5
-
6
- from .group import Group
7
-
8
- _G = TypeVar("_G", bound=Group)
9
-
10
-
11
- @unique
12
- class Page(Enum):
13
- ORIGINAL = 0
14
- FRIEND = 1
15
-
16
-
17
- class Save(ABC, Generic[_G], Mapping[Page, _G]):
18
- __slots__ = ()
19
-
20
- def __contains__(self, key: object, /) -> TypeGuard[Page]:
21
- return isinstance(key, Page)
22
-
23
- def __iter__(self) -> Iterator[Page]:
24
- return iter(Page)
25
-
26
- def __len__(self) -> int:
27
- return 2
@@ -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=N7SqLRHSykv5qYgV0tlo814KqpvRQ95lBUateYKwgqE,5467
6
- koro/item/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- koro/item/group.py,sha256=T2dgb1jmLTaiKcdgfDCZ7x9jwBYe8dk_1hRUqKAkWd0,1430
8
- koro/item/level.py,sha256=opGy-JnytnsXGYEZDQky9bTwAr_oJFq1mrQsOAr6pOs,2723
9
- koro/item/save.py,sha256=vwI2b1iUs976ZgTIt3hFxpJajGrGZugDhUxkS7Zl4SE,577
10
- koro-1.0.4.dist-info/LICENSE,sha256=Q2ptU2E48gOsMzhYz_kqVovmJ5d1KzrblLyqD2_-fvY,1235
11
- koro-1.0.4.dist-info/METADATA,sha256=-38RPmFchNe3oiYB0_JxAzp1ngsSBDW9Hq9jg_BDP0c,612
12
- koro-1.0.4.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
13
- koro-1.0.4.dist-info/top_level.txt,sha256=Msq6ssMwv56hnBQqwaTdJJkxM7x7BZ-3JfQbkepQAEY,5
14
- koro-1.0.4.dist-info/RECORD,,
File without changes