def _try_load_ai_data(self): self._loaded = True open_files_service = locator.get_scoped("OpenFilesService") try: bin_archive = open_files_service.open(_AI_DATA_PATH) reader = BinArchiveReader(bin_archive) ac_ptr = reader.read_internal_pointer() mi_ptr = reader.read_internal_pointer() at_ptr = reader.read_internal_pointer() mv_ptr = reader.read_internal_pointer() ac_table = self._read_null_terminated_list(reader, ac_ptr) mi_table = self._read_null_terminated_list(reader, mi_ptr) at_table = self._read_null_terminated_list(reader, at_ptr) mv_table = self._read_null_terminated_list(reader, mv_ptr) ac_labels = self._read_mapped_pointers(reader, ac_table) mi_labels = self._read_mapped_pointers(reader, mi_table) at_labels = self._read_mapped_pointers(reader, at_table) mv_labels = self._read_mapped_pointers(reader, mv_table) self.ac = ac_labels self.mi = mi_labels self.at = at_labels self.mv = mv_labels except: logging.exception("Unable to load AI data.")
def _read_supports_from_table(cls, reader: BinArchiveReader): reader.seek(reader.tell() + 2) # Don't care about the owner here. count = reader.read_u16() supports = [] for _ in range(0, count): support = cls._read_support(reader) supports.append(support) return supports
def _read_mapped_pointers(reader: BinArchiveReader, addresses: List[int]) -> List[str]: result = [] for address in addresses: reader.seek(address) label = reader.read_mapped() if label: result.append(label) return result
def _read_null_terminated_list(reader: BinArchiveReader, address: int) -> List[int]: result = [] reader.seek(address) next_pointer = reader.read_internal_pointer() while next_pointer: result.append(next_pointer) next_pointer = reader.read_internal_pointer() return result
def read_count(self, archive) -> int: base_address = self.location_strategy.read_base_address(archive) reader = BinArchiveReader(archive, base_address) next_bytes = reader.read_bytes(self.entry_size) count = 0 while any(next_bytes): count += 1 next_bytes = reader.read_bytes(self.entry_size) return count
def read_count(self, archive) -> int: count_address = self.location_strategy.read_base_address(archive) reader = BinArchiveReader(archive, count_address) if self.width == 1: return reader.read_u8() elif self.width == 2: return reader.read_u16() else: return reader.read_u32()
def get_property_address(self): if issubclass(type(self.parent.owner), Module): property_address = self.parent.owner.find_base_address_for_element( self.parent) + self.offset return property_address, self.parent.owner.archive else: parent_property_address, archive = self.parent.owner.get_property_address( ) reader = BinArchiveReader(archive, parent_property_address) return (reader.read_internal_pointer() + self.offset), archive
def write(self, writer): if self.value is None: writer.write_pointer(None) else: reader = BinArchiveReader(writer.get_archive(), writer.tell()) target_address = reader.read_internal_pointer() end_address = writer.tell() + 4 writer.seek(target_address) for prop in self.value.values(): prop.write(writer) writer.seek(end_address)
def _load(self): open_files_service = locator.get_scoped("OpenFilesService") self.archive = open_files_service.open("sound/IndirectSound.bin.lz") address = self._location_strategy.read_base_address(self.archive) count = self._count_strategy.read_count(self.archive) reader = BinArchiveReader(self.archive, address) for i in range(0, count): self.voice_set_labels.append(reader.read_mapped()) # Skip to the next set. reader.seek(reader.tell() + 8) set_count = reader.read_u32() reader.seek(reader.tell() + set_count * 8 + 4)
def check_support_id_validity(self): module_service = locator.get_scoped("ModuleService") characters = module_service.get_module("Characters").entries reader = BinArchiveReader(self.archive, self._get_master_support_table_address()) table_count = reader.read_u32() encountered_ids = set() for character in characters: support_id = character["Support ID"].value if support_id == 0xFFFF: continue if support_id in encountered_ids: raise SupportIDInUseException(support_id) elif support_id >= table_count: raise OutOfBoundsSupportIDException(support_id) encountered_ids.add(support_id)
def read(self, reader: BinArchiveReader): self.name = reader.read_string() spawn_address = reader.read_internal_pointer() spawn_count = reader.read_u32() end_address = reader.tell() self.spawns = [] reader.seek(spawn_address) for _ in range(0, spawn_count): self.spawns.append(self._read_spawn(reader)) reader.seek(end_address)
def _add_support_to_table(self, character1, character2, support_type): # Jump to the target support table. master_support_table_address = self._get_master_support_table_address() reader = BinArchiveReader(self.archive, master_support_table_address) target_support_id = character1["Support ID"].value reader.seek(reader.tell() + target_support_id * 4 + 4) reader.seek(reader.read_internal_pointer() + 2) # Skip the owner id. # Update the support count. writer = BinArchiveWriter(self.archive, reader.tell()) old_count = reader.read_u16() writer.write_u16(old_count + 1) # Create the new support. new_support_address = writer.tell() + old_count * 0xC self.archive.allocate(new_support_address, 0xC, False) writer.seek(new_support_address) writer.write_u16(character2["ID"].value) writer.write_u16(old_count) writer.write_u32(support_type) writer.write_u32(0x1) # Support tag. Still figuring this part out.
def read(self, archive): self.factions.clear() reader = BinArchiveReader(archive) next_bytes = reader.read_bytes(12) while any(next_bytes): reader.seek(reader.tell() - 12) faction = Faction() faction.read(reader) self.factions.append(faction) next_bytes = reader.read_bytes(12)
def _create_support_table(self, character): # First, increment master support table count. master_support_table_address = self._get_master_support_table_address() writer = BinArchiveWriter(self.archive, master_support_table_address) reader = BinArchiveReader(self.archive, master_support_table_address) old_count = reader.read_u32() writer.write_u32(old_count + 1) # Next, create a pointer to the new table. pointer_address = master_support_table_address + old_count * 4 + 4 self.archive.allocate(pointer_address, 4, False) destination = self.archive.size() self.archive.set_internal_pointer(pointer_address, destination) # Generate and assign a support ID for the character support_id = self._find_next_support_id() character["Support ID"].value = support_id # Allocate and format the new table. writer.seek(destination) self.archive.allocate_at_end(4) writer.write_u16(support_id)
def read(self, archive): reader = BinArchiveReader(archive) tile_table_address = reader.read_internal_pointer() tile_count = reader.read_u32() self.map_model.read(reader) grid_address = reader.read_internal_pointer() self.tiles.clear() reader.seek(tile_table_address) for _ in range(0, tile_count): tile = self._read_tile(reader) self.tiles.append(tile) reader.seek(grid_address) self.map_size_x.read(reader) self.map_size_y.read(reader) self.border_size_x.read(reader) self.border_size_y.read(reader) self.trimmed_size_x.read(reader) self.trimmed_size_y.read(reader) for r in range(0, 32): for c in range(0, 32): self.grid[r][c] = reader.read_u8()
def _read_support(reader: BinArchiveReader): module_service = locator.get_scoped("ModuleService") characters = module_service.get_module("Characters").entries character = characters[reader.read_u16()] reader.seek(reader.tell() + 2) # The ID is not needed when editing. raw_type = reader.read_u32() tag = reader.read_bytes(4) return Support(character, raw_type, tag)
def attach_to(self, archive): self.entries.clear() location = self.location_strategy.read_base_address(archive) count = self.count_strategy.read_count(archive) reader = BinArchiveReader(archive) for i in range(0, count): reader.seek(location + i * self.entry_size) base = reader.tell() elem = self.element_template.duplicate(new_owner=self) self.entries.append(elem) for (name, prop) in elem.items(): self.element_template[name].offset = reader.tell() - base prop.offset = reader.tell() - base prop.read(reader) self.archive = archive self._resolve_references(archive)
def _get_reader_at_voice_set_table(self, voice_set_label: str) -> (BinArchiveReader, int): # Seek to the voice set's address. address = self.archive.addr_of_mapped_pointer(voice_set_label) if not address: raise Exception # Read the count and perform sanity checks. reader = BinArchiveReader(self.archive, address) if reader.read_u32() != 0xFFFF0002 or reader.read_string() != voice_set_label: raise Exception set_count = reader.read_u32() if reader.read_u32() != set_count: raise Exception return reader, set_count
def _get_master_support_table_address(self): reader = BinArchiveReader(self.archive, 8) reader.seek(reader.read_internal_pointer() + 8) return reader.read_internal_pointer()
def read_base_address(self, archive) -> int: reader = BinArchiveReader(archive, self.address) return reader.read_internal_pointer() + self.offset
def _open_reader_at_table(self, table_number): addr = self._get_master_support_table_address() + table_number * 4 + 4 reader = BinArchiveReader(self.archive, addr) reader.seek(reader.read_internal_pointer()) return reader
def read_base_address(self, archive) -> int: reader = BinArchiveReader(archive) num_fields = reader.read_u32() return num_fields * 0x14 + self.offset + 4
def read_base_address(self, archive) -> int: reader = BinArchiveReader(archive) num_fields = reader.read_u32() reader.seek(num_fields * 0x14 + self.offset_to_pointer + 4) return reader.read_internal_pointer() + self.offset_to_pointer
def read_base_address(self, archive) -> int: ptr = self.offsets[0] for off in self.offsets[1:]: reader = BinArchiveReader(archive, ptr) ptr = reader.read_internal_pointer() + off return ptr
def attach_to(self, archive): location = self.location_strategy.read_base_address(archive) reader = BinArchiveReader(archive, location) for prop in self.element.values(): prop.read(reader) self.archive = archive