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
 | 
			
		||||
    ModuleUpdate.update()
 | 
			
		||||
 | 
			
		||||
from worlds.Files import AutoPatchRegister, APPatch
 | 
			
		||||
from worlds.Files import AutoPatchRegister, APAutoPatchInterface
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RomMeta(TypedDict):
 | 
			
		||||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ class RomMeta(TypedDict):
 | 
			
		|||
def create_rom_file(patch_file: str) -> Tuple[RomMeta, str]:
 | 
			
		||||
    auto_handler = AutoPatchRegister.get_handler(patch_file)
 | 
			
		||||
    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
 | 
			
		||||
        handler.patch(target)
 | 
			
		||||
        return {"server": handler.server,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,7 @@ import zipfile
 | 
			
		|||
import os
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ class AutoPatchRegister(abc.ABCMeta):
 | 
			
		|||
        return None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
current_patch_version: int = 5
 | 
			
		||||
container_version: int = 6
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class InvalidDataError(Exception):
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +50,7 @@ class InvalidDataError(Exception):
 | 
			
		|||
 | 
			
		||||
class APContainer:
 | 
			
		||||
    """A zipfile containing at least archipelago.json"""
 | 
			
		||||
    version: int = current_patch_version
 | 
			
		||||
    version: int = container_version
 | 
			
		||||
    compression_level: int = 9
 | 
			
		||||
    compression_method: int = zipfile.ZIP_DEFLATED
 | 
			
		||||
    game: Optional[str] = None
 | 
			
		||||
| 
						 | 
				
			
			@ -124,14 +124,31 @@ class APContainer:
 | 
			
		|||
            "game": self.game,
 | 
			
		||||
            # minimum version of patch system expected for patching to be successful
 | 
			
		||||
            "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
 | 
			
		||||
    to be used by the `Patch.create_rom_file` function.
 | 
			
		||||
    An `APContainer` 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
 | 
			
		||||
    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"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -140,14 +157,15 @@ class APPatch(APContainer, abc.ABC, metaclass=AutoPatchRegister):
 | 
			
		|||
        """ create the output file with the file name `target` """
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class APDeltaPatch(APPatch):
 | 
			
		||||
    """An APPatch that additionally has delta.bsdiff4
 | 
			
		||||
    containing a delta patch to get the desired file, often a rom."""
 | 
			
		||||
class APDeltaPatch(APAutoPatchInterface):
 | 
			
		||||
    """An implementation of `APAutoPatchInterface` that additionally
 | 
			
		||||
    has delta.bsdiff4 containing a delta patch to get the desired file."""
 | 
			
		||||
 | 
			
		||||
    hash: Optional[str]  # base checksum of source file
 | 
			
		||||
    patch_file_ending: str = ""
 | 
			
		||||
    delta: Optional[bytes] = None
 | 
			
		||||
    source_data: bytes
 | 
			
		||||
    procedure = None  # delete this line when APPP is added
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args: Any, patched_path: str = "", **kwargs: Any) -> None:
 | 
			
		||||
        self.patched_path = patched_path
 | 
			
		||||
| 
						 | 
				
			
			@ -158,6 +176,7 @@ class APDeltaPatch(APPatch):
 | 
			
		|||
        manifest["base_checksum"] = self.hash
 | 
			
		||||
        manifest["result_file_ending"] = self.result_file_ending
 | 
			
		||||
        manifest["patch_file_ending"] = self.patch_file_ending
 | 
			
		||||
        manifest["compatible_version"] = 5  # delete this line when APPP is added
 | 
			
		||||
        return manifest
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ from typing import Optional, Any
 | 
			
		|||
import Utils
 | 
			
		||||
from .Locations import AdventureLocation, LocationData
 | 
			
		||||
from settings import get_settings
 | 
			
		||||
from worlds.Files import APDeltaPatch, AutoPatchRegister, APContainer
 | 
			
		||||
from worlds.Files import APPatch, AutoPatchRegister
 | 
			
		||||
 | 
			
		||||
import bsdiff4
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -78,7 +78,7 @@ class BatNoTouchLocation:
 | 
			
		|||
        return ret_dict
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AdventureDeltaPatch(APContainer, metaclass=AutoPatchRegister):
 | 
			
		||||
class AdventureDeltaPatch(APPatch, metaclass=AutoPatchRegister):
 | 
			
		||||
    hash = ADVENTUREHASH
 | 
			
		||||
    game = "Adventure"
 | 
			
		||||
    patch_file_ending = ".apadvn"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@ import zipfile
 | 
			
		|||
from copy import deepcopy
 | 
			
		||||
from .Regions import object_id_table
 | 
			
		||||
from Utils import __version__
 | 
			
		||||
from worlds.Files import APContainer
 | 
			
		||||
from worlds.Files import APPatch
 | 
			
		||||
import pkgutil
 | 
			
		||||
 | 
			
		||||
settings_template = yaml.load(pkgutil.get_data(__name__, "data/settings.yaml"), yaml.Loader)
 | 
			
		||||
| 
						 | 
				
			
			@ -116,10 +116,10 @@ def generate_output(self, output_directory):
 | 
			
		|||
        APMQ.write_contents(zf)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class APMQFile(APContainer):
 | 
			
		||||
class APMQFile(APPatch):
 | 
			
		||||
    game = "Final Fantasy Mystic Quest"
 | 
			
		||||
 | 
			
		||||
    def get_manifest(self):
 | 
			
		||||
        manifest = super().get_manifest()
 | 
			
		||||
        manifest["patch_file_ending"] = ".apmq"
 | 
			
		||||
        return manifest
 | 
			
		||||
        return manifest
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 .Utils import __version__
 | 
			
		||||
 | 
			
		||||
from worlds.Files import APContainer
 | 
			
		||||
from worlds.Files import APPatch
 | 
			
		||||
from Utils import __version__ as ap_version
 | 
			
		||||
 | 
			
		||||
AP_PROGRESSION = 0xD4
 | 
			
		||||
AP_JUNK = 0xD5
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class OoTContainer(APContainer):
 | 
			
		||||
class OoTContainer(APPatch):
 | 
			
		||||
    game: str = 'Ocarina of Time'
 | 
			
		||||
 | 
			
		||||
    def __init__(self, patch_data: bytes, base_path: str, output_directory: str,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,7 @@ import zipfile
 | 
			
		|||
from typing_extensions import override
 | 
			
		||||
 | 
			
		||||
import Utils
 | 
			
		||||
from worlds.Files import APPatch
 | 
			
		||||
from worlds.Files import APAutoPatchInterface
 | 
			
		||||
 | 
			
		||||
from zilliandomizer.patch import Patcher
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -14,7 +14,7 @@ from .gen_data import GenData
 | 
			
		|||
USHASH = 'd4bf9e7bcf9a48da53785d2ae7bc4270'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ZillionPatch(APPatch):
 | 
			
		||||
class ZillionPatch(APAutoPatchInterface):
 | 
			
		||||
    hash = USHASH
 | 
			
		||||
    game = "Zillion"
 | 
			
		||||
    patch_file_ending = ".apzl"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue