def write(self) -> bytes: toc_buffer = bytearray(8 * (len(self.model) + 1)) toc_cursor = 0 image_buffer = bytearray() # File list for w16 in self.model: # TOC entry # Pointer write_u32(toc_buffer, u32_checked(len(toc_buffer) + len(image_buffer)), toc_cursor) # entry data write_u8(toc_buffer, w16.entry_data.width, toc_cursor + 4) write_u8(toc_buffer, w16.entry_data.height, toc_cursor + 5) write_u8(toc_buffer, w16.entry_data.index, toc_cursor + 6) write_u8(toc_buffer, w16.entry_data.null, toc_cursor + 7) toc_cursor += 8 # Palettes pal = bytes(w16.pal) assert len(pal) == 3 * 16 image_buffer += pal # Data image_buffer += w16.compressed_img_data # Null toc entry write_u32(toc_buffer, u32_checked(len(toc_buffer) + len(image_buffer)), toc_cursor) return toc_buffer + image_buffer
def write(self) -> Tuple[bytes, List[int], Optional[int]]: buffer = bytearray() # Sprites spr_pointer = len(buffer) for tiles in self.model.sprites: for tile in tiles: buffer += tile # Palettes pal_pointer = len(buffer) data = bytearray(len(self.model.palettes) * PAL_LEN * PAL_ENTRY_LEN) cursor = 0 for pal in self.model.palettes: for i, col in enumerate(pal): write_u8(data, u8(col), cursor) cursor += 1 if i % 3 == 2: write_u8(data, u8(0xAA), cursor) cursor += 1 buffer += data # Header header = bytearray(4 * 4) write_u32(header, u32_checked(spr_pointer), 0x00) write_u32(header, u32_checked(len(self.model.sprites)), 0x04) write_u32(header, u32_checked(pal_pointer), 0x08) write_u32(header, u32_checked(len(self.model.palettes) * PAL_LEN), 0x0C) pointer_offsets = [len(buffer), len(buffer) + 8] header_pointer = len(buffer) buffer += header return buffer, pointer_offsets, header_pointer
def to_bytes(self): """Convert the string list back to bytes""" length_of_index = 4 * (len(self.strings) + 1) length_of_str_bytes = 0 offset_list = [] strings_bytes = [] for s in self.strings: b = bytes(s, self.string_encoding) + bytes([0]) offset_list.append( u32_checked(length_of_index + length_of_str_bytes)) length_of_str_bytes += len(b) strings_bytes.append(b) result = bytearray(length_of_index + length_of_str_bytes) cursor = 0 for pnt in offset_list: write_u32(result, pnt, cursor) cursor += 4 # End of pointers markers write_u32(result, u32_checked(length_of_index + length_of_str_bytes), cursor) cursor += 4 # Write string bytes offset_list.append(u32_checked(length_of_index + length_of_str_bytes)) for i, s in enumerate(strings_bytes): length = offset_list[i + 1] - offset_list[i] result[cursor:cursor + length] = s cursor += length return result
def write(self) -> Tuple[bytes, List[int], Optional[int]]: pointer_offsets = [] buffer = bytearray() # Insert the tiles with their masks tile_table = [] for i in range(len(self.model.tiles)): tile_table.append(u32_checked(len(buffer))) current_mask = self.model.masks[i] current_tile = self.model.tiles[i] for x in range(ZMAPPAT_TILE_SIZE // 8): buffer += current_mask[x * 4:x * 4 + 4] + current_tile[x * 4:x * 4 + 4] # Insert the tile pointers table table = bytearray(len(tile_table) * 4) table_pointer = u32_checked(len(buffer)) for i, x in enumerate(tile_table): pointer_offsets.append(len(buffer) + i * 4) write_u32(table, x, i * 4) buffer += table # The palette palette_pointer = u32_checked(len(buffer)) palette_buffer = bytearray(len(self.model.palette) * 4 // 3) j = 0 for i, p in enumerate(self.model.palette): write_u8(palette_buffer, u8(p), j) j += 1 if i % 3 == 2: # Insert the fourth color write_u8(palette_buffer, u8(0), j) j += 1 assert j == len(palette_buffer) buffer += palette_buffer # The header header_pointer = len(buffer) header = bytearray(0x8) pointer_offsets.append(len(buffer)) pointer_offsets.append(len(buffer) + 4) write_u32(header, table_pointer, 0) write_u32(header, palette_pointer, 4) buffer += header return buffer, pointer_offsets, header_pointer
def write(self) -> Tuple[bytes, List[int], Optional[int]]: pointer_offsets = [] buffer = bytearray() # Image data image_pointer = len(buffer) buffer += self.model.image_data # Padding if len(buffer) % 16 != 0: buffer += bytes(0 for _ in range(0, 16 - (len(buffer) % 16))) # Palette palette_pointer = len(buffer) palette_buffer = bytearray(len(self.model.palette) + int(len(self.model.palette) / 3)) j = 0 for i, p in enumerate(self.model.palette): write_u8(palette_buffer, u8(p), j) j += 1 if i % 3 == 2: # Insert the fourth color write_u8(palette_buffer, u8(0x80), j) j += 1 assert j == len(palette_buffer) buffer += palette_buffer # Header # We don't really know how many 0s the game wants but better to many than too few... header = bytearray(0x34) header[0:4] = MAGIC_NUMBER pointer_offsets.append(len(buffer) + 0x04) write_u32(header, u32_checked(image_pointer), 0x04) write_u32(header, u32_checked(len(self.model.image_data)), 0x08) write_u8(header, self.model.actual_dim, 0x0C) write_u8(header, self.model.image_type.value, 0x0D) write_u32(header, self.model.unk10, 0x10) write_u16(header, self.model.width, 0x14) write_u16(header, self.model.height, 0x16) pointer_offsets.append(len(buffer) + 0x18) write_u32(header, u32_checked(palette_pointer), 0x18) write_u32(header, u32_checked(len(self.model.palette) // 3), 0x1C) header_pointer = len(buffer) buffer += header return buffer, pointer_offsets, header_pointer
def write(self) -> Tuple[bytes, List[int], Optional[int]]: from skytemple_files.common.types.file_types import FileType pointer_offsets = [] char_offsets = [] sorted_entries = sorted(self.model.entries, key=lambda x: (x.table, x.char)) buffer = bytearray() # Image data for i, e in enumerate(sorted_entries): char_offsets.append(u32_checked(len(buffer))) buffer += FileType.RLE_NIBBLE.compress(e.data) if len(buffer) % 16 != 0: buffer += bytearray([0xAA] * (16 - len(buffer) % 16)) # Character pointers char_pointer = bytearray( len(self.model.entries) * BANNER_FONT_ENTRY_LEN) char_pointer_offset = u32_checked(len(buffer)) last: Tuple[Optional[int], Optional[int]] = (None, None) for i, e in enumerate(sorted_entries): if last == (e.char, e.table): raise ValueError( "Character {e.char} in table {e.table} is be defined multiple times in a font file!" ) last = (e.char, e.table) pointer_offsets.append(len(buffer) + i * BANNER_FONT_ENTRY_LEN) write_u32(char_pointer, char_offsets[i], i * BANNER_FONT_ENTRY_LEN) write_u8(char_pointer, e.char, i * BANNER_FONT_ENTRY_LEN + 0x4) write_u8(char_pointer, e.table, i * BANNER_FONT_ENTRY_LEN + 0x5) write_i16(char_pointer, e.width, i * BANNER_FONT_ENTRY_LEN + 0x6) buffer += char_pointer # Header header = bytearray(0xC) pointer_offsets.append(len(buffer)) write_u32(header, char_pointer_offset, 0) write_u32(header, u32_checked(len(self.model.entries)), 0x4) write_u32(header, self.model.unknown, 0x8) header_pointer = len(buffer) buffer += header return buffer, pointer_offsets, header_pointer
def write(self) -> bytes: bytelen_single_tile = int(BGP_TILE_DIM * BGP_TILE_DIM / 2) palette_length = u32_checked(len(self.model.palettes) * BGP_PAL_NUMBER_COLORS * BGP_PAL_ENTRY_LEN) tiles_length = u32_checked(len(self.model.tiles) * bytelen_single_tile) tilemapping_length = u32_checked(len(self.model.tilemap) * BGP_TILEMAP_ENTRY_BYTELEN) palette_begin = BGP_HEADER_LENGTH tilemapping_begin = u32_checked(palette_begin + palette_length) tiles_begin = u32_checked(tilemapping_begin + tilemapping_length) # 32 byte header + palette, tiles and tilemapping data self.data = bytearray(BGP_HEADER_LENGTH + palette_length + tiles_length + tilemapping_length) # Header write_u32(self.data, u32(palette_begin), 0) write_u32(self.data, palette_length, 4) write_u32(self.data, tiles_begin, 8) write_u32(self.data, tiles_length, 12) write_u32(self.data, tilemapping_begin, 16) write_u32(self.data, tilemapping_length, 20) write_u32(self.data, self.model.header.unknown3, 24) write_u32(self.data, self.model.header.unknown4, 28) self.bytes_written = BGP_HEADER_LENGTH assert self.bytes_written == palette_begin # Palettes for palette in self.model.palettes: for i, color in enumerate(palette): self._write_byte(u8(color)) if i % 3 == 2: # Insert the fourth color self._write_byte(u8(BGP_PAL_UNKNOWN4_COLOR_VAL)) assert self.bytes_written == tilemapping_begin # Tile Mappings for entry in self.model.tilemap: write_u16(self.data, entry.to_int(), self.bytes_written) self.bytes_written += BGP_TILEMAP_ENTRY_BYTELEN assert self.bytes_written == tiles_begin # Tiles for tile in self.model.tiles: self.data[self.bytes_written:self.bytes_written+bytelen_single_tile] = tile self.bytes_written += bytelen_single_tile return self.data
def write(self) -> bytes: file_data = bytearray(4) write_u32(file_data, u32_checked(len(self.model.evo_entries)*MEVO_ENTRY_LENGTH+4), 0) for x in self.model.evo_entries: file_data += x.to_bytes() for y in self.model.evo_stats: file_data += y.to_bytes() return bytes(file_data)
def _push_string(self, full_binary: bytes, out_data: bytearray, pointer: u32) -> u32: """Add the string that's being pointed to to in full_binary to out_data and return a new relative pointer""" str_len, string = read_var_length_string(full_binary, pointer) new_pointer = u32_checked(len(out_data)) out_data += bytes(string, string_codec.PMD2_STR_ENCODER) number_of_nulls = self._read_nulls(full_binary, pointer + str_len) + 1 out_data += (b'\0' * number_of_nulls) return new_pointer
def write(self) -> bytes: data = bytearray(HEADER_SIZE) write_u32(data, u32_checked(len(data)), 0) for e in self.model.trap_table: data += e.to_bytes() write_u32(data, u32_checked(len(data)), 4) for e in self.model.item_table: data += e.to_bytes() write_u32(data, u32_checked(len(data)), 8) for e in self.model.move_table: data += e.to_bytes() write_u32(data, u32_checked(len(data)), 12) for e in self.model.general_table: data += e.to_bytes() write_u32(data, u32_checked(len(data)), 16) for e in self.model.special_move_table: data += e.to_bytes() return bytes(data)
def write(self) -> bytes: nb_items = len(self.model.items_effects) header = bytearray(4 + 2 * nb_items + len(self.model.effects_code) * 8) write_u32(header, u32_checked(4 + 2 * nb_items), 0) code_data = bytearray(0) current_ptr = len(header) for i, c in enumerate(self.model.effects_code): write_u32(header, u32_checked(current_ptr), 4 + 2 * nb_items + i * 8) write_u32(header, u32_checked(len(c)), 4 + 2 * nb_items + i * 8 + 4) code_data += bytearray(c) current_ptr += len(c) for i, x in enumerate(self.model.items_effects): write_u16(header, u16_checked(x), 4 + 2 * i) file_data = header + code_data return bytes(file_data)
def to_bytes(self) -> bytes: buffer = bytearray(12) write_u32( buffer, u32_checked( self.item_id * 8 + self._overlay29bin.symbols['ItemSpawnTable'].begin_absolute), 0) write_u32( buffer, u32_checked(self.monster_id * 4 + self._overlay29bin. symbols['MonsterSpawnTable'].begin_absolute), 4) write_u32( buffer, u32_checked( self.tile_id * 4 + self._overlay29bin.symbols['TileSpawnTable'].begin_absolute), 8) return buffer
def write(self) -> Tuple[bytes, List[int], Optional[int]]: pointer_offsets = [] sorted_entries = sorted(self.model.entries, key=lambda x: (x.table, x.char)) buffer = bytearray() # Image data for i, e in enumerate(sorted_entries): buffer += e.data if len(buffer) % 16 != 0: buffer += bytearray([0xAA] * (16 - len(buffer) % 16)) # Character pointers char_pointer = bytearray(len(self.model.entries) * FONT_SIR0_ENTRY_LEN) char_pointer_offset = len(buffer) last: Tuple[Optional[int], Optional[int]] = (None, None) for i, e in enumerate(sorted_entries): if last == (e.char, e.table): raise ValueError( f( _("Character {e.char} in table {e.table} is be defined multiple times in a font file!" ))) last = (e.char, e.table) pointer_offsets.append(len(buffer) + i * FONT_SIR0_ENTRY_LEN) write_u32(char_pointer, u32_checked(i * FONT_SIR0_DATA_LEN), i * FONT_SIR0_ENTRY_LEN) write_u8(char_pointer, e.char, i * FONT_SIR0_ENTRY_LEN + 0x4) write_u8(char_pointer, e.table, i * FONT_SIR0_ENTRY_LEN + 0x5) write_u32(char_pointer, e.width, i * FONT_SIR0_ENTRY_LEN + 0x6) write_u8(char_pointer, e.cat, i * FONT_SIR0_ENTRY_LEN + 0xA) write_u8(char_pointer, e.padding, i * FONT_SIR0_ENTRY_LEN + 0xB) buffer += char_pointer # Header header = bytearray(0x8) write_u32(header, u32_checked(len(self.model.entries)), 0) pointer_offsets.append(len(buffer) + 4) write_u32(header, u32_checked(char_pointer_offset), 0x4) header_pointer = len(buffer) buffer += header return buffer, pointer_offsets, header_pointer
def write(self) -> bytes: # Correct all pointers in content by HEADER_LEN if not isinstance(self.model.content, bytearray): self.model.content = bytearray(self.model.content) for i, pnt_off in enumerate(self.model.content_pointer_offsets): self.model.content_pointer_offsets[i] = pnt_off + HEADER_LEN write_u32(self.model.content, u32(read_u32(self.model.content, pnt_off) + HEADER_LEN), pnt_off) # Also add the two header pointers pointer_offsets = [4, 8] + self.model.content_pointer_offsets # Pointer offsets list pol = bytearray(4 * len(pointer_offsets)) pol_cursor = self._encode_pointer_offsets(pol, pointer_offsets) pol = pol[:pol_cursor] len_content_padding = self._len_pad(len(self.model.content)) len_eof_padding = self._len_pad(len(pol)) pointer_pol = HEADER_LEN + len( self.model.content) + len_content_padding self.bytes_written = 0 self.data = bytearray(pointer_pol + len(pol) + len_eof_padding) # Header self._append(b'SIR0') self._write_u32(u32_checked(self.model.data_pointer + HEADER_LEN)) self._write_u32(u32_checked(pointer_pol)) self._write_u32(u32(0)) assert self.bytes_written == HEADER_LEN self._append(self.model.content) self._pad(len_content_padding) assert self.bytes_written == pointer_pol self._append(pol) self._pad(len_eof_padding) assert self.bytes_written == len(self.data) return self.data
def write(self) -> bytes: nb_items = len(self.model.struct_ids) header = bytearray(4 + 2 * nb_items) write_u32(header, u32_checked(4 + 2 * nb_items), 0) for i, x in enumerate(self.model.struct_ids): write_i16(header, i16_checked(x), 4 + 2 * i) file_data = header + self.model.struct_data return bytes(file_data)
def write(self) -> bytes: header = bytearray(len(self.model.attrs) * 4) data = bytearray(0) for i, g_list in enumerate(self.model.attrs): current_ptr = u32_checked(len(header) + len(data)) d_list = bytearray(g_list) if len(d_list) % 4 != 0: d_list += bytearray(4 - (len(d_list) % 4)) write_u32(header, current_ptr, i * 4) data += d_list data = header + data return bytes(data)
def compress(cls, data: bytes) -> 'Pkdpx': """Create a new PKDPX container from originally uncompressed data.""" from skytemple_files.common.types.file_types import FileType new_container = cls() flags, px_data = FileType.PX.compress(data) new_container.compression_flags = flags new_container.length_decompressed = u32_checked(len(data)) new_container.compressed_data = px_data new_container.length_compressed = u16_checked(len(px_data) + 0x14) return new_container
def write(self) -> bytes: header = bytearray(6 + 2 * len(self.model.list_dungeons)) write_u32(header, u32_checked(len(header)), 0) code_data = bytearray(0) current = 0 for i, x in enumerate(self.model.list_dungeons): for y in sorted(x, key=lambda v: v.floor): code_data += bytearray(y.to_bytes()) current += 1 write_u16(header, u16_checked(current), 6 + 2 * i) file_data = header + code_data return bytes(file_data)
def compress(cls, data: bytes) -> 'Atupx': """Create a new ATUPX container from originally uncompressed data.""" from skytemple_files.common.types.file_types import FileType new_container = cls() compressed_data = FileType.CUSTOM_999.compress(data) new_container.compressed_data = compressed_data new_container.length_decompressed = u32_checked(len(data)) new_container.length_compressed = u16_checked( len(compressed_data) + 0xb) return new_container
def write(self) -> Tuple[bytes, List[int], Optional[int]]: """Returns the content and the offsets to the pointers and the sub-header pointer, for Sir0 serialization.""" pointer_offsets = [] floor_lists, floor_layouts = self.model.minimize() # Floor list data data = bytearray( sum((len(floor_list) + 1) * 4 for floor_list in floor_lists)) cursor = 0 for floor_list in floor_lists: cursor += 4 # null floor for floor in floor_list: data[cursor:cursor + 4] = floor.to_mappa() cursor += 4 # Floor list LUT start_floor_list_lut = u32_checked(len(data)) floor_list_lut = bytearray(4 * len(floor_lists)) cursor_floor_data = u32(0) for i, floor_list in enumerate(floor_lists): pointer_offsets.append(start_floor_list_lut + i * 4) write_u32(floor_list_lut, cursor_floor_data, i * 4) cursor_floor_data = u32_checked(cursor_floor_data + (len(floor_list) + 1) * 4) data += floor_list_lut # Floor layout data start_floor_layout_data = u32_checked(len(data)) layout_data = bytearray(4 * len(floor_layouts)) for i, layout in enumerate(floor_layouts): layout_data[i * 4:(i + 1) * 4] = layout.to_mappa() data += layout_data # Sub-header data_pointer = len(data) subheader = bytearray(8) pointer_offsets.append(data_pointer + 0x00) write_u32(subheader, start_floor_list_lut, 0x00) pointer_offsets.append(data_pointer + 0x04) write_u32(subheader, start_floor_layout_data, 0x04) data += subheader return data, pointer_offsets, data_pointer
def on_cr_item_awarded_edited(self, widget, path, text): match = PATTERN_ITEM_ENTRY.match(text) if match is None: return try: item_id = u32_checked(int(match.group(1))) except ValueError: return # item_id: self._list_store[path][4] = item_id # item_name: self._list_store[path][5] = self._item_names[item_id]
def write(self) -> bytes: files = self.model.get_files_bytes() len_header = (len(self.model.get_files_bytes()) + 1) * 8 + 16 # 16 is a row of padding if len_header % 16 != 0: len_header += 16 - (len_header % 16) out_buffer = bytearray(b'\xff' * ( # Header len: max(self.fixed_header_len, len_header) + # File data: self._get_file_sizes(files))) write_u32(out_buffer, u32(0), 0x00) write_u32(out_buffer, u32_checked(len(files)), 0x04) data_cursor = len_header toc_curosr = 8 for file in files: # toc pointer write_u32(out_buffer, u32_checked(data_cursor), toc_curosr) # toc length write_u32(out_buffer, u32_checked(len(file)), toc_curosr + 0x04) # file out_buffer[data_cursor:data_cursor + len(file)] = file data_cursor += len(file) # If the cursor is not aligned with 16 bytes, we pad. if data_cursor % 16 != 0: data_cursor += 16 - (data_cursor % 16) toc_curosr += 8 # If the toc cursor is not aligned with 16 bytes, we will with zeros if toc_curosr % 16 != 0: pad = 16 - (toc_curosr % 16) out_buffer[toc_curosr:toc_curosr + pad] = b'\x00' * pad return out_buffer
def _wrap_sir0(self, full_binary: bytes, table_data: bytes, entry_len: int, string_offs_per_entry: List[int], write_subheader) -> bytes: table_data = bytearray(table_data) out_data = bytearray() pointer_offsets = [] # 1. Write strings number_entries = 0 for i in range(0, len(table_data), entry_len): for string_off in string_offs_per_entry: new_pointer = self._push_string( full_binary, out_data, u32_checked( read_u32(table_data, i + string_off) - self._binary.loadaddress)) pointer_offsets.append(i + string_off) write_u32(table_data, new_pointer, i + string_off) number_entries += 1 # Padding self._pad(out_data) # 2. Correct string pointer offsets pointer_offsets = [off + len(out_data) for off in pointer_offsets] # 3. Append table pointer_data_block = len(out_data) out_data += table_data # Padding self._pad(out_data) # 4. Write sub-header if write_subheader: data_pointer = len(out_data) pointer_offsets.append(len(out_data)) out_data += pointer_data_block.to_bytes(4, byteorder='little', signed=False) out_data += number_entries.to_bytes(4, byteorder='little', signed=False) else: data_pointer = pointer_data_block # 5. Convert into SIR0 return FileType.SIR0.serialize( FileType.SIR0.wrap(out_data, pointer_offsets, data_pointer))
def write(self) -> bytes: buffer = bytearray(self.model.header_size + WTU_ENTRY_LEN * len(self.model.entries)) buffer[0:4] = MAGIC_NUMBER write_u32(buffer, u32_checked(len(self.model.entries)), 0x4) write_u32(buffer, self.model.image_mode, 0x8) write_u32(buffer, self.model.header_size, 0xC) for i, e in enumerate(self.model.entries): write_u16(buffer, e.x, self.model.header_size + (i * WTU_ENTRY_LEN) + 0x00) write_u16(buffer, e.y, self.model.header_size + (i * WTU_ENTRY_LEN) + 0x02) write_u16(buffer, e.width, self.model.header_size + (i * WTU_ENTRY_LEN) + 0x04) write_u16(buffer, e.height, self.model.header_size + (i * WTU_ENTRY_LEN) + 0x06) return buffer
def sir0_serialize_parts(self) -> Tuple[bytes, List[int], Optional[int]]: string_codec.init() out_data = bytearray() # 1. Write strings pointer_offsets: List[u32] = [] for entry in self.list: pointer_offsets.append(u32_checked(len(out_data))) out_data += bytes(entry.name, string_codec.PMD2_STR_ENCODER) + b'\0' # Padding self._pad(out_data) # Write table sir0_pointer_offsets = [] pointer_data_block = len(out_data) for i, entry in enumerate(self.list): entry_buffer = bytearray(LEN_ACTOR_ENTRY) write_u16(entry_buffer, entry.type, 0) write_u16(entry_buffer, entry.entid, 2) sir0_pointer_offsets.append(len(out_data) + 4) write_u32(entry_buffer, pointer_offsets[i], 4) write_u16(entry_buffer, entry.unk3, 8) write_u16(entry_buffer, entry.unk4, 10) out_data += entry_buffer # Padding self._pad(out_data) # 4. Write sub-header data_pointer = len(out_data) sir0_pointer_offsets.append(len(out_data)) out_data += pointer_data_block.to_bytes(4, byteorder='little', signed=False) out_data += len(self.list).to_bytes(4, byteorder='little', signed=False) return out_data, sir0_pointer_offsets, data_pointer
def write(self) -> bytes: buffer = bytearray(FONT_DAT_ENTRY_LEN * len(self.model.entries)) write_u32(buffer, u32_checked(len(self.model.entries)), 0x00) # Font Data last: Tuple[Optional[int], Optional[int]] = (None, None) for i, e in enumerate( sorted(self.model.entries, key=lambda x: (x.table, x.char))): if last == (e.char, e.table): raise ValueError( _("Character {e.char} in table {e.table} is defined multiple times in a font file!" )) last = (e.char, e.table) off_start = 0x4 + (i * FONT_DAT_ENTRY_LEN) write_u8(buffer, e.char, off_start + 0x00) write_u8(buffer, e.table, off_start + 0x01) write_u8(buffer, e.width, off_start + 0x02) write_u8(buffer, e.bprow, off_start + 0x03) buffer[off_start + 0x04:off_start + FONT_DAT_ENTRY_LEN] = e.data return buffer
def write(self) -> Tuple[bytes, List[int], Optional[int]]: """Returns the content and the offsets to the pointers and the sub-header pointer, for Sir0 serialization.""" fixed_floors = bytearray() pointers = [] for floor in self.model.fixed_floors: pointers.append(u32_checked(len(fixed_floors))) fixed_floors += floor.to_bytes() # Padding if len(fixed_floors) % 4 != 0: fixed_floors += bytes( 0xAA for _ in range(0, 4 - (len(fixed_floors) % 4))) header_buffer = bytearray((len(self.model.fixed_floors) + 1) * 4) pointer_offsets = [] i = 0 for i, pointer in enumerate(pointers): pointer_offsets.append(len(fixed_floors) + i * 4) write_u32(header_buffer, pointer, i * 4) write_u32(header_buffer, u32(0xAAAAAAAA), (i + 1) * 4) return fixed_floors + header_buffer, pointer_offsets, len(fixed_floors)
def from_bin(cls, data: bytes): data = memoryview(bytearray(data)) data_pointer = read_u32(data, 0x04) pointer_offset_list_pointer = read_u32(data, 0x08) pointer_offsets = cls._decode_pointer_offsets(data, pointer_offset_list_pointer) # Correct pointers by subtracting the header for pnt_off in pointer_offsets: write_u32( data, # type: ignore u32_checked(read_u32(data, pnt_off) - HEADER_LEN), pnt_off ) # The first two are for the pointers in the header, we remove them now, they are not # part of the content pointers content_pointer_offsets = [pnt - HEADER_LEN for pnt in pointer_offsets][2:] return cls( bytes(data[HEADER_LEN:pointer_offset_list_pointer]), content_pointer_offsets, data_pointer - HEADER_LEN )
def sir0_serialize_parts(self) -> Tuple[bytes, List[int], Optional[int]]: string_codec.init() out_data = bytearray() # 1. Write strings pointer_offsets = [] for entry in self.list: pointer_offsets.append(u32_checked(len(out_data))) out_data += bytes(entry.name, string_codec.PMD2_STR_ENCODER) + b'\0' # Padding self._pad(out_data) # Write table sir0_pointer_offsets = [] pointer_data_block = len(out_data) for i, entry in enumerate(self.list): entry_buffer = bytearray(LEN_LEVEL_ENTRY) write_u16(entry_buffer, entry.mapty, 0) write_u16(entry_buffer, entry.nameid, 2) write_u16(entry_buffer, entry.mapid, 4) write_i16(entry_buffer, entry.weather, 6) sir0_pointer_offsets.append(len(out_data) + 8) write_u32(entry_buffer, pointer_offsets[i], 8) out_data += entry_buffer out_data += PADDING_END # Padding self._pad(out_data) # 4. Write sub-header # sir0_pointer_offsets.append(len(out_data)) # out_data += pointer_data_block.to_bytes(4, byteorder='little', signed=False) # out_data += len(self.list).to_bytes(4, byteorder='little', signed=False) return out_data, sir0_pointer_offsets, pointer_data_block
def sir0_serialize_parts(self) -> Tuple[bytes, List[int], Optional[int]]: data = bytearray() pointers = [] pointer_offsets = [] for i, color_frames in enumerate(self.colors): pointers.append(u32_checked(len(data))) number_colors = len(color_frames) // 3 buffer_entry = bytearray(((number_colors + 1) * 4)) # Number colors write_u8(buffer_entry, u8_checked(number_colors), 0) # Unk write_u8(buffer_entry, u8_checked(self.durations_per_frame_for_colors[i]), 2) # Always one null color null_color = False if len(color_frames) == 0: null_color = True color_frames = [0, 0, 0] cursor = 4 for j, (r, g, b) in enumerate(chunk(color_frames, 3)): write_u8(buffer_entry, r, cursor) write_u8(buffer_entry, g, cursor + 1) write_u8(buffer_entry, b, cursor + 2) write_u8(buffer_entry, u8(128 if not null_color else 0), cursor + 3) cursor += 4 data += buffer_entry data_offset = cursor = len(data) data += bytes(4 * len(pointers)) for pnt in pointers: write_u32(data, pnt, cursor) pointer_offsets.append(cursor) cursor += 4 return data, pointer_offsets, data_offset