Beispiel #1
0
 def get_replace_strings(self):
     try:
         newline = "\n"
         old = self.e_name_old.toPlainText()
         new = self.e_name_new.toPlainText()
         old = old.split(newline)
         new = new.split(newline)
         if len(old) != len(new):
             interaction.showdialog(
                 f"Old {len(old)} and new {len(new)} must have the same amount of lines!"
             )
         return list(zip(old, new))
     except BaseException as err:
         print(err)
Beispiel #2
0
    def create_ovl(self, ovl_dir):
        # clear the ovl
        self.ovl_data = OvlFile(progress_callback=self.update_progress)
        self.game_changed()

        # read tables for constants
        mimes_table = {}
        tables_dir = os.path.join(os.getcwd(), "dicts")
        self.read_table(os.path.join(tables_dir, "mimes.txt"), mimes_table)
        try:
            self.ovl_data.create(ovl_dir, mime_names_dict=mimes_table)
        except Exception as ex:
            traceback.print_exc()
            interaction.showdialog(str(ex))
        self.update_gui_table()
Beispiel #3
0
 def closeEvent(self, event):
     if self.file_widget.dirty:
         quit_msg = f"Quit? You will lose unsaved work on {os.path.basename(self.file_widget.filepath)}!"
         if not interaction.showdialog(quit_msg, ask=True):
             event.ignore()
             return
     event.accept()
Beispiel #4
0
def check_length(name_tups):
	# Ask and return true if error is found and process should be stopped
	for old, new in name_tups:
		if len(old) != len(new):
			if showdialog(f"WARNING: length of '{old}' [{len(old)} chars] and '{new}' [{len(new)} chars] don't match!\n"
							 f"Stop hashing?", ask=True):
				return True
Beispiel #5
0
def load_lua(ovl_data, lua_file_path, lua_sized_str_entry):
    # read lua
    # inject lua buffer
    # update sized string
    # IMPORTANT: all meta data of the lua except the sized str entries lua size value seems to just be meta data, can be zeroed
    with open(lua_file_path, "rb") as lua_stream:
        # load the new buffer
        buffer_bytes = lua_stream.read()
    if b"DECOMPILER ERROR" in buffer_bytes:
        confirmed = showdialog(
            f"{lua_file_path} has not been successfully decompiled and may crash your game. Inject anyway?",
            ask=True)
        if not confirmed:
            return

    buff_size = len(buffer_bytes)
    # update the buffer
    lua_sized_str_entry.data_entry.update_data((buffer_bytes, ))

    ss_len = len(lua_sized_str_entry.pointers[0].data) / 4
    ss_data = struct.unpack("<{}I".format(int(ss_len)),
                            lua_sized_str_entry.pointers[0].data)
    ss_new = struct.pack("<{}I".format(int(ss_len)), buff_size, *ss_data[1:])

    lua_sized_str_entry.pointers[0].update_data(ss_new, update_copies=True)
Beispiel #6
0
 def extract_all(self):
     if self.is_open_ovl():
         out_dir = QtWidgets.QFileDialog.getExistingDirectory(
             self,
             'Output folder',
             self.cfg.get("dir_extract", "C://"),
         )
         if out_dir:
             self.cfg["dir_extract"] = out_dir
             try:
                 out_paths, error_files, skip_files = self.ovl_data.extract(
                     out_dir, self.show_temp_files)
                 interaction.skip_messages(error_files, skip_files)
             except Exception as ex:
                 traceback.print_exc()
                 interaction.showdialog(str(ex))
 def load(self):
     if self.file_widget.filepath:
         self.file_widget.dirty = False
         self.update_progress("Reading OVL " + self.file_widget.filepath,
                              value=0,
                              vmax=0)
         try:
             self.ovl_data.load(self.file_widget.filepath,
                                commands=self.commands,
                                hash_table=self.hash_table)
             self.ovl_data.load_archives()
         except Exception as ex:
             traceback.print_exc()
             interaction.showdialog(str(ex))
         self.update_gui_table()
         game = get_game(self.ovl_data)
         self.game_container.entry.setText(game)
Beispiel #8
0
 def inject_files(self, files):
     """Tries to inject files into self.ovl_data"""
     if files:
         self.cfg["dir_inject"] = os.path.dirname(files[0])
         try:
             error_files, foreign_files = self.ovl_data.inject(
                 files, self.show_temp_files)
             self.file_widget.dirty = True
             if foreign_files:
                 if interaction.showdialog(
                         f"Do you want to add {len(foreign_files)} files to this ovl?",
                         ask=True):
                     self.ovl_data.add_files(foreign_files)
                     self.update_gui_table()
         except Exception as ex:
             traceback.print_exc()
             interaction.showdialog(str(ex))
Beispiel #9
0
 def save_included_ovls(self):
     if self.is_open_ovl():
         filelist_src = QtWidgets.QFileDialog.getSaveFileName(
             self,
             'ovls.include',
             os.path.join(self.cfg.get("dir_ovls_out", "C://"),
                          "ovls.include"),
             "Include file (*.include)",
         )[0]
         if filelist_src:
             try:
                 self.ovl_data.save_included_ovls(filelist_src)
                 self.update_progress("Operation completed!",
                                      value=1,
                                      vmax=1)
             except BaseException as ex:
                 traceback.print_exc()
                 interaction.showdialog(str(ex))
Beispiel #10
0
def species_dat_replacer(ovl, name_tups):
    logging.info(f"Replacing Species Dat contents for {name_tups}")
    if check_length(name_tups):
        return
    name_tups_new = []
    name_tups_new2 = []
    if ovl.user_version.is_jwe:
        suffixes = ("@", "_Var")
        suffixes2 = ("", "@", "_Var")
        for old, new in name_tups:
            extend_name_tuples(name_tups_new, new, old, suffixes)
            extend_name_tuples(name_tups_new2, new, old, suffixes2)
    else:
        suffixes = []
        for gender in ("_Female", "_Male", "_Juvenile", ""):
            # various hardcoded suffixes
            for sym in ("@", "_Mat", "_Skin", "_Skin_NoDirt", "_Fur",
                        "_Fur_Shell", "_Fur_Fin", "_Eyeball", "_Eyes", "_Eye",
                        "_EyeMouthClaws", "_Whiskers", "_Hair", "_Feathers",
                        "_Teeth", ""):
                suffixes.append(f"{gender}{sym}")
            # lods
            for i in range(7):
                suffixes.append(f"{gender}_l{i}")
        for old, new in name_tups:
            extend_name_tuples(name_tups_new, new, old, suffixes)
    try:
        # hash the internal buffers
        for archive_entry in ovl.archives:
            ovs = archive_entry.content
            for pool in ovs.pools:
                b = pool.data.getvalue()
                pool.data = io.BytesIO(replace_bytes(b, name_tups_new))
            ovs.populate_pointers()
            for buffer_entry in ovs.buffer_entries:
                if ovl.user_version.is_jwe:
                    b = buffer_entry.data
                    buffer_entry.data = replace_bytes(b, name_tups_new2)
                else:
                    b = buffer_entry.data
                    buffer_entry.data = replace_bytes(b, name_tups_new)
    except Exception as err:
        showdialog(err)
    logging.info("Finished DAT replacing")
Beispiel #11
0
	def load(self, ms2_file_path):
		logging.info(f"Injecting MS2")
		versions = get_versions(self.ovl)

		ms2_file = Ms2File()
		ms2_file.load(ms2_file_path, read_bytes=True)

		missing_materials = set()
		for model_info, mdl2_name, mdl2_entry in zip(ms2_file.model_infos, ms2_file.mdl_2_names, self.sized_str_entry.children):
			for material in model_info.model.materials:
				fgm_name = f"{material.name.lower()}.fgm"
				if ovl_versions.is_jwe(self.ovl) or ovl_versions.is_jwe2(self.ovl) and fgm_name == "airliftstraps.fgm":
					# don't cry about this
					continue
				if fgm_name not in self.ovl._ss_dict:
					missing_materials.add(fgm_name)
			if len(mdl2_entry.model_data_frags) != len(model_info.model.meshes):
				raise AttributeError(
					f"{mdl2_entry.name} ({len(model_info.model.meshes)}) doesn't have the "
					f"expected amount ({len(mdl2_entry.model_data_frags)}) of meshes!")
		if missing_materials:
			mats = '\n'.join(missing_materials)
			msg = f"The following materials are used by {self.file_entry.name}, but are missing from the OVL:\n" \
				f"{mats}\n" \
				f"This will crash unless you are importing the materials from another OVL. Inject anyway?"
			if not interaction.showdialog(msg, ask=True):
				logging.info("Injection was canceled by the user")
				return

		for mdl2_entry, model_info in zip(self.sized_str_entry.children, ms2_file.model_infos):
			logging.debug(f"Injecting {mdl2_entry.name} ")
	
			materials, lods, objects, meshes, model_info_ptr = mdl2_entry.fragments
			for frag, mdl2_list in (
					(materials, model_info.model.materials,),
					(lods, model_info.model.lods),
					(objects, model_info.model.objects),
					(meshes, model_info.model.meshes)):
				if len(mdl2_list) > 0:
					data = as_bytes(mdl2_list, version_info=versions)
					# objects.pointers[1] has padding in stock, apparently as each entry is 4 bytes
					logging.debug(f"Injecting mdl2 data {len(data)} into {len(frag.pointers[1].data)} ({len(frag.pointers[1].padding)})")
					# frag.pointers[1].update_data(data, pad_to=8)
					# the above breaks injecting minmi
					frag.pointers[1].update_data(data)
					logging.debug(f"Result {len(frag.pointers[1].data)} ({len(frag.pointers[1].padding)})")

		# load ms2 ss data
		self.sized_str_entry.pointers[0].update_data(as_bytes(ms2_file.info, version_info=versions))
	
		buffer_info_frag, model_info_frag, end_frag = self.sized_str_entry.fragments
		buffer_info_frag.pointers[1].update_data(as_bytes(ms2_file.buffer_info, version_info=versions), update_copies=True)
		model_info_frag.pointers[1].update_data(as_bytes(ms2_file.model_infos, version_info=versions))
	
		# update ms2 data
		self.sized_str_entry.data_entry.update_data(ms2_file.buffers)
Beispiel #12
0
def dat_replacer(ovl, name_tups):
    logging.info(f"Replacing Dat contents for {name_tups}")
    if check_length(name_tups):
        return
    name_tups_new = [(name_bytes(o), name_bytes(n)) for o, n in name_tups]
    try:
        # hash the internal buffers
        for archive_entry in ovl.archives:
            ovs = archive_entry.content
            for pool in ovs.pools:
                b = pool.data.getvalue()
                pool.data = io.BytesIO(replace_bytes(b, name_tups_new))
            ovs.populate_pointers()
    # for buffer_entry in ovs.buffer_entries:
    # 	b = buffer_entry.data
    # 	buffer_entry.data = replace_bytes(b, name_tups)
    except Exception as err:
        showdialog(err)
    logging.info("Done!")
Beispiel #13
0
 def handle_path(self, save_over=True):
     # get path
     if self.in_folder.isChecked():
         root_dir = self.get_selected_dir()
         if root_dir:
             # walk path
             ovls = walker.walk_type(root_dir, extension=".ovl")
             for ovl_path in ovls:
                 # open ovl file
                 self.file_widget.decide_open(ovl_path)
                 # process each
                 yield self.ovl_data
                 if save_over:
                     self.ovl_data.save(ovl_path, "")
         else:
             interaction.showdialog("Select a root directory!")
     # just the one that's currently open
     else:
         yield self.ovl_data
Beispiel #14
0
	def _get_data(self, file_path):
		"""Loads and returns the data for a LUA"""
		buffer_0 = self.get_content(file_path)
		if b"DECOMPILER ERROR" in buffer_0:
			confirmed = showdialog(
				f"{file_path} has not been successfully decompiled and may crash your game. Inject anyway?", ask=True)
			if not confirmed:
				raise UserWarning(f"Injection aborted for {file_path}")
		# 4 uint, 2 ptrs, 16 unused bytes
		ss = struct.pack("4I 2Q 2Q", len(buffer_0), 16000, 0, 0, 0, 0, 0, 0)
		return ss, buffer_0
Beispiel #15
0
 def save_ovl(self):
     if self.is_open_ovl():
         file_src = QtWidgets.QFileDialog.getSaveFileName(
             self,
             'Save OVL',
             os.path.join(self.cfg.get("dir_ovls_out", "C://"),
                          self.file_widget.filename),
             "OVL files (*.ovl)",
         )[0]
         if file_src:
             self.cfg["dir_ovls_out"], ovl_name = os.path.split(file_src)
             try:
                 self.ovl_data.save(file_src, self.use_ext_dat,
                                    self.dat_widget.filepath)
                 self.file_widget.dirty = False
                 self.update_progress("Operation completed!",
                                      value=1,
                                      vmax=1)
             except BaseException as ex:
                 traceback.print_exc()
                 interaction.showdialog(str(ex))
Beispiel #16
0
    def save_file_list(self):
        if self.is_open_ovl():
            filelist_src = QtWidgets.QFileDialog.getSaveFileName(
                self,
                'Save File List',
                os.path.join(self.cfg.get("dir_ovls_out", "C://"),
                             self.file_widget.filename + ".files.txt"),
                "Txt file (*.txt)",
            )[0]
            if filelist_src:
                try:
                    file_names = self.files_container.table.get_files()
                    with open(filelist_src, 'w') as f:
                        f.write("\n".join(file_names))

                    self.update_progress("Operation completed!",
                                         value=1,
                                         vmax=1)
                except BaseException as ex:
                    traceback.print_exc()
                    interaction.showdialog(str(ex))
Beispiel #17
0
    def startDrag(self, actions):
        """Starts a drag from inside the app towards the outside"""
        drag = QtGui.QDrag(self)
        names = self.get_selected_files()
        print("DRAGGING", names)
        try:
            temp_dir = tempfile.gettempdir()
            out_paths, errors, skips = self.main_window.ovl_data.extract(
                temp_dir,
                only_names=names,
                show_temp_files=self.main_window.show_temp_files)

            data = QtCore.QMimeData()
            data.setUrls(
                [QtCore.QUrl.fromLocalFile(path) for path in out_paths])
            drag.setMimeData(data)
            drag.exec_()
        except BaseException as ex:
            traceback.print_exc()
            showdialog(str(ex))
            print(ex)
Beispiel #18
0
    def drag_files(self, file_names):
        logging.info(f"DRAGGING {file_names}")
        drag = QtGui.QDrag(self)
        temp_dir = tempfile.mkdtemp("-cobra")
        try:
            out_paths, errors = self.ovl_data.extract(
                temp_dir,
                only_names=file_names,
                show_temp_files=self.show_temp_files)

            data = QtCore.QMimeData()
            data.setUrls(
                [QtCore.QUrl.fromLocalFile(path) for path in out_paths])
            drag.setMimeData(data)
            drag.exec_()
            logging.info(
                f"Tried to extract {len(file_names)} files, got {len(errors)} errors"
            )
        except BaseException as ex:
            traceback.print_exc()
            interaction.showdialog(str(ex))
            logging.error(ex)
        shutil.rmtree(temp_dir)
Beispiel #19
0
 def is_open_ovl(self):
     if not self.file_widget.filename:
         interaction.showdialog("You must open an OVL file first!")
     else:
         return True
Beispiel #20
0
 def load(self):
     if self.file_widget.filepath:
         self.file_widget.dirty = False
         try:
             # runTask(self.ovl_data.load, (self.file_widget.filepath,), {"commands": self.commands,})
             # test(2)
             # self.ovl_thread.func = self.ovl_thread.ovl_data.load
             # self.ovl_thread.args = (self.file_widget.filepath,)
             # self.ovl_thread.kwargs = {"commands": self.commands,}
             # self.ovl_thread.start()
             self.ovl_data.load(self.file_widget.filepath,
                                commands=self.commands)
             # print(self.ovl_data.user_version)
             # print(self.ovl_data)
             # for a in self.ovl_data.archives:
             # 	print(a)
             # for a in self.ovl_data.archives[1:]:
             # 	print(a.name)
             # 	for ss in a.content.sized_str_entries:
             # 		print(ss.name)
             # print(self.ovl_data.mimes)
             # print(self.ovl_data.triplets)
             # for a, z in zip(self.ovl_data.archives, self.ovl_data.zlibs):
             # 	print(a, z)
             # 	print(f"zlib sum {z.zlib_thing_1 + z.zlib_thing_2 - 68}")
             # 	print(f"pool size {a.pools_end - a.pools_start}")
             # 	print(f"stream links size {12 * a.num_files}")
             # 	print(f"buffer size {sum([buff.size for buff in a.content.buffer_entries])}")
             # 	print(f"d1 size {sum([data.size_1 for data in a.content.data_entries])}")
             # 	print(f"d2 size {sum([data.size_2 for data in a.content.data_entries])}")
             # 	if a.name != "STATIC":
             # 		streams = self.ovl_data.stream_files[a.stream_files_offset: a.stream_files_offset+a.num_files]
             # 		print(a.name, streams)
             # print(self.ovl_data.stream_files)
             # for i, f in enumerate(self.ovl_data.files):
             # 	if f.ext == ".texturestream":
             # 		print(i, f.name)
             # offsets = list(sorted((f.file_offset, i) for i, f in enumerate(self.ovl_data.stream_files)))
             # # print(self.ovl_data)
             # print(offsets)
             # # for a in self.ovl_data.archives[1:]:
             # # 	print(a.content)
             # for sf in self.ovl_data.stream_files:
             # 	print(sf)
             # 	for a in self.ovl_data.archives:
             # 		if a.pools_start <= sf.stream_offset < a.pools_end:
             # 			print(f"is in {a.name}")
             # 			print(f"pool offset relative {sf.stream_offset - a.pools_start}")
             # 			# print(a.content.sized_str_entries)
             # 	for a in self.ovl_data.archives:
             # 		if a.name == "STATIC":
             # 			for i, pool in enumerate(a.content.pools):
             # 				if pool.offset <= sf.file_offset < pool.offset + pool.size:
             # 					print(f"static pool {i} offset relative {sf.file_offset - pool.offset}")
             # 	logging.debug(a.content)
             # print(self.ovl_data.user_version)
         except Exception as ex:
             traceback.print_exc()
             interaction.showdialog(str(ex))
             print(self.ovl_data)
         self.update_gui_table()
         game = get_game(self.ovl_data)[0]
         self.game_choice.entry.setText(game.value)
         self.compression_choice.entry.setText(
             self.ovl_data.user_version.compression.name)