def read(self, reader: ByteIO): self.hash = reader.read_uint32() self.name_offset = reader.read_uint32() self.name = reader.read_from_offset(0x90 + self.name_offset, reader.read_ascii_string) self.unknown08 = reader.read_uint32() self.unknown0C = reader.read_uint32() self.unknown10 = reader.read_uint32()
def read(self, reader: ByteIO): self.name_hash = reader.read_uint32() self.type_hash = reader.read_uint32() self.fileNo = reader.read_uint16() self.size = reader.read_uint16() self.unk4 = reader.read_uint32() self.size1 = reader.read_uint64() self.size2 = reader.read_uint64()
def write(self, writer: ByteIO): writer.write_uint32(self.name_hash) writer.write_uint32(self.type_hash) writer.write_uint16(self.fileNo) writer.write_uint16(self.size) writer.write_uint32(self.unk4) writer.write_uint64(self.size1) writer.write_uint64(self.size2)
def read(self, reader: ByteIO): self.name_offset = reader.read_uint32() self.hash = reader.read_uint32() self.type = reader.read_uint16() self.loader_index = reader.read_uint16() self.name = reader.read_from_offset(0x90 + self.name_offset, reader.read_ascii_string)
def __init__(self, path): self.path = Path(path) self.reader = ByteIO(self.path.open('rb')) self.header = OVLHeader() self.types = [] # type:List[OVLTypeHeader] self.files = [] # type:List[OVLFileDescriptor] self.archive_name_table_offset = 0 self.archives = [] # type: List[OVLArchiveV2] self.dirs = [] # type:List[OVLDir] self.parts = [] # type:List[OVLPart] self.others = [] # type:List[OVLOther] self.unknown = [] # type:List[OVLUnk] self.archives2 = [] # type:List[OVLArchive2] self.static_archive = None # type: OVLArchiveV2 self.files_by_hash = {} #type: Dict[int,OVLFileDescriptor] self.hash_by_name = {} #type: Dict[str,int]
def __init__(self, parent): from OVL_COMPRESSED_DATA import OVLCompressedData self.parent: OVLCompressedData = parent self.readers = [] self.resources = {} # type: Dict[int,OVSResourceHeader] if len(self.parent.parent.archives) > 1: self.textures_1 = self.parent.parent.path.with_suffix( '.ovs.textures_l1') self.reader_t1 = ByteIO(file=self.textures_1.open('rb')).unzip() self.readers.append(self.reader_t1) self.read_archive(self.reader_t1) if len(self.parent.parent.archives) > 2: self.textures_2 = self.parent.parent.path.with_suffix( '.ovs.textures_l0') self.reader_t2 = ByteIO(file=self.textures_2.open('rb')).unzip() self.readers.append(self.reader_t2) else: pass
def read(self, reader: ByteIO): self.unk1 = reader.read_uint32() self.unk2 = reader.read_uint32() self.size = reader.read_uint32() self.offset = reader.read_uint32() self.file_hash = reader.read_uint32() self.unk6 = reader.read_uint32() self.type_hash = reader.read_uint32() self.unk8 = reader.read_uint32()
def __init__(self, parent): from OVL_COMPRESSED_DATA import OVLCompressedData self.parent: OVLCompressedData = parent if len(self.parent.parent.archives)>1: self.filepath = self.parent.parent.path.with_suffix('.ovs.textures_l1') elif len(self.parent.parent.archives)>2: self.filepath = self.parent.parent.path.with_suffix('.ovs.textures_l0') else: print('INVALID') exit(0xDEAD) self.reader = ByteIO(file=self.filepath.open('rb')).unzip()
def __init__(self, path): self.reader = ByteIO(path=path) self.name = Path(path).name self.version = 0 self.i32_count = 0 self.i16_count = 0 self.i8_count = 0 self.i1_count = 0 self.export_time = 0 self.i32_offset = 0 self.i16_offset = 0 self.i8_offset = 0 self.i1_offset = 0 self.bit_cursor = 0 self._i1_array = [] self.options = {} self.geometry = HeroGeomerty() self.vertex_count = 0
def write(self, writer: ByteIO): # TODO: FIX IT self.archive.file_type_header_count = len(self.ovs_headers) for header in self.ovs_headers: header.sub_type_count = len(header.subs) header.write(writer) for chunk_id, sub_header in enumerate(self.ovs_sub_headers): sub_header.size = len(self.chunks[chunk_id].data) sub_header.write(writer) self.archive.file_data_header_count = len(self.ovs_file_headers) for file_header in self.ovs_file_headers: file_header.write(writer) self.archive.embedded_file_count = len(self.embedded_file_headers) for embedded_file_id, embedded_file_header in enumerate(self.embedded_file_headers): embedded_file_header.size = len(self.embedded_files[embedded_file_id]) embedded_file_header.write(writer) self.archive.asset_count = len(self.ovs_assets) for file3_header in self.ovs_assets: file3_header.write(writer) self.archive.relocation_num = len(self.relocations) for file4_header in self.relocations: file4_header.write(writer) writer.write_bytes(self.extra_data) for chunk in self.chunks: writer.write_bytes(chunk.data) for embedded_file in self.embedded_files: writer.write_bytes(embedded_file)
def read(self, reader: ByteIO, is_x64=True): if is_x64: self.name_offset = reader.read_uint64() else: self.name_offset = reader.read_uint32() self.type_hash = reader.read_uint32() self.loader_type = reader.read_uint32() self.symbol_start = reader.read_uint32() self.symbols_to_resolve = reader.read_uint32() self.name = reader.read_from_offset(0x90 + self.name_offset, reader.read_ascii_string)
def read(self, reader: ByteIO): self.file_hash = reader.read_uint32() self.type_hash = reader.read_uint32() self.fileNo = reader.read_uint16() self.part_count = reader.read_uint16() self.unk4 = reader.read_uint32() self.size1 = reader.read_uint64() self.total_size = reader.read_uint64()
def read(self, reader: ByteIO): self.name = reader.read_ascii_string() self.index = reader.read_uint32() self.offset = reader.read_uint32() self.size = reader.read_uint32() self.type_map_elements = reader.read_uint32() self.types = [reader.read_uint32() for _ in range(self.type_map_elements)] return self
def __init__(self, path: str): self.path = Path(path) self.reader = ByteIO(path=self.path) self.dump_path = self.path.parent / 'dump' / self.path.stem # type: Path os.makedirs(self.dump_path, exist_ok=True) self.magic = b'' self.model_name = '' self.model_name2 = '' self.copyright = '' self.textures = [] # type: List[Texture] self.meshes = [] # type: List[Mesh] self.models = [] # type: List[Model] self.materials = [] # type: List[Material] self.audio = [] # type: List[Audio] self.animation = [] # type: List[Animation]
def read(self, reader: ByteIO): items = reader.get_items() for item in items: item.seek_to() if item.type == 20: self.chunk_name = reader.read_ascii_string(reader.read_int32()) if item.type == 21: self.name = reader.read_ascii_string(reader.read_int32()) if item.type == 100: self.temp_path = reader.read_ascii_string(reader.read_int32()) if item.type == 1: items2 = item.get_items() for item2 in items2: item2.seek_to() if item2.type == 30: item2.seek_to() self.size = reader.read_uint32() if item2.type == 31: self.data = reader.read_bytes(self.size)
def read(self, reader: ByteIO): self.magic = reader.read_uint32() self.magic_s = "%X" % self.magic self.version = reader.read_uint32() self.face_count = reader.read_uint32() self.vertex_count = reader.read_uint32() self.vertex_size = reader.read_uint32() self.texture_count = reader.read_uint32() self.shader_count = reader.read_uint32() self.attrib_count = reader.read_uint32() self.read_attributes(reader) self.read_textures(reader) self.read_shaders(reader) self.read_indexes(reader) self.read_vertexes(reader)
def read_vertexes(self, reader: ByteIO): for i in range(self.vertex_count): vertex_entry = reader.tell() vertex = RIPVertex() for attrib in self.attributes: reader.seek(vertex_entry + attrib.offset) if attrib.name == RIPAttrTypes.POSITION: vertex.pos.read(reader,attrib.types) elif attrib.name == RIPAttrTypes.NORMAL: vertex.norm.read(reader,attrib.types) elif attrib.name == RIPAttrTypes.TEXCOORD: vertex.UV.append(RIPVarVector().read(reader,attrib.types)) elif attrib.name == RIPAttrTypes.COLOR: vertex.color.read(reader,attrib.types) elif attrib.name == RIPAttrTypes.TANGENT: reader.skip(attrib.size) elif attrib.name == RIPAttrTypes.BLENDINDICES: vertex.blend.read(reader,attrib.types) else: print('Found unknown attribute! Please report about this') reader.seek(vertex_entry + self.vertex_size) self.vertexes.append(vertex)
def write(self, writer: ByteIO): writer.write_uint32(self.unknown00) writer.write_uint64(self.unknown08)
class OVL(OVLBase): is_x64 = False unknown_type = OVLTypeHeader() def __init__(self, path): self.path = Path(path) self.reader = ByteIO(self.path.open('rb')) self.header = OVLHeader() self.types = [] # type:List[OVLTypeHeader] self.files = [] # type:List[OVLFileDescriptor] self.archive_name_table_offset = 0 self.archives = [] # type: List[OVLArchiveV2] self.dirs = [] # type:List[OVLDir] self.parts = [] # type:List[OVLPart] self.others = [] # type:List[OVLOther] self.unknown = [] # type:List[OVLUnk] self.archives2 = [] # type:List[OVLArchive2] self.static_archive = None # type: OVLArchiveV2 self.files_by_hash = {} #type: Dict[int,OVLFileDescriptor] self.hash_by_name = {} #type: Dict[str,int] def read(self): self.header.read(self.reader) self.is_x64 = True # self.header.flags & 0x08 self.reader.skip(self.header.names_length) for _ in range(self.header.type_count): ovl_type = OVLTypeHeader() self.register(ovl_type) ovl_type.read(self.reader, is_x64=self.is_x64) self.types.append(ovl_type) for _ in range(self.header.file_count): ovl_file = OVLFileDescriptor() self.register(ovl_file) ovl_file.read(self.reader) self.files.append(ovl_file) self.files_by_hash = {f.file_hash: f for f in self.files} self.hash_by_name = {f.name: f.file_hash for f in self.files} self.archive_name_table_offset = self.reader.tell() self.reader.skip(self.header.archive_names_length) for _ in range(self.header.archive_count): ovl_archive = OVLArchiveV2() self.register(ovl_archive) ovl_archive.read(self.reader, self.archive_name_table_offset) self.archives.append(ovl_archive) for _ in range(self.header.dir_count): ovl_dir = OVLDir() self.register(ovl_dir) ovl_dir.read(self.reader) self.dirs.append(ovl_dir) for _ in range(self.header.part_count): ovl_part = OVLPart() self.register(ovl_part) ovl_part.read(self.reader) for file in self.files: if ovl_part.hash == file.file_hash: ovl_part.name = file.name self.parts.append(ovl_part) for _ in range(self.header.other_count): ovl_other = OVLOther() self.register(ovl_other) ovl_other.read(self.reader) self.others.append(ovl_other) for _ in range(self.header.unknown_count): ovl_unk = OVLUnk() self.register(ovl_unk) ovl_unk.read(self.reader) self.unknown.append(ovl_unk) for _ in range(self.header.archive_count): ovl_archive2 = OVLArchive2() self.register(ovl_archive2) ovl_archive2.read(self.reader) self.archives2.append(ovl_archive2) for archive in self.archives: print(archive) try: if archive.name == 'STATIC': archive.uncompressed_data = zlib.decompress( self.reader.read_bytes(archive.packed_size)) self.static_archive = archive else: self.reader.seek(archive.ovs_offset) archive.uncompressed_data = zlib.decompress( self.reader.read_bytes(archive.packed_size)) with open( r'test_data\{}-{}.decompressed'.format( self.path.stem, archive.name), 'wb') as fp: fp.write(self.static_archive.uncompressed_data) except: pass def write(self, writer: ByteIO): self.header.write(writer) # not all header fields are accurate yet, # but we'll come back and re-write this section names_start = writer.tell() for ovl_type in sorted(self.types, key=lambda x: x.name_offset): ovl_type.name_offset = writer.tell() - names_start writer.write_ascii_string(ovl_type.name, True) for ovl_file in sorted(self.files, key=lambda x: x.name_offset): ovl_file.name_offset = writer.tell() - names_start writer.write_ascii_string(ovl_file.name, True) for ovl_dir in sorted(self.dirs, key=lambda x: x.name_offset): ovl_dir.name_offset = writer.tell() - names_start writer.write_ascii_string(ovl_dir.name, True) for ovl_part in sorted(self.parts, key=lambda x: x.name_offset): ovl_part.name_offset = writer.tell() - names_start writer.write_ascii_string(ovl_part.name, True) for ovl_other in sorted(self.others, key=lambda x: x.name_offset): ovl_other.name_offset = writer.tell() - names_start writer.write_ascii_string(ovl_other.name, True) writer.align(8) self.header.names_length = writer.tell() - names_start for ovl_type in self.types: ovl_type.write(writer, self.is_x64) for ovl_file in self.files: ovl_file.write(writer) archive_name_table_start = writer.tell() for ovl_archive in self.archives: ovl_archive.nameIndex = writer.tell() - archive_name_table_start writer.write_ascii_string(ovl_archive.name, True) writer.align(8, archive_name_table_start) self.header.archive_names_length = writer.tell( ) - archive_name_table_start for ovl_archive in self.archives: ovl_archive.unpacked_size = len(ovl_archive.uncompressed_data) ovl_archive.compressed_data = zlib.compress( ovl_archive.uncompressed_data) ovl_archive.packed_size = len(ovl_archive.compressed_data) ovl_archive.write(writer) for ovl_dir in self.dirs: ovl_dir.write(writer) for ovl_part in self.parts: ovl_part.write(writer) for ovl_other in self.others: ovl_other.write(writer) for ovl_unk in self.unknown: ovl_unk.write(writer) for ovl_archive2 in self.archives2: ovl_archive2.write(writer) for ovl_archive in self.archives: writer.write_bytes(ovl_archive.compressed_data) writer.seek(0) self.header.write(writer) def get_file_by_hash(self, hash_value) -> OVLFileDescriptor: if not self.files_by_hash: self.files_by_hash = {f.file_hash: f for f in self.files} return self.files_by_hash.get(hash_value) def get_type_by_hash(self, hash_value) -> OVLTypeHeader: for t in self.types: if t.type_hash == hash_value: return t return self.unknown_type
def write(self, writer: ByteIO): self.header.write(writer) # not all header fields are accurate yet, # but we'll come back and re-write this section names_start = writer.tell() for ovl_type in sorted(self.types, key=lambda x: x.name_offset): ovl_type.name_offset = writer.tell() - names_start writer.write_ascii_string(ovl_type.name, True) for ovl_file in sorted(self.files, key=lambda x: x.name_offset): ovl_file.name_offset = writer.tell() - names_start writer.write_ascii_string(ovl_file.name, True) for ovl_dir in sorted(self.dirs, key=lambda x: x.name_offset): ovl_dir.name_offset = writer.tell() - names_start writer.write_ascii_string(ovl_dir.name, True) for ovl_part in sorted(self.parts, key=lambda x: x.name_offset): ovl_part.name_offset = writer.tell() - names_start writer.write_ascii_string(ovl_part.name, True) for ovl_other in sorted(self.others, key=lambda x: x.name_offset): ovl_other.name_offset = writer.tell() - names_start writer.write_ascii_string(ovl_other.name, True) writer.align(8) self.header.names_length = writer.tell() - names_start for ovl_type in self.types: ovl_type.write(writer, self.is_x64) for ovl_file in self.files: ovl_file.write(writer) archive_name_table_start = writer.tell() for ovl_archive in self.archives: ovl_archive.nameIndex = writer.tell() - archive_name_table_start writer.write_ascii_string(ovl_archive.name, True) writer.align(8, archive_name_table_start) self.header.archive_names_length = writer.tell( ) - archive_name_table_start for ovl_archive in self.archives: ovl_archive.unpacked_size = len(ovl_archive.uncompressed_data) ovl_archive.compressed_data = zlib.compress( ovl_archive.uncompressed_data) ovl_archive.packed_size = len(ovl_archive.compressed_data) ovl_archive.write(writer) for ovl_dir in self.dirs: ovl_dir.write(writer) for ovl_part in self.parts: ovl_part.write(writer) for ovl_other in self.others: ovl_other.write(writer) for ovl_unk in self.unknown: ovl_unk.write(writer) for ovl_archive2 in self.archives2: ovl_archive2.write(writer) for ovl_archive in self.archives: writer.write_bytes(ovl_archive.compressed_data) writer.seek(0) self.header.write(writer)
writer.seek(0) self.header.write(writer) def get_file_by_hash(self, hash_value) -> OVLFileDescriptor: if not self.files_by_hash: self.files_by_hash = {f.file_hash: f for f in self.files} return self.files_by_hash.get(hash_value) def get_type_by_hash(self, hash_value) -> OVLTypeHeader: for t in self.types: if t.type_hash == hash_value: return t return self.unknown_type if __name__ == '__main__': # model = r'test_data\Tyrannosaurus.ovl' model = sys.argv[1] # model = r'JWEDinos\Tyrannosaurus\Tyrannosaurus.ovl' a = OVL(model) a.read() # a.read_uncompressed() compressed = OVLCompressedData(a, a.static_archive) compressed.read(ByteIO(byte_object=a.static_archive.uncompressed_data)) compressed.read_files() b = OVSTextureArchive(compressed) b.read() # out = ByteIO(path='test_data/compressed_repacked', mode='w') # compressed.write(out) # out.close()
def write(self, writer: ByteIO): writer.write_uint32(self.name_offset)
def write(self, writer: ByteIO): writer.write_fourcc(self.sig) writer.write_fmt('4B', self.flags, self.version, self.need_bswap, self.unknown07) writer.write_uint32(self.flags2) writer.write_uint32(self.unknown0C) writer.write_uint32(self.names_length) writer.write_uint32(self.unknown2_count) writer.write_uint32(self.other_count) writer.write_uint16(self.dir_count) writer.write_uint16(self.type_count) writer.write_uint32(self.file_count) writer.write_uint32(self.file_count2) writer.write_uint32(self.part_count) writer.write_uint32(self.archive_count) writer.write_uint32(self.unknown30) writer.write_uint32(self.unknown34) writer.write_uint32(self.unknown38) writer.write_uint32(self.unknown3C) writer.write_uint32(self.unknown_count) writer.write_uint32(self.unknown44) writer.write_uint32(self.unknown48) writer.write_uint32(self.unknown4C) writer.write_uint32(self.archive_names_length) writer.write_uint32(self.file_count3) writer.write_uint32(self.type_names_length) writer.write_uint32(self.zero0C) writer.write_uint32(self.zero10) writer.write_uint32(self.zero14) writer.write_uint32(self.zero18) writer.write_uint32(self.zero1C) writer.write_uint32(self.zero20) writer.write_uint32(self.zero24) writer.write_uint32(self.zero28) writer.write_uint32(self.zero2C) writer.write_uint32(self.zero30) writer.write_uint32(self.zero34) writer.write_uint32(self.zero38) writer.write_uint32(self.zero3C)
def read(self, reader: ByteIO): self.sig = reader.read_fourcc() assert self.sig == 'FRES' self.flags, self.version, self.need_bswap, self.unknown07 = reader.read_fmt( '4B') self.flags2 = reader.read_uint32() self.unknown0C = reader.read_uint32() self.names_length = reader.read_uint32() self.unknown2_count = reader.read_uint32() self.other_count = reader.read_uint32() self.dir_count = reader.read_uint16() self.type_count = reader.read_uint16() self.file_count = reader.read_uint32() self.file_count2 = reader.read_uint32() self.part_count = reader.read_uint32() self.archive_count = reader.read_uint32() self.unknown30 = reader.read_uint32() self.unknown34 = reader.read_uint32() self.unknown38 = reader.read_uint32() self.unknown3C = reader.read_uint32() self.unknown_count = reader.read_uint32() self.unknown44 = reader.read_uint32() self.unknown48 = reader.read_uint32() self.unknown4C = reader.read_uint32() self.archive_names_length = reader.read_uint32() self.file_count3 = reader.read_uint32() self.type_names_length = reader.read_uint32() self.zero0C = reader.read_uint32() self.zero10 = reader.read_uint32() self.zero14 = reader.read_uint32() self.zero18 = reader.read_uint32() self.zero1C = reader.read_uint32() self.zero20 = reader.read_uint32() self.zero24 = reader.read_uint32() self.zero28 = reader.read_uint32() self.zero2C = reader.read_uint32() self.zero30 = reader.read_uint32() self.zero34 = reader.read_uint32() self.zero38 = reader.read_uint32() self.zero3C = reader.read_uint32()
def write(self, writer: ByteIO): writer.write_uint32(self.unknown00) writer.write_uint32(self.data_size)
class HeroFile: me = (2 ** 8) - 1 ge = (2 ** 16) - 1 H = math.pow(2, 16) - 1 X = (math.pow(2, 16) - 2) / 2 def __init__(self, path): self.reader = ByteIO(path=path) self.name = Path(path).name self.version = 0 self.i32_count = 0 self.i16_count = 0 self.i8_count = 0 self.i1_count = 0 self.export_time = 0 self.i32_offset = 0 self.i16_offset = 0 self.i8_offset = 0 self.i1_offset = 0 self.bit_cursor = 0 self._i1_array = [] self.options = {} self.geometry = HeroGeomerty() self.vertex_count = 0 def read_float(self, offset=0): self.reader.seek(self.i32_offset + offset) ret = self.reader.read_float() self.i32_offset += 4 return ret def read_uint32(self, offset=0): self.reader.seek(self.i32_offset + offset) val = self.read_float() ret = round(val) return ret def read_uint16(self, offset=0, increment=True): self.reader.seek(self.i16_offset + offset) ret = self.reader.read_uint16() if increment: self.i16_offset += 2 return ret def read_int8(self, offset=0): self.reader.seek(self.i8_offset + offset) ret = self.reader.read_uint8() self.i8_offset += 1 return ret def read_string(self, offset=0): self.reader.seek(self.i8_offset + offset) l = self.read_int8() ret = self.reader.read_ascii_string(l) self.i8_offset += len(ret) return ret def read_bit(self): bit = self._i1_array[self.bit_cursor] self.bit_cursor += 1 return bit def get_quaternion_array(self, e): e *= 4 r = np.zeros(e) for i in range(e): r[i] = self.read_uint16() / self.H * 2 - 1 return r def get_position_array(self, e, t): n = np.zeros(e * 3) for a in range(e): for r in range(3): n[3 * a + r] = (self.read_uint16() - self.X) / self.X * t return n def get_scale_array(self, e, t): n = np.zeros(e * 3) for a in range(e): for r in range(3): n[3 * a + r] = self.read_uint16() / self.H * t return n def read(self): reader = self.reader self.version = round(reader.read_float(), 2) self.get_start_points() with reader.save_current_pos(): reader.seek(self.i1_offset) for _ in range(math.ceil(self.i1_count / 8)): byte = reader.read_int8() for i in range(8): self._i1_array.append(bool(byte & (1 << i))) self._init_settings() self._init_indices() self._init_points() self._init_normals() self._init_uvs() self._init_vertex_colors() self._init_blends() self._init_weights() self._init_parent() try: self._init_poses(); except: pass def get_bit(self): self.bit_cursor += 1 return self._i1_array[self.bit_cursor - 1] def get_start_points(self): reader = self.reader self.i32_count = reader.read_float_int32() self.i16_count = reader.read_float_int32() self.i8_count = reader.read_float_int32() self.i1_count = reader.read_float_int32() e = 20 if self.version >= 1.4: e += 4 self.export_time = reader.read_float() self.i32_offset = e self.i16_offset = self.i32_offset + 4 * self.i32_count self.i8_offset = self.i16_offset + 2 * self.i16_count self.i1_offset = self.i8_offset + self.i8_count def _init_settings(self): default_attributes = ["mesh", "normals", "uv1", "uv2", "blendTargets", "blendNormals", "weights", "animations", "jointScales", "addon", "paintMapping", "singleParent", "frameMappings", "indices32bit", "originalIndices", "vertexColors"] if self.version >= 1.2: default_attributes.append('posGroups') t = 32 if self.version >= 1.25: default_attributes.append('uvSeams') default_attributes.append('rivets') t -= 2 r = {} for attr in default_attributes: r[attr] = self.get_bit() if self.version >= 1.2: self.bit_cursor += t self.options = r self.geometry.main_skeleton = not self.options['addon'] and self.options['weights'] def _init_indices(self): if self.options['mesh']: indices_count = self.read_uint32() if self.options['indices32bit']: self.geometry.index = [self.read_uint32() for _ in range(indices_count)] else: self.geometry.index = [self.read_uint16() for _ in range(indices_count)] if self.options['originalIndices']: if self.options['indices32bit']: self.geometry.original_indices = [self.read_uint32() for _ in range(indices_count)] else: self.geometry.original_indices = [self.read_uint16() for _ in range(indices_count)] def _init_points(self): if self.options['mesh']: vertex_count = self.read_uint32() if self.options['indices32bit'] else self.read_uint16() self.vertex_count = vertex_count self.geometry.has_geometry = True # Z Y X bbox = [self.read_float() for _ in range(6)] scale = [bbox[3] - bbox[0], bbox[4] - bbox[1], (bbox[5] - bbox[2])] self.geometry.offset = [bbox[0] * scale[0], bbox[1] * scale[1], bbox[2] * scale[2]] self.geometry.bounds = [bbox[0:3], bbox[3:6]] verts = [] for _ in range(vertex_count): verts.append((self.read_uint16() / self.ge * scale[0] + bbox[0], self.read_uint16() / self.ge * scale[1] + bbox[1], self.read_uint16() / self.ge * scale[2] + bbox[2] )) self.geometry.positions = verts def _init_normals(self): if self.options['normals']: if self.vertex_count != 0: normals = [] r = 0 for _ in range(self.vertex_count): normals.append(self.read_int8() / self.me * 2 - 1) normals.append(self.read_int8() / self.me * 2 - 1) normals.append( (2 * self.get_bit() - 1) * (1 - math.pow(normals[r], 2) - math.pow(normals[r + 1], 2))) r += 3 self.geometry.normals = split(normals, 3) def _init_uvs(self): if self.options['uv1']: uvs = ['uv', 'uv2'] if self.options['uv2'] else ['uv'] for uv in uvs: n = [self.read_float() for _ in range(4)] s = [n[2] - n[0], n[3] - n[1]] u = [] for i in range(self.vertex_count): u.append((self.read_uint16() / self.ge * s[0] + n[0], self.read_uint16() / self.ge * s[1] + n[1])) setattr(self.geometry, uv, u) def _init_vertex_colors(self): if self.options['vertexColors']: layer_count = self.read_int8() for t in range(layer_count): layer_name = self.read_string() v_colors = [] for _ in range(self.vertex_count): col = self.read_int8() v_colors.append(col / 255) v_colors.append(col / 255) v_colors.append(col / 255) v_colors.append(1) self.geometry.vertex_colors[layer_name] = np.array(v_colors).reshape((-1, 4)) def _init_blends(self): if self.options['blendTargets']: shape_key_count = self.read_int8() if shape_key_count: shape_key_data = {} for shape_key_id in range(shape_key_count): shape_key_name = self.read_string() o = [self.read_float() for _ in range(6)] u = [o[3] - o[0], o[4] - o[1], o[5] - o[2]] c = [] for d in range(self.vertex_count): c.append(self.read_int8() / self.me * u[0] + o[0]) c.append(self.read_int8() / self.me * u[1] + o[1]) c.append(self.read_int8() / self.me * u[2] + o[2]) shape_key_data[shape_key_name] = split(c, 3) if self.options['blendNormals']: for _ in range(self.vertex_count): self.read_int8() self.read_int8() self.get_bit() self.geometry.shape_key_data = shape_key_data def _init_weights(self): if self.options['weights']: self.geometry.skinned = True weight_per_vert = self.read_int8() additional_weights = max(0, weight_per_vert - 4) skin_indices = np.zeros(4 * self.vertex_count, dtype=np.int16) additional_skin_indices = np.zeros(additional_weights * self.vertex_count, dtype=np.int16) u = 4 if weight_per_vert < 4 else weight_per_vert for l in range(u): if weight_per_vert > l: if l < 4: for t in range(self.vertex_count): skin_indices[4 * t + l] = self.read_uint16(2 * (t * weight_per_vert + l), False) else: for t in range(self.vertex_count): additional_skin_indices[t * additional_weights + (l - 4)] = self.read_uint16( 2 * (t * additional_weights + l), False) self.geometry.skin_indices = skin_indices.reshape((-1, u,)) self.geometry.additional_skin_indices = additional_skin_indices.reshape((-1, u,)) self.i16_offset = self.i16_offset + weight_per_vert * self.vertex_count * 2; skin_weights = np.zeros(4 * self.vertex_count, dtype=np.float32) additional_skin_weights = np.zeros(additional_weights * self.vertex_count, dtype=np.float32) u = 4 if weight_per_vert < 4 else weight_per_vert for f in range(u): if weight_per_vert > f: if f < 4: for c in range(self.vertex_count): skin_weights[4 * c + f] = self.read_uint16(2 * (c * weight_per_vert + f), False) / self.ge else: for c in range(self.vertex_count): additional_skin_weights[c * additional_weights + (f - 4)] = self.read_uint16( 2 * (c * weight_per_vert + f), False) / self.ge self.geometry.skin_weights = skin_weights.reshape((-1, u)) self.geometry.additional_skin_weights = additional_skin_weights.reshape((-1, weight_per_vert)) self.i16_offset = self.i16_offset + weight_per_vert * self.vertex_count * 2 def _init_parent(self): if self.options['singleParent']: name = self.read_string() e = self.read_uint16() r = np.zeros(4 * self.vertex_count) i = np.zeros(4 * self.vertex_count) a = 4 * self.vertex_count for n in range(a): r[n] = e if n % 4 == 0 else 0 i[n] = 1 if n % 4 == 0 else 0 self.geometry.skin_indices = r.reshape((-1, 4)) self.geometry.skin_weights = i.reshape((-1, 4)) def _init_poses(self): if self.options['animations']: bone_count = self.read_int8() if self.options['frameMappings']: n = self.read_uint16() a = [self.read_uint16() for _ in range(n)] if n: i = {} for s in range(n): i[a[s]] = s p = self.read_float() m = self.options['jointScales'] g = self.read_float() if m else 1 poses = {} locators = {} bones = [] for y in range(bone_count): o = self.read_string() l = self.read_uint16() u = self.read_uint16() # print(o, l, u) v = lambda: { "pos": self.get_position_array(1, p) if self.get_bit() else self.get_position_array(u, p), "rot": self.get_quaternion_array(1) if self.get_bit() else self.get_quaternion_array(u), "scl": self.get_scale_array(1, g) if self.get_bit() else self.get_scale_array(u, g) if m else [1, 1, 1], "frameMapping": i if self.options["frameMappings"] else None } if o == 'main': for S in range(l): b = self.read_uint16() w = HeroBone() w.bone_id = S w.name = self.read_string() # print(w.name) if b == 5e3: self.geometry.main_skeleton = True w.parent_id = -1 print(w.name, b, S) else: w.parent_id = b k = v() w.pos = k['pos'] w.quat = k['rot'] w.scale = k['scl'] bones.append(w) elif o == 'locators': for R in range(l): bone = HeroBone() bone.name = self.read_string() C = v() bone.pos = C['pos'] bone.scale = C['cls'] bone.quat = C['rot'] locators[bone.name] = bone else: c = {} for x in range(l): c[self.read_string()] = v() poses[o] = c # print(h) self.geometry.bones = bones self.geometry.poses = poses self.geometry.locations = locators
def read(self, reader: ByteIO): self.unknown00 = reader.read_uint32() self.unknown08 = reader.read_uint64()
def write(self, writer: ByteIO): writer.write_uint32(self.unknown00) writer.write_uint32(self.name_offset) writer.write_uint32(self.unknown08)
def write(self, writer: ByteIO): writer.write_uint32(self.hash) writer.write_uint32(self.name_offset) writer.write_uint32(self.unknown08) writer.write_uint32(self.unknown0C) writer.write_uint32(self.unknown10)
def read(self, reader: ByteIO): self.unknown00 = reader.read_uint32() self.data_size = reader.read_uint32()