def add_tag(self, tag, filepath=None): ''' Adds the provided tag to this handlers tag collection. filepath is expected to be a relative filepath if self.tagsdir_relative == True If it isnt provided, then tag.filepath is expected to be an absolute filepath. If self.tagsdir_relative = True, tag.filepath is relative expected to be relative to self.tagsdir, where is_in_dir(tag.filepath, self.tagsdir) == True ''' def_id = tag.def_id tag_coll = self.tags.get(def_id, {}) abs_filepath = tag.filepath filepath = Path(filepath) if not is_path_empty(abs_filepath): if is_path_empty(filepath) and self.tagsdir_relative: filepath = Path(relpath(str(abs_filepath), str(self.tagsdir))) elif not is_path_empty(filepath): abs_filepath = self.tagsdir.joinpath(filepath) else: raise ValueError("No filepath provided to index tag under") tag.filepath = abs_filepath tag_coll[filepath] = tag self.tags[def_id] = tag_coll
def get_resource_map_paths(self, maps_dir=""): map_paths = {name: None for name in HALO2_MAP_TYPES[1:]} if self.engine == "halo2alpha": map_paths.pop("single_player_shared", None) if not is_path_empty(maps_dir): maps_dir = Path(maps_dir) else: maps_dir = self.filepath.parent # detect the map paths for the resource maps for map_name in sorted(map_paths): map_path = str(maps_dir.joinpath(map_name)) if self.maps.get(map_name) is not None: map_path = self.maps[map_name].filepath elif os.path.exists(map_path + ".map"): map_path = Path(map_path + ".map") elif os.path.exists(map_path + "_DECOMP.map"): map_path = Path(map_path + "_DECOMP.map") elif os.path.exists(map_path + ".map.dtz"): map_path = Path(map_path + ".map.dtz") else: map_path = None map_paths[map_name] = map_path return map_paths
def make_log_file(self, logstr, logpath=None): ''' Writes the supplied string to a log file. Required arguments: logstr(str) If self.log_filename is a non-blank string it will be used as the log filename. Otherwise the current timestamp will be used as the filename in the format "YY-MM-DD HH:MM SS". If the file already exists it will be appended to with the current timestamp separating each write. Otherwise the file will be created. ''' # get the timestamp for the debug log's name timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") if not is_path_empty(logpath): pass elif isinstance(self.log_filename, str) and self.log_filename: logpath = self.tagsdir.joinpath(self.log_filename) logstr = '\n' + '-'*80 + '\n' + timestamp + '\n' + logstr else: logpath = self.tagsdir.joinpath(timestamp.replace(':', '.') + ".log") logpath = Path(logpath) mode = 'w' if logpath.is_file(): mode = 'a' # open a debug file and write the debug string to it with logpath.open(mode) as logfile: logfile.write(logstr)
def bitmap_from_multiple_dds(app, fps=()): load_dir = app.bitmap_load_dir data_dir = app.data_dir if is_path_empty(data_dir): data_dir = Path("") if is_path_empty(load_dir): load_dir = data_dir if not fps: fps = askopenfilenames( initialdir=load_dir, parent=app, filetypes=(("DDS image", "*.dds"), ("All", "*")), title="Select dds files to turn into a single bitmap tag") fps = [fp for fp in fps if fp.lower().endswith(".dds")] if not fps: return # make the tag window window = app.load_tags(filepaths='', def_id='bitm') if not window: return print("Creating bitmap from dds files") window = window[0] window.is_new_tag = True fps = sorted(fps) for fp in fps: pure_path = Path(fp) window.update_title(list(pure_path.parts)[-1]) app.bitmap_load_dir = pure_path.parent break compile_bitmap_from_dds_files(window.tag, fps) # reload the window to display the newly entered info window.reload() # prompt the user to save the tag somewhere app.save_tag_as()
def parse(self, **kwargs): ''' Optional keywords arguments: # bool: init_attrs ----- allow_corrupt -- # buffer: rawdata -------- # int: root_offset ---- offset --------- # iterable: initdata ------- #str: filepath ------- ''' if not kwargs.get('rawdata'): kwargs.setdefault('filepath', self.filepath) kwargs.setdefault('root_offset', self.root_offset) filepath = kwargs.get('filepath') desc = self.definition.descriptor block_type = desc.get(NODE_CLS, desc[TYPE].node_cls) # Create the root node and set self.data to it before parsing. new_tag_data = self.data = block_type(desc, parent=self) if not is_path_empty(filepath): self.filepath = filepath # If this is an incomplete object then we # need to keep a path to the source file if self.definition.incomplete: self.sourcepath = filepath elif 'rawdata' not in kwargs: kwargs['init_attrs'] = True # whether or not to allow corrupt tags to be built. # this is a debugging tool. if kwargs.pop('allow_corrupt', False): try: new_tag_data.parse(**kwargs) except OSError: # file was likely not found, or something similar raise except Exception: print(format_exc()) else: new_tag_data.parse(**kwargs)
def bitmap_from_bitmap_source(app, e=None): load_dir = app.bitmap_load_dir if is_path_empty(load_dir): load_dir = app.last_data_load_dir fps = askopenfilenames(initialdir=load_dir, parent=app, filetypes=(("bitmap", "*.bitmap"), ("All", "*")), title="Select a bitmap tag to get the source tiff") if not fps: return app.bitmap_load_dir = os.path.dirname(fps[0]) print('Creating bitmap from uncompressed source image of these bitmaps:') for fp in fps: print(" %s" % fp) width, height, pixels = extract_bitmap_tiff_data(fp) if not pixels: continue # make the tag window try: window = app.load_tags(filepaths='', def_id='bitm') except LookupError: print(' Could not make a new bitmap. Change the tag set.') if not window: continue window = window[0] window.is_new_tag = True add_bitmap_to_bitmap_tag(window.tag, width, height, 1, "texture_2d", "a8r8g8b8", 0, pixels) window.tag.rel_filepath = "untitled%s.bitmap" % app.untitled_num window.tag.filepath = app.tags_dir.joinpath(window.tag.rel_filepath) app.update_tag_window_title(window) # reload the window to display the newly entered info window.reload() # prompt the user to save the tag somewhere app.save_tag_as()
def delete_tag(self, *, tag=None, def_id=None, filepath=''): filepath = Path(filepath) if tag is not None: def_id = tag.def_id if not is_path_empty(filepath): pass elif self.tagsdir_relative: filepath = Path(self.tagsdir, tag.filepath) else: filepath = tag.filepath elif def_id is None: def_id = self.get_def_id(filepath) if filepath in self.tags.get(def_id, {}): del self.tags[def_id][filepath] elif Path(self.tagsdir, filepath) in self.tags.get(def_id, {}): del self.tags[def_id][Path(self.tagsdir, filepath)] else: print("Warning: Tried to delete tag %s [%s] from handler, " "but tag couldn't be found." % (filepath, def_id))
def get_resource_map_paths(self, maps_dir=""): play_meta = self.root_tags.get("cache_file_resource_layout_table") if not play_meta: return {} map_paths = { name.split(".")[0]: None for name in self.shared_map_names } if not is_path_empty(maps_dir): maps_dir = Path(maps_dir) else: maps_dir = self.filepath.parent # detect/ask for the map paths for the resource maps for map_name in sorted(map_paths): map_path = str(maps_dir.joinpath("%s.map" % map_name)) if self.maps.get(map_name) is not None: map_paths[map_name] = self.maps[map_name].filepath elif os.path.exists(map_path): map_paths[map_name] = map_path return map_paths
def post_toplevel_init(self): if not is_path_empty(e_c.MOZZ_ICON_PATH): self.iconbitmap_filepath = e_c.MOZZ_ICON_PATH ConfigWindow.post_toplevel_init(self)
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 _do_compression(self, compress, antr_path=None): state = "compress" if compress else "decompress" if not antr_path: antr_path = self.model_animations_path.get() antr_path = Path(antr_path) while is_path_empty(antr_path): self.model_animations_path_browse(True) antr_path = Path(self.model_animations_path.get()) if is_path_empty(antr_path) and self.warn_cancel(): return print("%sing %s." % (state.capitalize(), antr_path)) self.app_root.update() antr_def = None try: with antr_path.open('rb') as f: f.seek(36) tag_type = f.read(4) if tag_type == b'antr': f.seek(56) antr_ver = f.read(2) if antr_ver == b'\x00\x05': antr_def = stubbs_antr_def elif antr_ver == b'\x00\x04': antr_def = halo_antr_def except Exception: pass if antr_def is None: print("Could not determine model_animation tag version.") return antr_tag = antr_def.build(filepath=antr_path) anims = antr_tag.data.tagdata.animations.STEPTREE errors = False edited = False for anim in anims: try: if not anim.flags.compressed_data: continue if compress: edited |= compress_animation(anim) else: edited |= decompress_animation( anim, self.preserve_compressed.get()) except Exception: print(format_exc()) self.update() errors = True if not edited: print(" No changes made. Not saving.") return if errors: self.update() if not messagebox.askyesno( "Model_animations %sing failed" % state, ("Errors occurred while %sing(check console). " % state) + "Do you want to save the model_animations tag anyway?", icon='warning', parent=self): print(" Model_animations compilation failed.") return try: if not self.overwrite.get(): fp = Path(antr_tag.filepath) antr_tag.filepath = Path(fp.parent, fp.stem + "_DECOMP" + fp.suffix) antr_tag.calc_internal_data() antr_tag.serialize(temp=False, backup=False, calc_pointers=False, int_test=False) print(" Finished") except Exception: print(format_exc()) print(" Could not save %sed model_animations." % state)
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()
def get_rawdata(**kwargs): ''' This function serves as a macro for returning a Buffer object. 'filepath' and 'rawdata' may be given as keyword arguments. Accepts any number of keyword arguments and ignores invalid ones. If filepath is given, this function will open the file as a PeekableMmap. If rawdata is a bytes object, it will be converted into a BytesBuffer. If rawdata is a bytearray, it will be converted into a BytearrayBuffer. If rawdata is not a bytearray or bytes and is not None, it will be checked to make sure it has read, seek, and peek methods. Returns the rawdata, or None if rawdata and filepath were unsupplied. Raises TypeError if rawdata doesnt have read, seek, or peek methods. Raises TypeError if rawdata and filepath are both provided. ''' filepath = kwargs.get('filepath') if filepath is not None: filepath = Path(filepath) rawdata = kwargs.get('rawdata') writable = kwargs.get('writable', True) if not is_path_empty(filepath): if rawdata: raise TypeError("Provide either rawdata or filepath, not both.") access = ACCESS_WRITE # to avoid 'open' failing if windows files are hidden, # we open in 'r+b' mode if the file exists. if not writable: open_mode = 'rb' access = ACCESS_READ elif filepath.is_file(): open_mode = 'r+b' else: open_mode = 'w+b' # try to open the file as the rawdata rawdata_file = filepath.open(open_mode) try: rawdata = PeekableMmap(rawdata_file.fileno(), 0, access=access) rawdata_file.close() except ValueError: # can't mmap an empty file rawdata = rawdata_file elif not rawdata: rawdata = None elif isinstance(rawdata, bytes): rawdata = BytesBuffer(rawdata) elif isinstance(rawdata, bytearray): rawdata = BytearrayBuffer(rawdata) elif not (hasattr(rawdata, 'read') and hasattr(rawdata, 'seek')): raise TypeError( ("If rawdata is provided it must either be one of " + "the following:\n %s, %s, %s, %s\nor it must have " + "'read' and 'seek' attributes.\nGot %s instead.") % (BytesBuffer, BytearrayBuffer, mmap, PeekableMmap, type(rawdata))) return rawdata