def run_operation( self, operation: Callable[[], OperationReturnType], title="Amulet", msg="Running Operation", throw_exceptions=False, ) -> Any: def operation_wrapper(): yield 0, "Disabling Threads" self.renderer.disable_threads() yield 0, msg op = operation() if isinstance(op, GeneratorType): yield from op yield 0, "Creating Undo Point" yield from self.create_undo_point_iter() return op err = None out = None try: out = show_loading_dialog( operation_wrapper, title, msg, self, ) 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: log.error(traceback.format_exc()) dialog = TracebackDialog( self, "Exception while running operation", str(e), traceback.format_exc(), ) dialog.ShowModal() dialog.Destroy() err = e self.world.restore_last_undo_point() self.renderer.enable_threads() self.renderer.render_world.rebuild_changed() if err is not None and throw_exceptions: raise err return out
def set_selection_corners( self, selection_corners: Tuple[Tuple[Tuple[int, int, int], Tuple[int, int, int]], ...], ): """Set the minimum and maximum points of each selection Note this method will not trigger the history logic. You may instead want the selection_corners setter method. :param selection_corners: The minimum and maximum points of each selection :return: """ selections = [] for points in selection_corners: if len(points) == 2 and all(len(point) == 3 for point in points): selections.append( tuple(tuple(int(p) for p in point) for point in points)) else: log.error( f"selection_corners must be of the format Tuple[Tuple[Tuple[int, int, int], Tuple[int, int, int]], ...]" ) self.changed = True self._selection_corners = tuple(selections) self._selection_group = SelectionGroup( [SelectionBox(*box) for box in self._selection_corners]) wx.PostEvent(self._canvas(), SelectionChangeEvent())
def _open_world(self, path: str): """Open a world panel add add it to the notebook""" if path in self._open_worlds: self.world_tab_holder.SetSelection( self.world_tab_holder.GetPageIndex(self._open_worlds[path])) self._disable_enable() else: try: world = WorldPageUI(self.world_tab_holder, path, lambda: self.close_world(path)) except LoaderNoneMatched as e: log.error(f"Could not find a loader for this world.\n{e}") wx.MessageBox( f"{lang.get('select_world.no_loader_found')}\n{e}") except Exception as e: log.error(lang.get("select_world.loading_world_failed"), exc_info=True) dialog = TracebackDialog( self, lang.get("select_world.loading_world_failed"), str(e), traceback.format_exc(), ) dialog.ShowModal() dialog.Destroy() else: self._open_worlds[path] = world self._add_world_tab(world, world.world_name)
def thread_action(self): # first check if there is a chunk that exists and needs rebuilding camera = numpy.asarray(self.camera_location)[[0, 2]] if self._last_rebuild_camera_location is None or numpy.sum( (self._last_rebuild_camera_location - camera)**2) > min( 2048, self.render_distance * 16 - 8): # if the camera has moved more than 32 blocks set the rebuild flag self._rebuild = True self._last_rebuild_camera_location = camera chunk_coords = next(self._chunk_rebuilds) if chunk_coords is not None: # generate the chunk chunk = RenderChunk( self.context_identifier, self.resource_pack, self.level, self.chunk_manager.region_size, chunk_coords, self.dimension, self.draw_floor, ) try: chunk.create_geometry() except: log.error( f"Failed generating chunk geometry for chunk {chunk_coords}", exc_info=True, ) self.chunk_manager.add_render_chunk(chunk)
def __init__(self, parent: wx.Window, world_dirs, open_world_callback, sort=True): super().__init__(parent) sizer = wx.BoxSizer(wx.VERTICAL) self.SetSizer(sizer) self.worlds = [] world_formats = [] for world_path in world_dirs: if os.path.isdir(world_path): try: world_formats.append(load_format(world_path)) except FormatError as e: log.info(f"Could not find loader for {world_path} {e}") except Exception: log.error( f"Error loading format wrapper for {world_path} {traceback.format_exc()}" ) 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) sizer.Add( world_button, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, 5 ) self.worlds.append(world_button) except Exception as e: log.info(f"Failed to display world button for {world_format.path} {e}") self.Layout()
def _on_open_file(self, evt): with wx.FileDialog( self.canvas, "Open a Minecraft data file", wildcard="|". join([ # TODO: Automatically load these from the FormatWrapper classes. "All files (*.construction;*.mcstructure;*.schematic)|*.construction;*.mcstructure;*.schematic", "Construction file (*.construction)|*.construction", "Bedrock mcstructure file (*.mcstructure)|*.mcstructure", "Legacy Schematic file (*.schematic)|*.schematic", "Sponge Schematic file (*.schem)|*.schem", ]), style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST, ) as fileDialog: if fileDialog.ShowModal() == wx.ID_CANCEL: return else: pathname = fileDialog.GetPath() try: level = amulet.load_level(pathname) except LoaderNoneMatched: wx.MessageBox(f"Could not find a matching loader for {pathname}.") log.error(f"Could not find a matching loader for {pathname}.") except Exception as e: log.error( f"Could not open {pathname}. Check the console for more details.\n{traceback.format_exc()}" ) wx.MessageBox( f"Could not open {pathname}. Check the console for more details.\n{e}" ) else: self.canvas.paste(level, level.dimensions[0])
def reload_operations(self): """Reload all operations and repopulate the UI.""" # store the id of the old operation operation_id = self.active_operation_id # reload the operations self._operations.reload() # repopulate the selection self._operation_choice.SetItems( {op.identifier: op.name for op in self._operations.operations} ) if operation_id: identifiers = self._operation_choice.values if identifiers: if operation_id in identifiers: self._operation_choice.SetSelection(identifiers.index(operation_id)) else: log.info(f"Operation {operation_id} was not found.") self._operation_choice.SetSelection(0) else: log.error("No operations found. Something has gone wrong.") self._setup_operation() self.canvas.reset_bound_events()
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(load_format(world_path)) except FormatError as e: log.info(f"Could not find loader for {world_path} {e}") except Exception: log.error( f"Error loading format wrapper for {world_path} {traceback.format_exc()}" ) 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.path} {e}") self.Layout()
def _load_dir(self, path: str): """Load all operations in a set directory.""" os.makedirs(path, exist_ok=True) for obj_name in os.listdir(path): if obj_name in {"__init__.py", "__pycache__"}: continue obj_path = os.path.join(path, obj_name) if os.path.isfile(obj_path) and not obj_path.endswith(".py"): continue try: mod = load_module(obj_path) except ImportError: log.warning(f"Failed to import {obj_path}.\n{traceback.format_exc()}") else: if hasattr(mod, "export"): export = mod.export if isinstance(export, dict): self._load_operation(obj_path, export) elif isinstance(export, (list, tuple)): for i, export_dict in export: self._load_operation(f"{obj_path}[{i}]", export_dict) else: log.error(f"The format of export in {obj_path} is invalid.") else: log.error(f"export is not present in {obj_path}")
def _on_drop_files(self, evt: wx.DropFilesEvent): """Logic to run when a file is dropped into the canvas.""" paths = evt.GetFiles() if paths: pathname = paths[0] if os.path.isfile(pathname): # TODO: if importing worlds get supported fix this try: level = amulet.load_level(pathname) except LoaderNoneMatched: msg = f"Could not find a matching loader for {pathname}." wx.MessageBox(msg) log.error(msg) except Exception as e: log.error(f"Could not open {pathname}.", exc_info=True) dialog = TracebackDialog( self.canvas, f"Could not open {pathname}.", str(e), traceback.format_exc(), ) dialog.ShowModal() dialog.Destroy() else: self.canvas.paste(level, level.dimensions[0]) evt.Skip()
def _generate_chunks(self): while self._enabled: start_time = time.time() # first check if there is a chunk that exists and needs rebuilding chunk_coords = next( ( c for c in self.render_world.chunk_coords() if self.render_world.chunk_manager.render_chunk_needs_rebuild(c) ), None ) if chunk_coords is not None: # if there was a chunk found that needs rebuilding then add the surrounding chunks for rebuilding # (this deals with if the chunk was deleted or the blocks up to the chunk boundary were deleted) for offset in [(-1, 0), (1, 0), (0, -1), (0, 1)]: chunk_coords_ = (chunk_coords[0] + offset[0], chunk_coords[1] + offset[1]) if chunk_coords_ in self.render_world.chunk_manager: self._chunk_rebuilds.add(chunk_coords_) elif self._chunk_rebuilds: # if a chunk was not found that needs rebuilding due to it changing but a previously # identified neighbour chunk needs rebuilding do that. chunk_coords = self._chunk_rebuilds.pop() else: # if no chunks need rebuilding then find a new chunk to load. chunk_coords = next( ( c for c in self.render_world.chunk_coords() if c not in self.render_world.chunk_manager ), None ) if chunk_coords is not None: # if chunk coords is in here then remove it so it doesn't get generated twice. if chunk_coords in self._chunk_rebuilds: self._chunk_rebuilds.remove(chunk_coords) # generate the chunk chunk = RenderChunk( self.render_world, self._region_size, chunk_coords, self.render_world.dimension, self.render_world.texture ) try: chunk.create_geometry() except: log.error(f'Failed generating chunk geometry for chunk {chunk_coords}', exc_info=True) self.render_world.chunk_manager.add_render_chunk( chunk ) delta_time = time.time() - start_time if delta_time < 1/60: # go to sleep so this thread doesn't lock up the main thread. time.sleep(1/60-delta_time)
def _load(self, export_dict: dict): """load the operation.""" if not isinstance(export_dict, dict): log.error(f"The export for {self.identifier} is not a dictionary.") return if "name" in export_dict and isinstance(export_dict["name"], str): self._name = export_dict["name"] self._setup(export_dict) else: log.error(f"Missing or invalid name in {self.identifier}")
def tear_down_events(self): """Unbind all events. We are allowing users to bind custom events so we should have a way to reset what is bound.""" for event, handler, source in self._bound_events: if source is None: while super().Unbind(event): pass else: if not self.Unbind(event, source, handler=handler): log.error(f"Failed to unbind {event}, {handler}, {source}") self._bound_events.clear()
def _setup(self, export_dict: dict): """Parse the export dictionary and setup as required.""" options_path = os.path.abspath( os.path.join( "config", "edit_plugins", f"""{''.join(c for c in self._name if c in ValidChrs)}_{ struct.unpack( "H", hashlib.sha1( self.identifier.encode('utf-8') ).digest()[:2] )[0] }.config""", # generate a file name that identifiable to the operation but "unique" to the path )) if "operation" in export_dict: if inspect.isclass(export_dict["operation"]) and issubclass( export_dict["operation"], (wx.Window, wx.Sizer)): operation_ui: Type[OperationUI] = export_dict.get( "operation", None) if issubclass(operation_ui, OperationUI): self._ui = lambda parent, canvas, world: operation_ui( parent, canvas, world, options_path) self._is_valid = True else: log.error( f'"operation" must be a subclass of edit.plugins.OperationUI. {self.identifier}' ) elif callable(export_dict["operation"]): operation = export_dict["operation"] if operation.__code__.co_argcount == 4: options = export_dict.get("options", {}) if isinstance(options, dict): self._ui = lambda parent, canvas, world: FixedFunctionUI( parent, canvas, world, options_path, operation, options) self._is_valid = True else: log.error( f'"operation" in export must be a dictionary if defined. {self.identifier}' ) else: log.error( f'"operation" function in export must have 4 inputs. {self.identifier}' ) else: log.error( f'"operation" in export must be a callable, or a subclass of wx.Window or wx.Sizer. {self.identifier}' ) else: log.error( f'"operation" is not present in export. {self.identifier}')
def _load_module(self, obj_path: str, mod: ModuleType): if hasattr(mod, "export"): export = mod.export if isinstance(export, dict): self._load_operation(obj_path, export) elif isinstance(export, (list, tuple)): for i, export_dict in export: self._load_operation(f"{obj_path}[{i}]", export_dict) else: log.error(f"The format of export in {obj_path} is invalid.") else: log.error(f"export is not present in {obj_path}")
def _open_world(self, path: str): """Open a world panel add add it to the notebook""" if path in self._open_worlds: self.world_tab_holder.SetSelection( self.world_tab_holder.FindPage(self._open_worlds[path])) self._disable_enable() else: try: world = WorldManagerUI(self.world_tab_holder, path) except LoaderNoneMatched as e: log.error(e) wx.MessageBox(str(e)) else: self._open_worlds[path] = world self._add_world_tab(world, world.world_name)
def _change_options(self, evt): operation_path = self._operation_choice.GetAny() operation = operations.operations[operation_path] if "options" in operation.get("features", []): pass # TODO: implement this elif "wxoptions" in operation.get("features", []): options = operation["wxoptions"](self, self._world(), operations.options.get( operation_path, {})) if isinstance(options, dict): operations.options[operation_path] = options else: log.error( f"Plugin {operation['name']} at {operation_path} did not return options in a valid format" ) evt.Skip()
def _run_main_operation( self, operation_path: str, operation: OperationType, operation_input_definitions: List[str], options=None, structure=None, ) -> Any: operation_inputs = [] for inp in operation_input_definitions: if inp == "src_selection": selection = self._get_box() if selection is None: return operation_inputs.append(selection) elif inp == "structure": operation_inputs.append(structure) elif inp == "options": if options: plugins.options[operation_path] = options operation_inputs.append(options) else: operation_inputs.append( plugins.options.get(operation_path, {})) self._canvas.disable_threads() try: out = show_loading_dialog( lambda: operation(self._world, self._canvas.dimension, * operation_inputs), f"Running Operation ?.", "Please wait for the operation to finish.", self, ) self._world.create_undo_point() self._file_panel.update_buttons() except Exception as e: operation_info = plugins.all_operations[operation_path] log.error( f'Error occurred while running operation: {operation_info["name"]} v{operation_info["v"]}' ) log.error(f"{e}\n{traceback.format_exc()}") wx.MessageBox(f"Error running operation: {e}") self._world.restore_last_undo_point() out = None self._canvas.enable_threads() return out
def run_operation(self, operation: Callable[[], OperationReturnType], title="", msg="", throw_exceptions=False) -> Any: self._disable_threads() err = None out = None try: out = show_loading_dialog( operation, 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 _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 _on_drop_files(self, evt: wx.DropFilesEvent): paths = evt.GetFiles() if paths: pathname = paths[0] if os.path.isfile(pathname): # TODO: if importing worlds get supported fix this try: level = amulet.load_level(pathname) except LoaderNoneMatched: wx.MessageBox(f"Could not find a matching loader for {pathname}.") log.error(f"Could not find a matching loader for {pathname}.") except Exception as e: wx.MessageBox( f"Could not open {pathname}. Check the console for more details.\n{e}" ) log.error( f"Could not open {pathname}. Check the console for more details.\n{traceback.format_exc()}" ) else: self.canvas.paste(level, level.dimensions[0]) evt.Skip()
def _setup_operation(self): """Remove the old operation and create the UI for the new operation.""" operation_path = self.active_operation_id if operation_path: # only reload the operation if the operation = self._operations[operation_path] if self._active_operation is not None: self._active_operation.disable() self._operation_sizer.Clear(delete_windows=True) try: self._active_operation = operation( self.canvas, self.canvas, self.canvas.world ) self._operation_sizer.Add( self._active_operation, *self._active_operation.wx_add_options ) self._active_operation.enable() except Exception as e: # If something went wrong clear the created UI self._active_operation = None self._operation_sizer.Clear(delete_windows=True) for window in self.canvas.GetChildren(): window: wx.Window # remove orphaned windows. # If the Sizer.Add method was not run it will not be in self._operation_sizer if window.GetContainingSizer() is None: window.Destroy() log.error("Error loading Operation UI.", exc_info=True) dialog = TracebackDialog( self.canvas, "Error loading Operation UI.", str(e), traceback.format_exc(), ) dialog.ShowModal() dialog.Destroy() finally: self._last_active_operation_id = operation.identifier self.Layout()
def _convert_method(self): global work_count try: out_world = load_format(self.out_world_path) log.info( f"Converting world {self.world.level_path} to {out_world.path}" ) out_world: WorldFormatWrapper out_world.open() self.world.save(out_world, self._update_loading_bar) out_world.close() message = lang.get("program_convert.conversion_completed") log.info( f"Finished converting world {self.world.level_path} to {out_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 _open_world(self, path: str): """Open a world panel add add it to the notebook""" if path in self._open_worlds: self.world_tab_holder.SetSelection( self.world_tab_holder.GetPageIndex(self._open_worlds[path])) self._disable_enable() else: try: world = WorldPageUI(self.world_tab_holder, path, lambda: self.close_world(path)) except LoaderNoneMatched as e: log.error(f"Could not find a loader for this world.\n{e}") wx.MessageBox(f"Could not find a loader for this world.\n{e}") except Exception as e: log.error( f"Error loading world.\n{e}\n{traceback.format_exc()}") wx.MessageBox( f"Error loading world. Check the console for more details.\n{e}" ) else: self._open_worlds[path] = world self._add_world_tab(world, world.world_name)
def _get_block_info_message(self) -> str: x, y, z = self.cursor_location try: block = self.world.get_block(x, y, z, self.dimension) chunk = self.world.get_chunk(x >> 4, z >> 4, self.dimension) block_entity = chunk.block_entities.get((x, y, z), None) platform = self.world.world_wrapper.platform version = self.world.world_wrapper.version translator = self.world.translation_manager.get_version( platform, version, ) ( version_block, version_block_entity, _, ) = translator.block.from_universal(block, block_entity, block_location=(x, y, z)) if isinstance(version, tuple): version_str = ".".join(str(v) for v in version[:4]) else: version_str = str(version) block_data_text = f"x: {x}, y: {y}, z: {z}\n\n{platform.capitalize()} {version_str}\n{version_block}" if version_block_entity: version_block_entity_str = str(version_block_entity) block_data_text = f"{block_data_text}\n{version_block_entity_str}" block_data_text = f"{block_data_text}\n\nUniversal\n{block}" if block_entity: block_entity_str = str(block_entity) block_data_text = f"{block_data_text}\n{block_entity_str}" if chunk.biomes.dimension == 2: biome = chunk.biomes[x % 16, z % 16] try: block_data_text = ( f"{block_data_text}\n\nBiome: {self.world.biome_palette[biome]}" ) except Exception as e: log.error(e) elif chunk.biomes.dimension == 3: biome = chunk.biomes[(x % 16) // 4, y // 4, (z % 16) // 4] try: block_data_text = ( f"{block_data_text}\n\nBiome: {self.world.biome_palette[biome]}" ) except Exception as e: log.error(e) except Exception as e: log.error(e) return str(e) else: return block_data_text
def _setup(self, export_dict: dict): """Parse the export dictionary and setup as required.""" if "operation" in export_dict: if callable(export_dict["operation"]): operation = export_dict["operation"] if operation.__code__.co_argcount == 3: self._operation = operation self._is_valid = True else: log.error( f'"operation" function in export must have 3 inputs. {self.identifier}' ) else: log.error( f'"operation" in export must be a callable. {self.identifier}' ) else: log.error( f'"operation" is not present in export. {self.identifier}')
def _setup(self) -> Generator[OperationYieldType, None, None]: """Set up objects that take a while to set up.""" packs = [] user_packs = [ load_resource_pack(os.path.join("resource_packs", rp)) for rp in os.listdir("resource_packs") if os.path.isdir(os.path.join("resource_packs", rp)) ] if ( self.world.level_wrapper.platform == "bedrock" and experimental_bedrock_resources ): packs.append( load_resource_pack( os.path.join( os.path.dirname(amulet_edit.__file__), "amulet_resource_pack", "bedrock", ) ) ) yield 0.1, lang.get( "program_3d_edit.canvas.downloading_bedrock_vanilla_resource_pack" ) gen = get_bedrock_vanilla_latest_iter() try: while True: yield next(gen) * 0.4 + 0.1 except StopIteration as e: packs.append(e.value) yield 0.5, lang.get("program_3d_edit.canvas.loading_resource_packs") packs += [ pack for pack in user_packs if isinstance(pack, BedrockResourcePack) ] packs.append(get_bedrock_vanilla_fix()) translator = self.world.translation_manager.get_version( "bedrock", (999, 0, 0) ) else: packs.append( load_resource_pack( os.path.join( os.path.dirname(amulet_edit.__file__), "amulet_resource_pack", "java", ) ) ) yield 0.1, lang.get( "program_3d_edit.canvas.downloading_java_vanilla_resource_pack" ) gen = get_java_vanilla_latest_iter() try: while True: yield next(gen) * 0.4 + 0.1 except StopIteration as e: packs.append(e.value) except Exception as e: log.error( str(e), exc_info=True, ) wx.MessageBox( f"{lang.get('program_3d_edit.canvas.downloading_java_vanilla_resource_pack_failed')}\n{e}" ) yield 0.5, lang.get("program_3d_edit.canvas.loading_resource_packs") packs += [pack for pack in user_packs if isinstance(pack, JavaResourcePack)] packs.append(get_java_vanilla_fix()) translator = self.world.translation_manager.get_version("java", (999, 0, 0)) resource_pack = load_resource_pack_manager(packs, load=False) for i in resource_pack.reload(): yield i / 4 + 0.5 opengl_resource_pack = OpenGLResourcePack(resource_pack, translator) yield 0.75, lang.get("program_3d_edit.canvas.creating_texture_atlas") for i in opengl_resource_pack.setup(): yield i / 4 + 0.75 yield 1.0, lang.get("program_3d_edit.canvas.setting_up_renderer") self._renderer: Optional[Renderer] = Renderer( self, self.world, self.context_identifier, opengl_resource_pack, )
def _setup(self) -> Generator[OperationYieldType, None, None]: """Set up objects that take a while to set up.""" packs = [] user_packs = [ load_resource_pack(os.path.join("resource_packs", rp)) for rp in os.listdir("resource_packs") if os.path.isdir(os.path.join("resource_packs", rp)) ] if (self.world.level_wrapper.platform == "bedrock" and experimental_bedrock_resources): packs.append( load_resource_pack( os.path.join( os.path.dirname(amulet_edit.__file__), "amulet_resource_pack", "bedrock", ))) yield 0.1, "Downloading Bedrock vanilla resource pack" gen = get_bedrock_vanilla_latest_iter() try: while True: yield next(gen) * 0.4 + 0.1 except StopIteration as e: packs.append(e.value) yield 0.5, "Loading resource packs" packs += [ pack for pack in user_packs if isinstance(pack, BedrockResourcePack) ] packs.append(get_bedrock_vanilla_fix()) translator = self.world.translation_manager.get_version( "bedrock", (999, 0, 0)) else: packs.append( load_resource_pack( os.path.join( os.path.dirname(amulet_edit.__file__), "amulet_resource_pack", "java", ))) yield 0.1, "Downloading Java vanilla resource pack" gen = get_java_vanilla_latest_iter() try: while True: yield next(gen) * 0.4 + 0.1 except StopIteration as e: packs.append(e.value) except Exception as e: log.error( str(e), exc_info=True, ) wx.MessageBox( "Failed to download the latest Java resource pack.\n" "Check your internet connection and restart Amulet.\n" "Check the console for more details.\n" f"{e}") yield 0.5, "Loading resource packs" packs += [ pack for pack in user_packs if isinstance(pack, JavaResourcePack) ] packs.append(get_java_vanilla_fix()) translator = self.world.translation_manager.get_version( "java", (999, 0, 0)) resource_pack = load_resource_pack_manager(packs, load=False) for i in resource_pack.reload(): yield i / 4 + 0.5 opengl_resource_pack = OpenGLResourcePack(resource_pack, translator) yield 0.75, "Creating texture atlas" for i in opengl_resource_pack.setup(): yield i / 4 + 0.75 yield 1.0, "Setting up renderer" self._renderer: Optional[Renderer] = Renderer( self, self.world, self.context_identifier, opengl_resource_pack, )
def _run_operation(self, operation_path=None) -> Any: if operation_path is None: operation_path = self._operation_options.operation operation = plugins.all_operations[operation_path] features = operation.get("features", []) operation_input_definitions = operation.get("inputs", []) if any(feature in features for feature in ("dst_location_absolute", )): if "structure_callable" in operation: operation_inputs = [] for inp in operation.get("structure_callable_inputs", []): if inp == "src_selection": selection = self._get_box() if selection is None: return operation_inputs.append(selection) elif inp == "options": operation_inputs.append( plugins.options.get(operation_path, {})) self._operation_options.Disable() self._canvas.disable_threads() try: structure = show_loading_dialog( lambda: operation["structure_callable"] (self._world, self._canvas.dimension, *operation_inputs ), f'Running structure operation for {operation["name"]}.', "Please wait for the operation to finish.", self, ) except Exception as e: log.error( f"Error running structure operation: {e}\n{traceback.format_exc()}" ) wx.MessageBox(f"Error running structure operation: {e}") self._world.restore_last_undo_point() self._canvas.enable_threads() return self._canvas.enable_threads() self._operation_options.Enable() if not isinstance(structure, Structure): log.error( "Object returned from structure_callable was not a Structure. Aborting." ) wx.MessageBox( "Object returned from structure_callable was not a Structure. Aborting." ) return else: selection = self._get_box() if selection is None: return self._operation_options.Disable() structure = show_loading_dialog( lambda: Structure.from_world(self._world, selection, self. _canvas.dimension), f'Running structure operation for {operation["name"]}.', "Copying structure from world.", self, ) self._operation_options.Enable() if "dst_location_absolute" in features: # trigger UI to show select box UI self._operation_options.enable_select_destination_ui( operation_path, operation["operation"], operation_input_definitions, structure, plugins.options.get(operation_path, {}), ) else: # trigger UI to show select box multiple UI raise NotImplementedError else: self._operation_options.Disable() out = self._run_main_operation(operation_path, operation["operation"], operation_input_definitions) self._operation_options.Enable() return out