Core: prepare worlds.Files for APWorldContainer (#4331)

Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
This commit is contained in:
Fabian Dill
2025-05-20 23:55:16 +02:00
committed by GitHub
parent e0d3101066
commit 9adbd4031f
3 changed files with 45 additions and 27 deletions

View File

@@ -78,24 +78,15 @@ class InvalidDataError(Exception):
class APContainer:
"""A zipfile containing at least archipelago.json"""
version: int = container_version
compression_level: int = 9
compression_method: int = zipfile.ZIP_DEFLATED
game: Optional[str] = None
"""A zipfile containing at least archipelago.json, which contains a manifest json payload."""
version: ClassVar[int] = container_version
compression_level: ClassVar[int] = 9
compression_method: ClassVar[int] = zipfile.ZIP_DEFLATED
# instance attributes:
path: Optional[str]
player: Optional[int]
player_name: str
server: str
def __init__(self, path: Optional[str] = None, player: Optional[int] = None,
player_name: str = "", server: str = ""):
def __init__(self, path: Optional[str] = None):
self.path = path
self.player = player
self.player_name = player_name
self.server = server
def write(self, file: Optional[Union[str, BinaryIO]] = None) -> None:
zip_file = file if file else self.path
@@ -135,31 +126,58 @@ class APContainer:
message = f"{arg0} - "
raise InvalidDataError(f"{message}This might be the incorrect world version for this file") from e
def read_contents(self, opened_zipfile: zipfile.ZipFile) -> None:
def read_contents(self, opened_zipfile: zipfile.ZipFile) -> Dict[str, Any]:
with opened_zipfile.open("archipelago.json", "r") as f:
manifest = json.load(f)
if manifest["compatible_version"] > self.version:
raise Exception(f"File (version: {manifest['compatible_version']}) too new "
f"for this handler (version: {self.version})")
self.player = manifest["player"]
self.server = manifest["server"]
self.player_name = manifest["player_name"]
return manifest
def get_manifest(self) -> Dict[str, Any]:
return {
"server": self.server, # allow immediate connection to server in multiworld. Empty string otherwise
"player": self.player,
"player_name": self.player_name,
"game": self.game,
# minimum version of patch system expected for patching to be successful
"compatible_version": 5,
"version": container_version,
}
class APPatch(APContainer):
class APPlayerContainer(APContainer):
"""A zipfile containing at least archipelago.json meant for a player"""
game: ClassVar[Optional[str]] = None
player: Optional[int]
player_name: str
server: str
def __init__(self, path: Optional[str] = None, player: Optional[int] = None,
player_name: str = "", server: str = ""):
super().__init__(path)
self.player = player
self.player_name = player_name
self.server = server
def read_contents(self, opened_zipfile: zipfile.ZipFile) -> Dict[str, Any]:
manifest = super().read_contents(opened_zipfile)
self.player = manifest["player"]
self.server = manifest["server"]
self.player_name = manifest["player_name"]
return manifest
def get_manifest(self) -> Dict[str, Any]:
manifest = super().get_manifest()
manifest.update({
"server": self.server, # allow immediate connection to server in multiworld. Empty string otherwise
"player": self.player,
"player_name": self.player_name,
"game": self.game,
})
return manifest
class APPatch(APPlayerContainer):
"""
An `APContainer` that represents a patch file.
An `APPlayerContainer` that represents a patch file.
It includes the `procedure` key in the manifest to indicate that it is a patch.
Your implementation should inherit from this if your output file

View File

@@ -63,7 +63,7 @@ recipe_time_ranges = {
}
class FactorioModFile(worlds.Files.APContainer):
class FactorioModFile(worlds.Files.APPlayerContainer):
game = "Factorio"
compression_method = zipfile.ZIP_DEFLATED # Factorio can't load LZMA archives
writing_tasks: List[Callable[[], Tuple[str, Union[str, bytes]]]]

View File

@@ -8,10 +8,10 @@ import zipfile
from .Items import item_dictionary_table
from .Locations import all_locations, SoraLevels, exclusion_table
from .XPValues import lvlStats, formExp, soraExp
from worlds.Files import APContainer
from worlds.Files import APPlayerContainer
class KH2Container(APContainer):
class KH2Container(APPlayerContainer):
game: str = 'Kingdom Hearts 2'
def __init__(self, patch_data: dict, base_path: str, output_directory: str,