Core: add layer for patches that don't use `Patch.py` (#2889)
* Core: add layer for patches that don't use `Patch.py` * bump container version * APAutoPatchInterface name * mystic quest change * OoT and Adventure changes * missed name in docstring * container version compatibility
This commit is contained in:
parent
fa233b2583
commit
e534abeab0
4
Patch.py
4
Patch.py
|
@ -8,7 +8,7 @@ if __name__ == "__main__":
|
||||||
import ModuleUpdate
|
import ModuleUpdate
|
||||||
ModuleUpdate.update()
|
ModuleUpdate.update()
|
||||||
|
|
||||||
from worlds.Files import AutoPatchRegister, APPatch
|
from worlds.Files import AutoPatchRegister, APAutoPatchInterface
|
||||||
|
|
||||||
|
|
||||||
class RomMeta(TypedDict):
|
class RomMeta(TypedDict):
|
||||||
|
@ -20,7 +20,7 @@ class RomMeta(TypedDict):
|
||||||
def create_rom_file(patch_file: str) -> Tuple[RomMeta, str]:
|
def create_rom_file(patch_file: str) -> Tuple[RomMeta, str]:
|
||||||
auto_handler = AutoPatchRegister.get_handler(patch_file)
|
auto_handler = AutoPatchRegister.get_handler(patch_file)
|
||||||
if auto_handler:
|
if auto_handler:
|
||||||
handler: APPatch = auto_handler(patch_file)
|
handler: APAutoPatchInterface = auto_handler(patch_file)
|
||||||
target = os.path.splitext(patch_file)[0]+handler.result_file_ending
|
target = os.path.splitext(patch_file)[0]+handler.result_file_ending
|
||||||
handler.patch(target)
|
handler.patch(target)
|
||||||
return {"server": handler.server,
|
return {"server": handler.server,
|
||||||
|
|
|
@ -6,7 +6,7 @@ import zipfile
|
||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from typing import ClassVar, Dict, Tuple, Any, Optional, Union, BinaryIO
|
from typing import ClassVar, Dict, List, Literal, Tuple, Any, Optional, Union, BinaryIO
|
||||||
|
|
||||||
import bsdiff4
|
import bsdiff4
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ class AutoPatchRegister(abc.ABCMeta):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
current_patch_version: int = 5
|
container_version: int = 6
|
||||||
|
|
||||||
|
|
||||||
class InvalidDataError(Exception):
|
class InvalidDataError(Exception):
|
||||||
|
@ -50,7 +50,7 @@ class InvalidDataError(Exception):
|
||||||
|
|
||||||
class APContainer:
|
class APContainer:
|
||||||
"""A zipfile containing at least archipelago.json"""
|
"""A zipfile containing at least archipelago.json"""
|
||||||
version: int = current_patch_version
|
version: int = container_version
|
||||||
compression_level: int = 9
|
compression_level: int = 9
|
||||||
compression_method: int = zipfile.ZIP_DEFLATED
|
compression_method: int = zipfile.ZIP_DEFLATED
|
||||||
game: Optional[str] = None
|
game: Optional[str] = None
|
||||||
|
@ -124,14 +124,31 @@ class APContainer:
|
||||||
"game": self.game,
|
"game": self.game,
|
||||||
# minimum version of patch system expected for patching to be successful
|
# minimum version of patch system expected for patching to be successful
|
||||||
"compatible_version": 5,
|
"compatible_version": 5,
|
||||||
"version": current_patch_version,
|
"version": container_version,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class APPatch(APContainer, abc.ABC, metaclass=AutoPatchRegister):
|
class APPatch(APContainer):
|
||||||
"""
|
"""
|
||||||
An abstract `APContainer` that defines the requirements for an object
|
An `APContainer` that represents a patch file.
|
||||||
to be used by the `Patch.create_rom_file` function.
|
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
|
||||||
|
represents a patch file, but will not be applied with AP's `Patch.py`
|
||||||
|
"""
|
||||||
|
procedure: Union[Literal["custom"], List[Tuple[str, List[Any]]]] = "custom"
|
||||||
|
|
||||||
|
def get_manifest(self) -> Dict[str, Any]:
|
||||||
|
manifest = super(APPatch, self).get_manifest()
|
||||||
|
manifest["procedure"] = self.procedure
|
||||||
|
manifest["compatible_version"] = 6
|
||||||
|
return manifest
|
||||||
|
|
||||||
|
|
||||||
|
class APAutoPatchInterface(APPatch, abc.ABC, metaclass=AutoPatchRegister):
|
||||||
|
"""
|
||||||
|
An abstract `APPatch` that defines the requirements for a patch
|
||||||
|
to be applied with AP's `Patch.py`
|
||||||
"""
|
"""
|
||||||
result_file_ending: str = ".sfc"
|
result_file_ending: str = ".sfc"
|
||||||
|
|
||||||
|
@ -140,14 +157,15 @@ class APPatch(APContainer, abc.ABC, metaclass=AutoPatchRegister):
|
||||||
""" create the output file with the file name `target` """
|
""" create the output file with the file name `target` """
|
||||||
|
|
||||||
|
|
||||||
class APDeltaPatch(APPatch):
|
class APDeltaPatch(APAutoPatchInterface):
|
||||||
"""An APPatch that additionally has delta.bsdiff4
|
"""An implementation of `APAutoPatchInterface` that additionally
|
||||||
containing a delta patch to get the desired file, often a rom."""
|
has delta.bsdiff4 containing a delta patch to get the desired file."""
|
||||||
|
|
||||||
hash: Optional[str] # base checksum of source file
|
hash: Optional[str] # base checksum of source file
|
||||||
patch_file_ending: str = ""
|
patch_file_ending: str = ""
|
||||||
delta: Optional[bytes] = None
|
delta: Optional[bytes] = None
|
||||||
source_data: bytes
|
source_data: bytes
|
||||||
|
procedure = None # delete this line when APPP is added
|
||||||
|
|
||||||
def __init__(self, *args: Any, patched_path: str = "", **kwargs: Any) -> None:
|
def __init__(self, *args: Any, patched_path: str = "", **kwargs: Any) -> None:
|
||||||
self.patched_path = patched_path
|
self.patched_path = patched_path
|
||||||
|
@ -158,6 +176,7 @@ class APDeltaPatch(APPatch):
|
||||||
manifest["base_checksum"] = self.hash
|
manifest["base_checksum"] = self.hash
|
||||||
manifest["result_file_ending"] = self.result_file_ending
|
manifest["result_file_ending"] = self.result_file_ending
|
||||||
manifest["patch_file_ending"] = self.patch_file_ending
|
manifest["patch_file_ending"] = self.patch_file_ending
|
||||||
|
manifest["compatible_version"] = 5 # delete this line when APPP is added
|
||||||
return manifest
|
return manifest
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -7,7 +7,7 @@ from typing import Optional, Any
|
||||||
import Utils
|
import Utils
|
||||||
from .Locations import AdventureLocation, LocationData
|
from .Locations import AdventureLocation, LocationData
|
||||||
from settings import get_settings
|
from settings import get_settings
|
||||||
from worlds.Files import APDeltaPatch, AutoPatchRegister, APContainer
|
from worlds.Files import APPatch, AutoPatchRegister
|
||||||
|
|
||||||
import bsdiff4
|
import bsdiff4
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ class BatNoTouchLocation:
|
||||||
return ret_dict
|
return ret_dict
|
||||||
|
|
||||||
|
|
||||||
class AdventureDeltaPatch(APContainer, metaclass=AutoPatchRegister):
|
class AdventureDeltaPatch(APPatch, metaclass=AutoPatchRegister):
|
||||||
hash = ADVENTUREHASH
|
hash = ADVENTUREHASH
|
||||||
game = "Adventure"
|
game = "Adventure"
|
||||||
patch_file_ending = ".apadvn"
|
patch_file_ending = ".apadvn"
|
||||||
|
|
|
@ -4,7 +4,7 @@ import zipfile
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from .Regions import object_id_table
|
from .Regions import object_id_table
|
||||||
from Utils import __version__
|
from Utils import __version__
|
||||||
from worlds.Files import APContainer
|
from worlds.Files import APPatch
|
||||||
import pkgutil
|
import pkgutil
|
||||||
|
|
||||||
settings_template = yaml.load(pkgutil.get_data(__name__, "data/settings.yaml"), yaml.Loader)
|
settings_template = yaml.load(pkgutil.get_data(__name__, "data/settings.yaml"), yaml.Loader)
|
||||||
|
@ -116,7 +116,7 @@ def generate_output(self, output_directory):
|
||||||
APMQ.write_contents(zf)
|
APMQ.write_contents(zf)
|
||||||
|
|
||||||
|
|
||||||
class APMQFile(APContainer):
|
class APMQFile(APPatch):
|
||||||
game = "Final Fantasy Mystic Quest"
|
game = "Final Fantasy Mystic Quest"
|
||||||
|
|
||||||
def get_manifest(self):
|
def get_manifest(self):
|
||||||
|
|
|
@ -29,14 +29,14 @@ from .TextBox import character_table, NORMAL_LINE_WIDTH, rom_safe_text
|
||||||
from .texture_util import ci4_rgba16patch_to_ci8, rgba16_patch
|
from .texture_util import ci4_rgba16patch_to_ci8, rgba16_patch
|
||||||
from .Utils import __version__
|
from .Utils import __version__
|
||||||
|
|
||||||
from worlds.Files import APContainer
|
from worlds.Files import APPatch
|
||||||
from Utils import __version__ as ap_version
|
from Utils import __version__ as ap_version
|
||||||
|
|
||||||
AP_PROGRESSION = 0xD4
|
AP_PROGRESSION = 0xD4
|
||||||
AP_JUNK = 0xD5
|
AP_JUNK = 0xD5
|
||||||
|
|
||||||
|
|
||||||
class OoTContainer(APContainer):
|
class OoTContainer(APPatch):
|
||||||
game: str = 'Ocarina of Time'
|
game: str = 'Ocarina of Time'
|
||||||
|
|
||||||
def __init__(self, patch_data: bytes, base_path: str, output_directory: str,
|
def __init__(self, patch_data: bytes, base_path: str, output_directory: str,
|
||||||
|
|
|
@ -5,7 +5,7 @@ import zipfile
|
||||||
from typing_extensions import override
|
from typing_extensions import override
|
||||||
|
|
||||||
import Utils
|
import Utils
|
||||||
from worlds.Files import APPatch
|
from worlds.Files import APAutoPatchInterface
|
||||||
|
|
||||||
from zilliandomizer.patch import Patcher
|
from zilliandomizer.patch import Patcher
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ from .gen_data import GenData
|
||||||
USHASH = 'd4bf9e7bcf9a48da53785d2ae7bc4270'
|
USHASH = 'd4bf9e7bcf9a48da53785d2ae7bc4270'
|
||||||
|
|
||||||
|
|
||||||
class ZillionPatch(APPatch):
|
class ZillionPatch(APAutoPatchInterface):
|
||||||
hash = USHASH
|
hash = USHASH
|
||||||
game = "Zillion"
|
game = "Zillion"
|
||||||
patch_file_ending = ".apzl"
|
patch_file_ending = ".apzl"
|
||||||
|
|
Loading…
Reference in New Issue