From db6d4ac9db40ce6dc4c5d4ff8d3d7522200f054e Mon Sep 17 00:00:00 2001 From: Fenhl Date: Sat, 23 Mar 2024 11:08:47 +0000 Subject: [PATCH] Fix mypy errors in Models.py and MQ.py --- MQ.py | 53 +++++++++++++++++++++++++++++++++++++++-------------- Models.py | 48 ++++++++++++++++++++++++------------------------ 2 files changed, 63 insertions(+), 38 deletions(-) diff --git a/MQ.py b/MQ.py index 95b3b7f37..2f8b0f83e 100644 --- a/MQ.py +++ b/MQ.py @@ -70,15 +70,18 @@ def __init__(self, name: str, start: int = 0, end: Optional[int] = None, remap: self.from_file: int = self.start # used to update the file's associated dmadata record - self.dma_key: int = self.start + self.dma_key: Optional[int] = self.start @classmethod def from_json(cls, file: JsonFile) -> File: + start = file.get('Start', None) + end = file.get('End', None) + remap_start = file.get('RemapStart', None) return cls( file['Name'], - int(file['Start'], 16) if file.get('Start', None) is not None else 0, - int(file['End'], 16) if file.get('End', None) is not None else None, - int(file['RemapStart'], 16) if file.get('RemapStart', None) is not None else None + 0 if start is None else int(start, 16), + None if end is None else int(end, 16), + None if remap_start is None else int(remap_start, 16), ) def __repr__(self) -> str: @@ -120,16 +123,29 @@ def write_to_scene(self, rom: Rom, start: int) -> None: rom.write_int32s(addr, [self.poly_addr, self.polytypes_addr, self.camera_data_addr]) +class JsonColDelta(TypedDict): + IsLarger: bool + Polys: list[dict[str, int]] + PolyTypes: list[dict[str, int]] + Cams: list[dict[str, int]] + + class ColDelta: - def __init__(self, delta: dict[str, bool | list[dict[str, int]]]) -> None: + def __init__(self, delta: JsonColDelta) -> None: self.is_larger: bool = delta['IsLarger'] self.polys: list[dict[str, int]] = delta['Polys'] self.polytypes: list[dict[str, int]] = delta['PolyTypes'] self.cams: list[dict[str, int]] = delta['Cams'] +class JsonIcon(TypedDict): + Icon: int + Count: int + IconPoints: list[dict[str, int]] + + class Icon: - def __init__(self, data: dict[str, int | list[dict[str, int]]]) -> None: + def __init__(self, data: JsonIcon) -> None: self.icon: int = data["Icon"] self.count: int = data["Count"] self.points: list[IconPoint] = [IconPoint(x) for x in data["IconPoints"]] @@ -374,8 +390,15 @@ def append_path_data(self, rom: Rom) -> int: return records_offset +class JsonRoom(TypedDict): + File: JsonFile + Id: int + Objects: list[str] + Actors: list[str] + + class Room: - def __init__(self, room: dict[str, int | list[str] | dict[str, Optional[str]]]): + def __init__(self, room: JsonRoom): self.file: File = File.from_json(room['File']) self.id: int = room['Id'] self.objects: list[int] = [int(x, 16) for x in room['Objects']] @@ -607,25 +630,25 @@ def insert_space(rom: Rom, file: File, vram_start: int, insert_section: int, ins (offset + insert_size)) # value contains the vram address - value = rom.read_int32(address) + base_value = rom.read_int32(address) reg = None if type == 2: # Data entry: value is the raw vram address - pass + value = base_value elif type == 4: # Jump OP: Get the address from a Jump instruction - value = 0x80000000 | (value & 0x03FFFFFF) << 2 + value = 0x80000000 | (base_value & 0x03FFFFFF) << 2 elif type == 5: # Load High: Upper half of an address load - reg = (value >> 16) & 0x1F - val_hi[reg] = (value & 0x0000FFFF) << 16 + reg = (base_value >> 16) & 0x1F + val_hi[reg] = (base_value & 0x0000FFFF) << 16 adr_hi[reg] = address # Do not process, wait until the lower half is read value = None elif type == 6: # Load Low: Lower half of the address load - reg = (value >> 21) & 0x1F - val_low = value & 0x0000FFFF + reg = (base_value >> 21) & 0x1F + val_low = base_value & 0x0000FFFF val_low = unpack('h', pack('H', val_low))[0] # combine with previous load high value = val_hi[reg] + val_low @@ -648,6 +671,8 @@ def insert_space(rom: Rom, file: File, vram_start: int, insert_section: int, ins new_value = op | new_value rom.write_int32(address, new_value) elif type == 6: + assert reg is not None + # Load Low: Lower half of the address load op = rom.read_int32(address) & 0xFFFF0000 new_val_low = new_value & 0x0000FFFF diff --git a/Models.py b/Models.py index fb149c6fa..3e02de39d 100644 --- a/Models.py +++ b/Models.py @@ -93,7 +93,7 @@ def WriteModelDataLo(self, data: int) -> None: # Either return the starting index of the requested data (when start == 0) # or the offset of the element in the footer, if it exists (start > 0) -def scan(bytes: bytearray, data: bytearray | str, start: int = 0) -> int: +def scan(bytes_to_scan: bytearray, data: bytearray | str, start: int = 0) -> int: databytes: bytearray | bytes # If a string was passed, encode string as bytes if isinstance(data, str): @@ -101,27 +101,27 @@ def scan(bytes: bytearray, data: bytearray | str, start: int = 0) -> int: else: databytes = data dataindex = 0 - for i in range(start, len(bytes)): + for i in range(start, len(bytes_to_scan)): # Byte matches next byte in string - if bytes[i] == databytes[dataindex]: + if bytes_to_scan[i] == databytes[dataindex]: dataindex += 1 # Special case: Bottle, Bow, Slingshot, Fist.L, and Fist.R are subsets of # Bottle.Hand.L, Bow.String, Slingshot.String, Gauntlet.Fist.L, and Gauntlet.Fist.R respectively # And Hookshot which is a subset of Hookshot.Spike, Hookshot.Chain, Hookshot.Aiming.Reticule # This leads to false positives. So if the next byte is . (0x2E) then reset the count. - if isinstance(data, str) and data in ["Bottle", "Bow", "Slingshot", "Hookshot", "Fist.L", "Fist.R", "Blade.3"] and i < len(bytes) - 1 and bytes[i+1] == 0x2E: + if isinstance(data, str) and data in ["Bottle", "Bow", "Slingshot", "Hookshot", "Fist.L", "Fist.R", "Blade.3"] and i < len(bytes_to_scan) - 1 and bytes_to_scan[i+1] == 0x2E: # Blade.3 is even wackier, as it is a subset of Blade.3.Break, # and also a forward subset of Broken.Blade.3, and has a period in it if data == "Blade.3": resetCount = False # If current byte is the "e" in "Blade.3", the period detected is the expected one- Carry on # If it isn't, then reset the count - if bytes[i] != 0x65: + if bytes_to_scan[i] != 0x65: resetCount = True # Make sure i is large enough, "Broken.Blad" is 11 chars (remember we're currently at the e) if not resetCount and i > 10: # Check if "Broken." immediately preceeds this string - preceedingBytes = bytes[i-11:i-4] + preceedingBytes = bytes_to_scan[i-11:i-4] if preceedingBytes == bytearray(b'Broken.'): resetCount = True if resetCount: @@ -130,7 +130,7 @@ def scan(bytes: bytearray, data: bytearray | str, start: int = 0) -> int: # "Gauntlet.Fis" is 12 chars (we are currently at the t) elif data in ["Fist.L", "Fist.R"] and i > 11: # Check if "Gauntlet." immediately preceeds this string - preceedingBytes = bytes[i-12:i-3] + preceedingBytes = bytes_to_scan[i-12:i-3] if preceedingBytes == bytearray(b'Gauntlet.'): dataindex = 0 # Default case for Bottle, Bow, Slingshot, Hookshot, reset count @@ -140,7 +140,7 @@ def scan(bytes: bytearray, data: bytearray | str, start: int = 0) -> int: # (Blade.3 and fists can check in the previous stanza since a . will be encountered at some point) if isinstance(data, str) and data == "Hookshot" and dataindex == 1 and i > 3: # Check if "FPS." immediately preceeds this string - preceedingBytes = bytes[i-4:i] + preceedingBytes = bytes_to_scan[i-4:i] if preceedingBytes == bytearray(b'FPS.'): dataindex = 0 # More special cases added by the new pipeline... @@ -148,20 +148,20 @@ def scan(bytes: bytearray, data: bytearray | str, start: int = 0) -> int: # And Hand.L specifically is a forward subset of Bottle.Hand.L if isinstance(data, str) and data in ["Hand.L", "Hand.R"] and dataindex == 1: if i > 8: - preceedingBytes = bytes[i-9:i] + preceedingBytes = bytes_to_scan[i-9:i] if preceedingBytes == bytearray(b'Gauntlet.'): dataindex = 0 if dataindex == 1 and i > 3: - preceedingBytes = bytes[i-4:i] + preceedingBytes = bytes_to_scan[i-4:i] if preceedingBytes == bytearray(b'FPS.'): dataindex = 0 if data == "Hand.L" and dataindex == 1 and i > 6: - preceedingBytes = bytes[i-7:i] + preceedingBytes = bytes_to_scan[i-7:i] if preceedingBytes == bytearray(b'Bottle.'): dataindex = 0 # Forearm.L and Forearm.R are forward subsets of FPS.Forearm.X if isinstance(data, str) and data in ["Forearm.L", "Forearm.R"] and dataindex == 1 and i > 3: - preceedingBytes = bytes[i-4:i] + preceedingBytes = bytes_to_scan[i-4:i] if preceedingBytes == bytearray(b'FPS.'): dataindex = 0 # All bytes have been found, so a match @@ -174,7 +174,7 @@ def scan(bytes: bytearray, data: bytearray | str, start: int = 0) -> int: i += 2 offsetbytes = [] for j in range(4): - offsetbytes.append(bytes[i + j]) + offsetbytes.append(bytes_to_scan[i + j]) return int.from_bytes(offsetbytes, 'big') # Match has been broken, reset to start of string else: @@ -211,9 +211,9 @@ def LoadVanilla(rom: Rom, missing: list[str], rebase: int, linkstart: int, links for i in range(linksize): vanillaData.append(rom.buffer[linkstart + i]) segment = 0x06 - vertices = {} - matrices = {} - textures = {} + vertices: dict[int, list[int]] = {} + matrices: dict[int, list[int]] = {} + textures: dict[int, list[int]] = {} displayLists = {} # For each missing piece, grab data from its vanilla display list for item in missing: @@ -285,7 +285,7 @@ def LoadVanilla(rom: Rom, missing: list[str], rebase: int, linkstart: int, links # Grab the address from the low byte without the base offset texOffset = lo & 0x00FFFFFF numTexels = -1 - returnStack = [] + returnStack: list[int] = [] j = i+8 # The point of this loop is just to find the number of texels # so that it may be multiplied by the bytesPerTexel so we know @@ -345,7 +345,7 @@ def LoadVanilla(rom: Rom, missing: list[str], rebase: int, linkstart: int, links i += 8 displayLists[item] = (displayList, offset) # Create vanilla zobj of the pieces from data collected during crawl - vanillaZobj = [] + vanillaZobj: list[int] = [] # Add textures, vertices, and matrices to the beginning of the zobj # Textures oldTex2New = {} @@ -475,13 +475,13 @@ def CorrectSkeleton(zobj: bytearray, skeleton: list[list[int]], agestr: str) -> hasVanillaSkeleton = True for i in range(21): offset = limb + i * 0x10 - bytes = [] - bytes.extend(int.to_bytes(skeleton[i][0], 2, 'big')) - bytes.extend(int.to_bytes(skeleton[i][1], 2, 'big')) - bytes.extend(int.to_bytes(skeleton[i][2], 2, 'big')) + skeleton_bytes: list[int] = [] + skeleton_bytes.extend(int.to_bytes(skeleton[i][0], 2, 'big')) + skeleton_bytes.extend(int.to_bytes(skeleton[i][1], 2, 'big')) + skeleton_bytes.extend(int.to_bytes(skeleton[i][2], 2, 'big')) # Overwrite the X, Y, Z bytes with their vanilla values for j in range(6): - zobj[offset+j] = bytes[j] + zobj[offset+j] = skeleton_bytes[j] return hasVanillaSkeleton @@ -532,7 +532,7 @@ def LoadModel(rom: Rom, model: str, age: int) -> int: # Find which pieces, if any, are missing from this model missing = [] present = {} - DLOffsets = {} + DLOffsets: dict[str, int] = {} for piece in pieces: offset = scan(zobj, piece, footerstart) if offset == -1: