def _check_close_world(self) -> bool: """ Check if it is safe to close the world and prompt the user if it is not. :return: True if the world can be closed, False otherwise """ unsaved_changes = self._world.chunk_history_manager.unsaved_changes if unsaved_changes: msg = wx.MessageDialog( self, f"""There { 'is' if unsaved_changes == 1 else 'are' } {unsaved_changes} unsaved change{ 's' if unsaved_changes >= 2 else '' } in { self._world.world_wrapper.world_name }. Would you like to save?""", style=wx.YES_NO | wx.CANCEL | wx.CANCEL_DEFAULT, ) response = msg.ShowModal() if response == wx.ID_YES: self._canvas.save() return True elif response == wx.ID_NO: return True elif response == wx.ID_CANCEL: log.info(f"""Aborting closing world { self._world.world_wrapper.world_name } because the user pressed cancel.""") return False return True
def __init__(self, parent, world_dirs, open_world_callback, sort=True): super(WorldList, self).__init__(parent) self.worlds = [] world_formats = [] for world_path in world_dirs: if os.path.isdir(world_path): try: world_formats.append( world_interface.load_format(world_path)) except Exception as e: log.info(f"Could not find loader for {world_path} {e}") if sort: world_formats = reversed( sorted(world_formats, key=lambda f: f.last_played)) for world_format in world_formats: try: world_button = WorldUIButton(self, world_format, open_world_callback) self.add_object(world_button, 0, wx.ALL | wx.EXPAND) self.worlds.append(world_button) except Exception as e: log.info( f"Failed to display world button for {world_format.world_path} {e}" ) self.Layout()
def run_operation( self, operation: Callable[[], OperationReturnType], title="Amulet", msg="Running Operation", throw_exceptions=False, ) -> Any: def operation_wrapper(): yield 0, "Disabling Threads" self._disable_threads() yield 0, msg op = operation() if isinstance(op, GeneratorType): yield from op return op err = None out = None try: out = show_loading_dialog( operation_wrapper, title, msg, self, ) self.world.create_undo_point() wx.PostEvent(self, CreateUndoEvent()) except OperationError as e: msg = f"Error running operation: {e}" log.info(msg) self.world.restore_last_undo_point() wx.MessageDialog(self, msg, style=wx.OK).ShowModal() err = e except OperationSuccessful as e: msg = str(e) log.info(msg) self.world.restore_last_undo_point() wx.MessageDialog(self, msg, style=wx.OK).ShowModal() err = e except OperationSilentAbort as e: self.world.restore_last_undo_point() err = e except Exception as e: self.world.restore_last_undo_point() log.error(traceback.format_exc()) wx.MessageDialog( self, f"Exception running operation: {e}\nSee the console for more details", style=wx.OK, ).ShowModal() err = e self._enable_threads() if err is not None and throw_exceptions: raise err return out
def is_closeable(self) -> bool: """ Check if it is safe to close the UI. :return: True if the program can be closed, False otherwise """ if self._canvas is not None: if self._canvas.is_closeable(): return self._check_close_world() log.info( f"The canvas in edit for world {self._world.world_wrapper.world_name} was not closeable for some reason." ) return False return not bool(self._world.chunk_history_manager.unsaved_changes)
def _convert_method(self): global work_count try: out_world = world_interface.load_format(self.out_world_path) log.info( f"Converting world {self.world.world_path} to {out_world.world_path}" ) out_world: WorldFormatWrapper out_world.open() self.world.save(out_world, self._update_loading_bar) out_world.close() message = "World conversion completed" log.info( f"Finished converting world {self.world.world_path} to {out_world.world_path}" ) except Exception as e: message = f"Error during conversion\n{e}" log.error(message, exc_info=True) self._update_loading_bar(0, 100) self.convert_button.Enable() wx.MessageBox(message) work_count -= 1
def _create_atlas(self) -> Generator[float, None, None]: """Create and bind the atlas texture.""" atlas_iter = textureatlas.create_atlas(self._resource_pack.textures) try: while True: yield next(atlas_iter) except StopIteration as e: texture_atlas, self._texture_bounds, width, height = e.value glBindTexture(GL_TEXTURE_2D, self._gl_texture_atlas) glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_atlas, ) glBindTexture(GL_TEXTURE_2D, 0) log.info("Finished setting up texture atlas in OpenGL")
def _setup_texture(self, context_id: str): """Set up the texture for a given context""" gl_texture = self._gl_textures[context_id] = glGenTextures( 1) # Create the texture location glBindTexture(GL_TEXTURE_2D, gl_texture) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) glBindTexture(GL_TEXTURE_2D, gl_texture) glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, self._image_width, self._image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, self._image, ) glBindTexture(GL_TEXTURE_2D, 0) log.info("Finished setting up texture atlas in OpenGL")
def is_closeable(self): if work_count: log.info( f"World {self.world.world_path} is still being converted. Please let it finish before closing" ) return work_count == 0
def create_atlas_iter( texture_tuple: Tuple[str, ...] ) -> Generator[ float, None, Tuple[numpy.ndarray, Dict[Any, Tuple[float, float, float, float]], int, int], ]: log.info("Creating texture atlas") # Parse texture names textures = [] for texture_index, texture in enumerate(texture_tuple): if not texture_index % 100: yield texture_index / (len(texture_tuple) * 2) # Look for a texture name name, frames = texture, [texture] # Build frame objects frames = [Frame(f) for f in frames] # Add frames to texture object list textures.append(Texture(name, frames)) # Sort textures by perimeter size in non-increasing order textures = sorted(textures, key=lambda i: i.frames[0].perimeter, reverse=True) height = 0 width = 0 pixels = 0 for t in textures: for f in t.frames: height = max(f.height, height) width = max(f.width, width) pixels += f.height * f.width size = max(height, width, 1 << (math.ceil(pixels ** 0.5) - 1).bit_length()) atlas_created = False atlas = None while not atlas_created: try: # Create the atlas and pack textures in log.info(f"Trying to pack textures into image of size {size}x{size}") atlas = TextureAtlas(size, size) for texture_index, texture in enumerate(textures): if not texture_index % 30: yield 0.5 + texture_index / (len(textures) / 2) atlas.pack(texture) atlas_created = True except AtlasTooSmall: log.info(f"Image was too small. Trying with a larger area") size *= 2 log.info(f"Successfully packed textures into an image of size {size}x{size}") texture_atlas = numpy.array(atlas.generate("RGBA"), numpy.uint8).ravel() texture_bounds = atlas.to_dict() texture_bounds = { texture_path: texture_bounds[texture_path] for texture_path in texture_tuple } log.info("Finished creating texture atlas") return texture_atlas, texture_bounds, atlas.width, atlas.height