def write_voxelskirt(archive, sized_str_entry, out_dir): name = sized_str_entry.name print(f"\nWriting {name}") ovl_header = pack_header(archive, b"VOXE") out_path = out_dir(name) buffers = sized_str_entry.data_entry.buffer_datas # write voxelskirt with open(out_path, 'wb') as outfile: # write the sized str and buffers # print(sized_str_entry.pointers[0].data) outfile.write(ovl_header) outfile.write(sized_str_entry.pointers[0].data) for buff in buffers: outfile.write(buff) return out_path,
def write_enumnamer(ovl, sized_str_entry, out_dir, show_temp_files, progress_callback): name = sized_str_entry.name print(f"\nWriting {name}") ovl_header = pack_header(ovl, b"ENUM") out_path = out_dir(name) # buffers = sized_str_entry.data_entry.buffer_datas # write voxelskirt with open(out_path, 'wb') as outfile: # write the sized str and buffers # print(sized_str_entry.pointers[0].data) outfile.write(ovl_header) outfile.write(sized_str_entry.pointers[0].data) # print(sized_str_entry.pointers[0].address) for f in sized_str_entry.vars: # print(f) # print(f.pointers[1].data) outfile.write(f.pointers[1].data) return out_path,
def write_specdef(ovl, sized_str_entry, out_dir, show_temp_files, progress_callback): name = sized_str_entry.name print(f"\nWriting {name}") ovl_header = pack_header(ovl, b"SPEC") out_path = out_dir(name) # save .bin data with open(out_path + ".bin", 'wb') as outfile: print("Exporting binary specdef file") outfile.write(ovl_header) outfile.write(sized_str_entry.pointers[0].data) for f in sized_str_entry.fragments: outfile.write(f.pointers[1].data) outfile.close() # save .text file with open(out_path, 'w') as outfile: print("Exporting text specdef file") attribcount, flags, namecount, childspeccount, managercount, scriptcount = struct.unpack( "<2H4B", sized_str_entry.pointers[0].data) outfile.write(f"Name : {name}\nFlags: {flags:x}\n") #debug print all fragments #for f in sized_str_entry.fragments: # print(f.pointers[1].data) # skip frags here based on counts offset = 3 + (namecount > 0) + (childspeccount > 0) + ( managercount > 0) + (scriptcount > 0) if attribcount > 0: outfile.write(f"Attributes:\n") lend = len(sized_str_entry.fragments[0].pointers[1].data) #this frag has padding dtypes = struct.unpack( f"<{attribcount}I", sized_str_entry.fragments[0].pointers[1].data[:4 * attribcount]) for i in range(0, attribcount): iname = sized_str_entry.fragments[ offset + i].pointers[1].data.decode().rstrip('\x00') dtype = dtypes[i] #todo: the tflags structure depends on the dtype value #tflags = struct.unpack(f"<{4}I", sized_str_entry.fragments[offset + attribcount + i].pointers[1].data) tflags = sized_str_entry.fragments[offset + attribcount + i].pointers[1].data outstr = f" - Type: {dtype:02} Name: {iname} Flags: {tflags}" #print(outstr) outfile.write(outstr + "\n") # skip the attrib names and data offset += 2 * attribcount if namecount > 0: outfile.write(f"Names:\n") for i in range(0, namecount): iname = sized_str_entry.fragments[ offset + i].pointers[1].data.decode().rstrip('\x00') outstr = f" - Name: {iname}" #print(outstr) outfile.write(outstr + "\n") # skip the names offset += namecount if childspeccount > 0: outfile.write(f"Child Specdefs:\n") for i in range(0, childspeccount): iname = sized_str_entry.fragments[ offset + i].pointers[1].data.decode().rstrip('\x00') outstr = f" - Specdef: {iname}" #print(outstr) outfile.write(outstr + "\n") # skip the names offset += childspeccount if managercount > 0: outfile.write(f"Managers:\n") for i in range(0, managercount): iname = sized_str_entry.fragments[ offset + i].pointers[1].data.decode().rstrip('\x00') outstr = f" - Manager: {iname}" #print(outstr) outfile.write(outstr + "\n") # skip the names offset += managercount if scriptcount > 0: outfile.write(f"Scripts:\n") for i in range(0, scriptcount): iname = sized_str_entry.fragments[ offset + i].pointers[1].data.decode().rstrip('\x00') outstr = f" - Script: {iname}" #print(outstr) outfile.write(outstr + "\n") outfile.close() return out_path + ".bin", out_path,
def write_ms2(ovl, ms2_sized_str_entry, out_dir): name = ms2_sized_str_entry.name if not ms2_sized_str_entry.data_entry: print("No data entry for ", name) return buffers = ms2_sized_str_entry.data_entry.buffer_datas if len(buffers) == 3: bone_names, bone_matrices, verts = buffers elif len(buffers) == 2: bone_names, verts = buffers bone_matrices = b"" else: raise BufferError(f"Wrong amount of buffers for {name}\nWanted 2 or 3 buffers, got {len(buffers)}") # sizedstr data has bone count ms2_general_info_data = ms2_sized_str_entry.pointers[0].data[:24] # ms2_general_info = ms2_sized_str_entry.pointers[0].load_as(Ms2SizedStrData, version_info=versions) # print("Ms2SizedStrData", ms2_sized_str_entry.pointers[0].address, ms2_general_info) ovl_header = pack_header(ovl, b"MS2 ") ms2_header = struct.pack("<2I", len(bone_names), len(bone_matrices)) print("\nWriting", name) print("\nbuffers", len(buffers)) # for i, buffer in enumerate(buffers): # p = out_dir(name+str(i)+".ms2") # with open(p, 'wb') as outfile: # outfile.write(buffer) # Planet coaster if is_pc(ovl.ovl) or is_ed(ovl.ovl): # only ss entry holds any useful stuff ms2_buffer_info_data = b"" next_model_info_data = b"" # Planet Zoo, JWE else: if len(ms2_sized_str_entry.fragments) != 3: print("must have 3 fragments") return f_0, f_1, f_2 = ms2_sized_str_entry.fragments # f0 has information on vert & tri buffer sizes ms2_buffer_info_data = f_0.pointers[1].data # this fragment informs us about the model count of the next mdl2 that is read # so we can use it to collect the variable mdl2 fragments describing a model each next_model_info_data = f_1.pointers[1].data # next_model_info = f_1.pointers[1].load_as(CoreModelInfo, version_info=versions) # print("next_model_info", f_1.pointers[1].address, next_model_info) # write the ms2 file out_path = out_dir(name) out_paths = [out_path, ] with open(out_path, 'wb') as outfile: outfile.write(ovl_header) outfile.write(ms2_header) outfile.write(ms2_general_info_data) outfile.write(ms2_buffer_info_data) outfile.write(bone_names) outfile.write(bone_matrices) outfile.write(verts) # zeros = [] # ones = [] bone_info_index = 0 # export each mdl2 for mdl2_index, mdl2_entry in enumerate(ms2_sized_str_entry.children): mdl2_path = out_dir(mdl2_entry.name) out_paths.append(mdl2_path) with open(mdl2_path, 'wb') as outfile: print("Writing", mdl2_entry.name, mdl2_index) mdl2_header = struct.pack("<2I", mdl2_index, bone_info_index) outfile.write(ovl_header) outfile.write(mdl2_header) # pack ms2 name as a sized string write_sized_str(outfile, ms2_sized_str_entry.name) if not (is_pc(ovl.ovl) or is_ed(ovl.ovl)): # the fixed fragments green_mats_0, blue_lod, orange_mats_1, yellow_lod0, pink = mdl2_entry.fragments print("model_count", mdl2_entry.model_count) # write the model info for this model, buffered from the previous model or ms2 (pink fragments) outfile.write(next_model_info_data) # print("PINK",pink.pointers[0].address,pink.pointers[0].data_size,pink.pointers[1].address, pink.pointers[1].data_size) if pink.pointers[0].data_size == 40: # 40 bytes (0,1 or 0,0,0,0) has_bone_info = pink.pointers[0].data elif (is_jwe(ovl.ovl) and pink.pointers[0].data_size == 144) \ or (is_pz(ovl.ovl) and pink.pointers[0].data_size == 160): # read model info for next model, but just the core part without the 40 bytes of 'padding' (0,1,0,0,0) next_model_info_data = pink.pointers[0].data[40:] has_bone_info = pink.pointers[0].data[:40] # core_model_data = pink.pointers[0].load_as(Mdl2ModelInfo, version_info=versions) # print(core_model_data) else: raise ValueError(f"Unexpected size {len(pink.pointers[0].data)} for pink fragment for {mdl2_entry.name}") core_model_data = struct.unpack("<5Q", has_bone_info) # print(core_model_data) var = core_model_data[1] bone_info_index += var # if var == 1: # ones.append((mdl2_index, mdl2_entry.name)) # elif var == 0: # zeros.append((mdl2_index, mdl2_entry.name)) # avoid writing bad fragments that should be empty if mdl2_entry.model_count: # need not write lod0 for f in (green_mats_0, blue_lod, orange_mats_1): # print(f.pointers[0].address,f.pointers[0].data_size,f.pointers[1].address, f.pointers[1].data_size) other_data = f.pointers[1].data outfile.write(other_data) # data 0 must be empty assert(f.pointers[0].data == b'\x00\x00\x00\x00\x00\x00\x00\x00') # print("modeldata frags") for f in mdl2_entry.model_data_frags: # each address_0 points to ms2's f_0 address_1 (size of vert & tri buffer) # print(f.pointers[0].address,f.pointers[0].data_size,f.pointers[1].address, f.pointers[1].data_size) # model_data = f.pointers[0].load_as(ModelData, version_info=versions) # print(model_data) model_data = f.pointers[0].data outfile.write(model_data) # print("ones", len(ones), ones) # print("zeros", len(zeros), zeros) return out_paths
def write_ms2(ovl, ms2_sized_str_entry, out_dir, show_temp_files, progress_callback): name = ms2_sized_str_entry.name assert ms2_sized_str_entry.data_entry buffers = ms2_sized_str_entry.data_entry.stream_datas name_buffer = buffers[0] bone_infos = buffers[1] verts = b"".join(buffers[2:]) for i, vbuff in enumerate(buffers[2:]): print(f"Vertex buffer {i}, size {len(vbuff)} bytes") print("\nWriting", name) print("buffers", len(buffers)) print( f"name_buffer: {len(name_buffer)}, bone_infos: {len(bone_infos)}, verts: {len(verts)}" ) # sizedstr data has bone count ms2_general_info_data = ms2_sized_str_entry.pointers[0].data[:24] # print("ms2 ss rest", ms2_sized_str_entry.pointers[0].data[24:]) # ms2_general_info = ms2_sized_str_entry.pointers[0].load_as(Ms2SizedStrData, version_info=versions) # print("Ms2SizedStrData", ms2_sized_str_entry.pointers[0].address, ms2_general_info) ovl_header = pack_header(ovl, b"MS2 ") ms2_header = struct.pack("<2I", len(name_buffer), len(bone_infos)) # for i, buffer in enumerate(buffers): # p = out_dir(name+str(i)+".ms2") # with open(p, 'wb') as outfile: # outfile.write(buffer) # Planet coaster if is_pc(ovl) or is_ztuac(ovl): # only ss entry holds any useful stuff ms2_buffer_info_data = b"" next_model_info_data = b"" # Planet Zoo, JWE else: if len(ms2_sized_str_entry.fragments) != 3: print("must have 3 fragments") return f_0, f_1, f_2 = ms2_sized_str_entry.fragments # f0 has information on vert & tri buffer sizes ms2_buffer_info_data = f_0.pointers[1].data # this fragment informs us about the model count of the next mdl2 that is read # so we can use it to collect the variable mdl2 fragments describing a model each next_model_info_data = f_1.pointers[1].data # next_model_info = f_1.pointers[1].load_as(CoreModelInfo, version_info=versions) # print("next_model_info", f_1.pointers[1].address, next_model_info) # write the ms2 file out_path = out_dir(name) out_paths = [ out_path, ] with open(out_path, 'wb') as outfile: outfile.write(ovl_header) outfile.write(ms2_header) outfile.write(ms2_general_info_data) outfile.write(ms2_buffer_info_data) outfile.write(name_buffer) outfile.write(bone_infos) outfile.write(verts) # zeros = [] # ones = [] bone_info_index = 0 # export each mdl2 for mdl2_index, mdl2_entry in enumerate(ms2_sized_str_entry.children): mdl2_path = out_dir(mdl2_entry.name) out_paths.append(mdl2_path) with open(mdl2_path, 'wb') as outfile: print("Writing", mdl2_entry.name, mdl2_index) mdl2_header = struct.pack("<2I", mdl2_index, bone_info_index) outfile.write(ovl_header) outfile.write(mdl2_header) # pack ms2 name as a sized string write_sized_str(outfile, ms2_sized_str_entry.name) if not (is_pc(ovl) or is_ztuac(ovl)): # the fixed fragments materials, lods, objects, model_data_ptr, model_info = mdl2_entry.fragments print("num_models", mdl2_entry.num_models) # write the model info for this model, buffered from the previous model or ms2 (model_info fragments) outfile.write(next_model_info_data) # print("model_info",model_info.pointers[0].address,model_info.pointers[0].data_size,model_info.pointers[1].address, model_info.pointers[1].data_size) if model_info.pointers[0].data_size == 40: # 40 bytes (0,1 or 0,0,0,0) has_bone_info = model_info.pointers[0].data elif (is_jwe(ovl) and model_info.pointers[0].data_size == 144) \ or (is_pz(ovl) and model_info.pointers[0].data_size == 160): # read model info for next model, but just the core part without the 40 bytes of 'padding' (0,1,0,0,0) next_model_info_data = model_info.pointers[0].data[40:] has_bone_info = model_info.pointers[0].data[:40] # core_model_data = model_info.pointers[0].load_as(Mdl2ModelInfo, version_info=versions) # print(core_model_data) else: raise ValueError( f"Unexpected size {len(model_info.pointers[0].data)} for model_info fragment for {mdl2_entry.name}" ) core_model_data = struct.unpack("<5Q", has_bone_info) # print(core_model_data) var = core_model_data[1] bone_info_index += var # if var == 1: # ones.append((mdl2_index, mdl2_entry.name)) # elif var == 0: # zeros.append((mdl2_index, mdl2_entry.name)) # avoid writing bad fragments that should be empty if mdl2_entry.num_models: # need not write model_data_ptr for f in (materials, lods, objects): # print(f.pointers[0].address,f.pointers[0].data_size,f.pointers[1].address, f.pointers[1].data_size) outfile.write(f.pointers[1].data) # data 0 must be empty assert f.pointers[ 0].data == b'\x00\x00\x00\x00\x00\x00\x00\x00' # print("modeldata frags") for f in mdl2_entry.model_data_frags: # each address_0 points to ms2's f_0 address_1 (size of vert & tri buffer) # print(f.pointers[0].address,f.pointers[0].data_size,f.pointers[1].address, f.pointers[1].data_size) # model_data = f.pointers[0].load_as(ModelData, version_info=versions) # print(model_data) outfile.write(f.pointers[0].data) # print("ones", len(ones), ones) # print("zeros", len(zeros), zeros) return out_paths
def write_fgm(ovl, sized_str_entry, out_dir, show_temp_files, progress_callback): name = sized_str_entry.name print("\nWriting", name) try: buffer_data = sized_str_entry.data_entry.buffer_datas[0] print("buffer size", len(buffer_data)) except: print("Found no buffer data for", name) buffer_data = b"" # basic fgms if len(sized_str_entry.fragments) == 4: tex_info, attr_info, zeros, data_lib = sized_str_entry.fragments len_tex_info = tex_info.pointers[1].data_size len_zeros = zeros.pointers[1].data_size # no zeros, otherwise same as basic elif len(sized_str_entry.fragments) == 3: tex_info, attr_info, data_lib = sized_str_entry.fragments len_tex_info = tex_info.pointers[1].data_size len_zeros = 0 # fgms for variants elif len(sized_str_entry.fragments) == 2: attr_info, data_lib = sized_str_entry.fragments len_tex_info = 0 len_zeros = 0 else: raise AttributeError("Fgm length is wrong") # grab the texture names that are linked to this fgm fgm_file_entry = get_file_entry(ovl, sized_str_entry) # write fgm fgm_header = struct.pack( "<6I", len(sized_str_entry.fragments), len(fgm_file_entry.dependencies), len_tex_info, attr_info.pointers[1].data_size, len_zeros, data_lib.pointers[1].data_size, ) # print(file_entry.textures) out_path = out_dir(name) # for i, f in enumerate(sized_str_entry.fragments): # with open(out_path+str(i), 'wb') as outfile: # outfile.write( f.pointers[1].data ) with open(out_path, 'wb') as outfile: # write custom FGM header outfile.write(pack_header(ovl, b"FGM ")) outfile.write(fgm_header) for tex in fgm_file_entry.dependencies: outfile.write(tex.basename.encode()) outfile.write(b"\x00") outfile.write(sized_str_entry.pointers[0].data) # write each of the fragments for frag in sized_str_entry.fragments: outfile.write(frag.pointers[1].data) # write the buffer outfile.write(buffer_data) return out_path,