APProcedurePatch: hotfix changing class variables to instance variables (#2996)

* change class variables to instance variables

* Update worlds/Files.py

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

* Update worlds/Files.py

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>

* move required_extensions to tuple

* fix missing tuple ellipsis

* fix classvar mixup

* rename tokens to _tokens. use hasattr

* type hint cleanup

* Update Files.py

* check using isinstance instead

---------

Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
This commit is contained in:
Silvris 2024-03-20 17:45:32 -05:00 committed by GitHub
parent 12864f7b24
commit f4b7c28a33
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 20 additions and 14 deletions

View File

@ -7,7 +7,7 @@ from enum import IntEnum
import os
import threading
from typing import ClassVar, Dict, List, Literal, Tuple, Any, Optional, Union, BinaryIO, overload
from typing import ClassVar, Dict, List, Literal, Tuple, Any, Optional, Union, BinaryIO, overload, Sequence
import bsdiff4
@ -41,7 +41,7 @@ class AutoPatchRegister(abc.ABCMeta):
class AutoPatchExtensionRegister(abc.ABCMeta):
extension_types: ClassVar[Dict[str, AutoPatchExtensionRegister]] = {}
required_extensions: List[str] = []
required_extensions: Tuple[str, ...] = ()
def __new__(mcs, name: str, bases: Tuple[type, ...], dct: Dict[str, Any]) -> AutoPatchExtensionRegister:
# construct class
@ -51,7 +51,9 @@ class AutoPatchExtensionRegister(abc.ABCMeta):
return new_class
@staticmethod
def get_handler(game: str) -> Union[AutoPatchExtensionRegister, List[AutoPatchExtensionRegister]]:
def get_handler(game: Optional[str]) -> Union[AutoPatchExtensionRegister, List[AutoPatchExtensionRegister]]:
if not game:
return APPatchExtension
handler = AutoPatchExtensionRegister.extension_types.get(game, APPatchExtension)
if handler.required_extensions:
handlers = [handler]
@ -191,7 +193,7 @@ class APProcedurePatch(APAutoPatchInterface):
hash: Optional[str] # base checksum of source file
source_data: bytes
patch_file_ending: str = ""
files: Dict[str, bytes] = {}
files: Dict[str, bytes]
@classmethod
def get_source_data(cls) -> bytes:
@ -206,6 +208,7 @@ class APProcedurePatch(APAutoPatchInterface):
def __init__(self, *args: Any, **kwargs: Any):
super(APProcedurePatch, self).__init__(*args, **kwargs)
self.files = {}
def get_manifest(self) -> Dict[str, Any]:
manifest = super(APProcedurePatch, self).get_manifest()
@ -277,7 +280,7 @@ class APDeltaPatch(APProcedurePatch):
super(APDeltaPatch, self).__init__(*args, **kwargs)
self.patched_path = patched_path
def write_contents(self, opened_zipfile: zipfile.ZipFile):
def write_contents(self, opened_zipfile: zipfile.ZipFile) -> None:
self.write_file("delta.bsdiff4",
bsdiff4.diff(self.get_source_data_with_cache(), open(self.patched_path, "rb").read()))
super(APDeltaPatch, self).write_contents(opened_zipfile)
@ -296,12 +299,12 @@ class APTokenMixin:
"""
A class that defines functions for generating a token binary, for use in patches.
"""
tokens: List[
_tokens: Sequence[
Tuple[APTokenTypes, int, Union[
bytes, # WRITE
Tuple[int, int], # COPY, RLE
int # AND_8, OR_8, XOR_8
]]] = []
]]] = ()
def get_token_binary(self) -> bytes:
"""
@ -309,8 +312,8 @@ class APTokenMixin:
:return: A bytes object representing the token data.
"""
data = bytearray()
data.extend(len(self.tokens).to_bytes(4, "little"))
for token_type, offset, args in self.tokens:
data.extend(len(self._tokens).to_bytes(4, "little"))
for token_type, offset, args in self._tokens:
data.append(token_type)
data.extend(offset.to_bytes(4, "little"))
if token_type in [APTokenTypes.AND_8, APTokenTypes.OR_8, APTokenTypes.XOR_8]:
@ -351,11 +354,14 @@ class APTokenMixin:
data: bytes) -> None:
...
def write_token(self, token_type: APTokenTypes, offset: int, data: Union[bytes, Tuple[int, int], int]):
def write_token(self, token_type: APTokenTypes, offset: int, data: Union[bytes, Tuple[int, int], int]) -> None:
"""
Stores a token to be used by patching.
"""
self.tokens.append((token_type, offset, data))
if not isinstance(self._tokens, list):
assert len(self._tokens) == 0, f"{type(self)}._tokens was tampered with."
self._tokens = []
self._tokens.append((token_type, offset, data))
class APPatchExtension(metaclass=AutoPatchExtensionRegister):
@ -371,10 +377,10 @@ class APPatchExtension(metaclass=AutoPatchExtensionRegister):
Patch extension functions must return the changed bytes.
"""
game: str
required_extensions: List[str] = []
required_extensions: ClassVar[Tuple[str, ...]] = ()
@staticmethod
def apply_bsdiff4(caller: APProcedurePatch, rom: bytes, patch: str):
def apply_bsdiff4(caller: APProcedurePatch, rom: bytes, patch: str) -> bytes:
"""Applies the given bsdiff4 from the patch onto the current file."""
return bsdiff4.patch(rom, caller.get_file(patch))
@ -411,7 +417,7 @@ class APPatchExtension(metaclass=AutoPatchExtensionRegister):
return bytes(rom_data)
@staticmethod
def calc_snes_crc(caller: APProcedurePatch, rom: bytes):
def calc_snes_crc(caller: APProcedurePatch, rom: bytes) -> bytes:
"""Calculates and applies a valid CRC for the SNES rom header."""
rom_data = bytearray(rom)
if len(rom) < 0x8000: