def tag_browse(self): if self._extracting: return filetypes = [('All', '*')] for def_id in sorted(self.tag_data_extractors.keys()): if def_id in self.tag_class_fcc_to_ext: filetypes.append( (def_id, "." + self.tag_class_fcc_to_ext[def_id])) fp = askopenfilename(initialdir=str(self.app_root.last_load_dir), filetypes=filetypes, parent=self, title="Select a tag to extract from") if not fp: return fp = Path(fp) self.app_root.last_load_dir = fp.parent if not is_in_dir(fp, self.handler.tagsdir): print("Tag %s is not located in tags directory %s" % (fp, self.handler.tagsdir)) return self.app_root.last_load_dir = fp.parent self.tag_path.set(fp)
def scenario_browse(self): dirpath = askopenfilename(initialdir=self.scenario_path.get(), parent=self, title="Select scenario to remove sauce from") if not dirpath: return self.app_root.last_load_dir = os.path.dirname(dirpath) self.scenario_path.set(dirpath)
def get_tags(coll_path, model_in_path): mod2_path = str(Path(model_in_path).with_suffix('')) + "_COLL.gbxmodel" # get whether or not the collision tag is stubbs stubbs = tag_header_def.build(filepath=coll_path).version == 11 if stubbs: coll_tag = stubbs_coll_def.build(filepath=coll_path) else: coll_tag = coll_def.build(filepath=coll_path) mod2_tag = mod2_def.build() mod2_tag.filepath = mod2_path model_in_rawdata = None guessed_mode = False while model_in_rawdata is None and model_in_path: try: model_in_rawdata = get_rawdata(filepath=model_in_path) except Exception: if guessed_mode: model_in_rawdata = None model_in_path = Path(askopenfilename( initialdir=model_in_path.parent, filetypes=( ('All', '*'), ('Gbxmodel', '*.gbxmodel')), title="Select the gbxmodel to extract nodes from")) else: model_in_path = model_in_path.with_suffix(".model") guessed_mode = True if model_in_rawdata is not None: # we dont actually care about the geometries or shaders of the gbxmodel # tag we're loading, so null them out to speed up the loading process. geom_off = 64 + 4*9 + 2*5 + 126 + 12*3 # make a copy so we dont edit the file model_in_rawdata = bytearray(model_in_rawdata) model_in_rawdata[geom_off:64 + 232] = b'\x00'*(64 + 232 - geom_off) if model_in_rawdata[36:40] == b"mod2": model_in_tag = mod2_def.build(rawdata=model_in_rawdata) elif stubbs: model_in_tag = stubbs_mode_def.build(rawdata=model_in_rawdata) else: model_in_tag = mode_def.build(rawdata=model_in_rawdata) mod2_tag.data.tagdata.nodes = model_in_tag.data.tagdata.nodes else: model_in_tag = None mod2_tag.data.tagdata.nodes.STEPTREE.append() node = mod2_tag.data.tagdata.nodes.STEPTREE[-1] node.name = "COLLISION ROOT" print(" %s" % model_in_path) print(" Could not load gbxmodel. Gbxmodel wont have nodes and " "the geometry will not be positioned or rotated properly.") return coll_tag, model_in_tag, mod2_tag
def tag_path_browse(self): initialdir = self.tag_path.get() if not initialdir: initialdir = self.tags_dir.get() filetypes = (("%s tag" % self.src_ext, "*.%s" % self.src_ext), ) filetypes += tuple(("%s tag" % ext, "*.%s" % ext) for ext in self.src_exts if ext != self.src_ext) filetypes += (('All', '*'), ) tag_path = askopenfilename(initialdir=initialdir, filetypes=filetypes) if tag_path: self.tag_path.set(tag_path)
def browse(self): if self._zipping: return filetypes = [('All', '*')] defs = self.app_root.handler.defs for def_id in sorted(defs.keys()): filetypes.append((def_id, defs[def_id].ext)) fp = askopenfilename(title="Select a tag", filetypes=filetypes, parent=self, initialdir=self.app_root.last_load_dir) if not fp: return self.app_root.last_load_dir = Path(fp).parent self.tag_filepath.set(fp)
def model_animations_path_browse(self, force=False): if not force and (self._working or self._loading): return antr_dir = os.path.dirname(self.model_animations_path.get()) if self.model_animations_dir.get() and not antr_dir: antr_dir = self.model_animations_dir.get() fp = askopenfilename(initialdir=antr_dir, title="Model_animations to compress/decompress", parent=self, filetypes=(("Model animations graph", "*.model_animations"), ('All', '*'))) if not fp: return fp = Path(fp) if not fp.suffix: fp = fp.with_suffix(".model_animations") self.app_root.last_load_dir = str(fp.parent) self.model_animations_path.set(str(fp))
def hud_message_text_from_hmt(app, fp=None): load_dir = app.last_data_load_dir tags_dir = app.tags_dir data_dir = app.data_dir if is_path_empty(tags_dir): tags_dir = Path("") if is_path_empty(data_dir): data_dir = Path("") if is_path_empty(load_dir): load_dir = data_dir if is_path_empty(fp): fp = askopenfilename( initialdir=load_dir, parent=app, filetypes=(("HUD messages", "*.hmt"), ("All", "*")), title="Select hmt file to turn into a hud_message_text tag") fp = Path(fp) if is_path_empty(fp): return try: app.last_data_load_dir = fp.parent print("Creating hud_message_text from this hmt file:") print(" %s" % fp) with fp.open("r", encoding=hacky_detect_encoding(fp)) as f: hmt_string_data = f.read() except Exception: print(format_exc()) print(" Could not load hmt file.") return try: rel_filepath = fp.relative_to(data_dir) except ValueError: rel_filepath = Path("hud messages") rel_filepath = rel_filepath.with_suffix(".hud_message_text") tag_path = Path("") if not is_path_empty(rel_filepath): tag_path = tags_dir.joinpath(rel_filepath) # make the tag window window = app.load_tags( filepaths=(tag_path, ) if tag_path.is_file() else "", def_id='hmt ') if not window: return window = window[0] window.is_new_tag = False window.tag.filepath = tag_path window.tag.rel_filepath = rel_filepath error = compile_hud_message_text(window.tag, hmt_string_data) # reload the window to display the newly entered info window.reload() app.update_tag_window_title(window) if error: print(" Errors occurred while compiling. " + "Tag will not be automatically saved.") window.is_new_tag = True elif not tag_path.is_file(): # save the tag if it doesnt already exist app.save_tag()
def import_node(self): '''Prompts the user for an exported node file. Imports data into the node from the file.''' if None in (self.parent, self.node): return try: initialdir = self.tag_window.app_root.last_load_dir except AttributeError: initialdir = None ext = self.field_ext filepath = askopenfilename(initialdir=initialdir, defaultextension=ext, filetypes=[(self.name, "*" + ext), ('All', '*')], title="Import '%s' from..." % self.name, parent=self) if not filepath: return curr_size = None index = self.attr_index try: undo_node = self.node curr_size = self.parent.get_size(attr_index=index) with get_rawdata_context(writable=False, filepath=filepath) as rawdata: try: self.parent.set_size(len(rawdata), attr_index=index) except Exception: # sometimes rawdata has an explicit size, so an exception # will be raised when trying to change it. just ignore it pass self.parent.parse(rawdata=rawdata, attr_index=index) self.node = self.parent[index] self.set_edited() self.edit_create(undo_node=undo_node, redo_node=self.node) # until i come up with a better method, i'll have to rely on # reloading the root field widget so stuff(sizes) will be updated try: root = self.f_widget_parent while hasattr(root, 'f_widget_parent'): if root.f_widget_parent is None: break root = root.f_widget_parent root.reload() except Exception: print(format_exc()) print("Could not reload after importing '%s' node." % self.name) except Exception: print(format_exc()) print("Could not import '%s' node." % self.name) if curr_size is None: pass elif hasattr(self.node, 'parse'): self.node.set_size(curr_size) else: self.parent.set_size(curr_size, attr_index=index)
def import_node(self): '''Prompts the user for an exported node file. Imports data into the node from the file.''' try: initialdir = self.tag_window.app_root.last_load_dir except AttributeError: initialdir = None ext = self.field_ext filepath = askopenfilename( initialdir=initialdir, defaultextension=ext, filetypes=[(self.name, "*" + ext), ('All', '*')], title="Import sound data from...", parent=self) if not filepath: return filepath = Path(filepath) ext = filepath.suffix.lower() curr_size = None index = self.attr_index try: curr_size = self.parent.get_size(attr_index=index) if ext == '.wav': # if the file is wav, we need to give it a header wav_file = wav_def.build(filepath=filepath) sound_data = self.parent.get_root().data.tagdata channel_count = sound_data.encoding.data + 1 sample_rate = 22050 * (sound_data.sample_rate.data + 1) wav_header = wav_file.data.wav_header wav_format = wav_file.data.wav_format wav_chunks = wav_file.data.wav_chunks typ = wav_format.fmt.enum_name block_align = (2 if typ == "pcm" else 36) * wav_format.channels data_chunk = None for chunk in wav_chunks: if chunk.sig.enum_name == "data": data_chunk = chunk break if wav_header.riff_sig != wav_header.get_desc("DEFAULT", "riff_sig"): raise ValueError( "RIFF signature is invalid. Not a valid wav file.") elif wav_header.wave_sig != wav_header.get_desc("DEFAULT", "wave_sig"): raise ValueError( "WAVE signature is invalid. Not a valid wav file.") elif wav_format.sig != wav_format.get_desc("DEFAULT", "sig"): raise ValueError( "Format signature is invalid. Not a valid wav file.") elif data_chunk is None: raise ValueError( "Data chunk not present. Not a valid wav file.") elif typ not in ('ima_adpcm', 'xbox_adpcm', 'pcm'): raise TypeError( "Wav file audio format must be either IMA ADPCM " + "Xbox ADPCM, or PCM, not %s" % wav_format.fmt.enum_name) elif sound_data.encoding.data + 1 != wav_format.channels: raise TypeError( "Wav file channel count does not match this sound " + "tags channel count. Expected %s, not %s" % (channel_count, wav_format.channels)) elif sample_rate != wav_format.sample_rate: raise TypeError( "Wav file sample rate does not match this sound " + "tags sample rate. Expected %skHz, not %skHz" % (sample_rate, wav_format.sample_rate)) elif block_align != wav_format.block_align: raise TypeError( "Wav file block size does not match this sound " + "tags block size. Expected %sbytes, not %sbytes" % (block_align, wav_format.block_align)) rawdata = data_chunk.data do_pcm_byteswap = (typ == 'pcm') else: rawdata = get_rawdata(filepath=filepath, writable=False) do_pcm_byteswap = False undo_node = self.node self.parent.set_size(len(rawdata), attr_index=index) self.parent.parse(rawdata=rawdata, attr_index=index) if do_pcm_byteswap: byteswap_pcm16_samples(self.parent) self.node = self.parent[index] self.set_edited() self.edit_create(undo_node=undo_node, redo_node=self.node) # reload the parent field widget so sizes will be updated try: self.f_widget_parent.reload() except Exception: print(format_exc()) print("Could not reload after importing sound data.") except Exception: print(format_exc()) print("Could not import sound data.") try: self.parent.set_size(curr_size, attr_index=index) except Exception: pass
def browse_tag(self): '''Opens a filepicker window to aid the user in referencing their wished tag file.''' if self.node is None: return try: try: tags_dir = self.tag_window.tag.tags_dir except AttributeError: return init_dir = tags_dir try: init_dir = Path( tagpath_to_fullpath(tags_dir, self.node.filepath, extension=self.tag_window.tag.ext, force_windows=True)).parent except Exception: # This path is not valid, so use our earlier assignment instead. pass filetypes = [] for ext in sorted(self.node.tag_class.NAME_MAP): if ext == 'NONE': continue filetypes.append((ext, '*.%s' % ext)) # TODO: Create a function that can generate globs # that support all types valid for this field. if len(filetypes) > 1: filetypes = (('All', '*'), ) + tuple(filetypes) else: filetypes.append(('All', '*')) filepath = askopenfilename(initialdir=init_dir, filetypes=filetypes, title="Select a tag", parent=self) if not filepath: # askopenfilename returned nothing. Quit. return # Halo tagpaths require backslashes( \ ) as dividers. # We take the path we got, interpret it as a native Path, then # convert it to a PureWindowsPath to get the backslashes safely. filepath = Path(filepath) try: tag_path = filepath.relative_to(tags_dir) # If the path is not relative just only take the filename. except ValueError: tag_path = Path(filepath.name) # get file extension. ext = tag_path.suffix.lower() # Remove file extension. tag_path = tag_path.with_suffix('') orig_tag_class = copy(self.node.tag_class) # Try to set the tagtype to the type that we selected. try: self.node.tag_class.set_to(ext[1:]) # If we fail, try to set the tagtype to the first one that # has a file that exists, otherwise, set type to NONE. except Exception: self.node.tag_class.set_to('NONE') for filetype in filetypes: ext = filetype[1][1:] if tagpath_to_fullpath(tags_dir, tag_path, extension=ext) is not None: self.node.tag_class.set_to(ext[1:]) break internal_tag_path = str(PureWindowsPath(tag_path)).lower() self.edit_create(attr_index=('tag_class', 'filepath'), redo_node=dict(tag_class=self.node.tag_class, filepath=internal_tag_path), undo_node=dict(tag_class=orig_tag_class, filepath=self.node.filepath)) self.node.filepath = internal_tag_path self.reload() self.set_edited() except Exception: print(format_exc())
def physics_from_jms(app, fp=None): load_dir = app.jms_load_dir tags_dir = app.tags_dir data_dir = app.data_dir if is_path_empty(tags_dir): tags_dir = Path("") if is_path_empty(data_dir): data_dir = Path("") if is_path_empty(load_dir): load_dir = data_dir if is_path_empty(fp): fp = askopenfilename( initialdir=load_dir, parent=app, filetypes=(("JMS model", "*.jms"), ("All", "*")), title="Select jms file to turn into a physics tag") fp = Path(fp) if is_path_empty(fp): return try: app.jms_load_dir = fp.parent with fp.open("r") as f: jms_model = read_jms(f.read(), "regions") except Exception: print(format_exc()) print(" Could not parse jms file") return try: rel_filepath = fp.relative_to(data_dir).parent.parent rel_filepath = rel_filepath.joinpath(rel_filepath.stem + ".physics") except ValueError: rel_filepath = Path("unnamed.physics") tag_path = Path("") if not is_path_empty(rel_filepath): tag_path = tags_dir.joinpath(rel_filepath) # make the tag window window = app.load_tags( filepaths=(tag_path, ) if tag_path.is_file() else "", def_id='phys') if not window: return window = window[0] window.is_new_tag = False window.tag.filepath = tag_path window.tag.rel_filepath = rel_filepath compile_physics(window.tag, jms_model.markers, tag_path.is_file()) # reload the window to display the newly entered info window.reload() app.update_tag_window_title(window) if not tag_path.is_file(): # save the tag if it doesnt already exist app.save_tag()
def strings_from_txt(app, fp=None): load_dir = app.last_data_load_dir tags_dir = app.tags_dir data_dir = app.data_dir if is_path_empty(tags_dir): tags_dir = Path("") if is_path_empty(data_dir): data_dir = Path("") if is_path_empty(load_dir): load_dir = data_dir if is_path_empty(fp): fp = askopenfilename( initialdir=load_dir, parent=app, filetypes=(("strings list", "*.txt"), ("All", "*")), title="Select hmt file to turn into a (unicode_)string_list tag") fp = Path(fp) if is_path_empty(fp): return try: app.last_data_load_dir = fp.parent tag_ext = "unicode_string_list" tag_cls = "ustr" encoding = hacky_detect_encoding(fp) if encoding == "latin-1": tag_ext = "string_list" tag_cls = "str#" print("Creating %s from this txt file:" % tag_ext) print(" %s" % fp) with fp.open("r", encoding=encoding) as f: string_data = f.read() if "utf-16" in encoding: string_data = string_data.lstrip('\ufeff').lstrip('\ufffe') except Exception: print(format_exc()) print(" Could not parse file.") return try: rel_filepath = fp.relative_to(data_dir) except ValueError: rel_filepath = Path("strings") rel_filepath = rel_filepath.with_suffix("." + tag_ext) tag_path = Path("") if not is_path_empty(rel_filepath): tag_path = tags_dir.joinpath(rel_filepath) # make the tag window window = app.load_tags( filepaths=(tag_path, ) if tag_path.is_file() else "", def_id=tag_cls) if not window: return window = window[0] window.is_new_tag = True window.tag.filepath = tag_path window.tag.rel_filepath = rel_filepath if 'utf-16' in encoding: compile_unicode_string_list(window.tag, string_data) else: compile_string_list(window.tag, string_data) # reload the window to display the newly entered info window.reload() app.update_tag_window_title(window) if not tag_path.is_file(): # save the tag if it doesnt already exist app.save_tag()