diff --git a/amulet_map_editor/api/wx/ui/select_world.py b/amulet_map_editor/api/wx/ui/select_world.py index 69fac186..2d7c4a2d 100644 --- a/amulet_map_editor/api/wx/ui/select_world.py +++ b/amulet_map_editor/api/wx/ui/select_world.py @@ -1,20 +1,22 @@ import os -import wx import glob from sys import platform from typing import List, Dict, Tuple, Callable, TYPE_CHECKING import traceback import logging +import zipfile + +import wx from amulet import load_format from amulet.api.errors import FormatError from amulet_map_editor import lang, CONFIG from amulet_map_editor.api.wx.ui import simple +from amulet_map_editor.api.wx.ui.traceback_dialog import TracebackDialog from amulet_map_editor.api.wx.util.ui_preferences import preserve_ui_preferences from amulet_map_editor.api.framework import app - if TYPE_CHECKING: from amulet.api.wrapper import WorldFormatWrapper @@ -313,11 +315,31 @@ def __init__(self, parent, open_world_callback): sizer = wx.BoxSizer(wx.VERTICAL) self.SetSizer(sizer) + header_sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(header_sizer, 0, wx.EXPAND) + header_sizer.AddStretchSpacer() + self.header_open_world = wx.Button( self, label=lang.get("select_world.open_world_button") ) + font = self.header_open_world.GetFont() + font.SetPointSize(16) + self.header_open_world.SetFont(font) self.header_open_world.Bind(wx.EVT_BUTTON, self._open_world) - sizer.Add(self.header_open_world) + header_sizer.Add(self.header_open_world) + + header_sizer.AddSpacer(20) + + self.header_open_mcworld = wx.Button( + self, label=lang.get("select_world.open_mcworld_button") + ) + font = self.header_open_mcworld.GetFont() + font.SetPointSize(16) + self.header_open_mcworld.SetFont(font) + self.header_open_mcworld.Bind(wx.EVT_BUTTON, self._open_mcworld) + header_sizer.Add(self.header_open_mcworld) + + header_sizer.AddStretchSpacer() content = ScrollableWorldsUI(self, open_world_callback) sizer.Add(content, 1, wx.EXPAND) @@ -340,6 +362,66 @@ def _open_world(self, evt): dir_dialog.Destroy() self.open_world_callback(path) + def _open_mcworld(self, evt): + mcworld_dialog = wx.FileDialog( + None, + lang.get("select_world.open_mcworld_dialogue"), + "", + style=wx.FD_DEFAULT_STYLE | wx.FD_FILE_MUST_EXIST, + wildcard="Bedrock world archive (*.mcworld)|*.mcworld", + ) + try: + if mcworld_dialog.ShowModal() == wx.ID_CANCEL: + return + mcworld_path = mcworld_dialog.GetPath() + except Exception: + wx.LogError(lang.get("select_world.select_directory_failed")) + return + finally: + mcworld_dialog.Destroy() + + dir_dialog = wx.DirDialog( + None, + lang.get("select_world.extract_mcworld_dialogue"), + "", + wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST, + ) + try: + if dir_dialog.ShowModal() == wx.ID_CANCEL: + return + extract_dir = dir_dialog.GetPath() + except Exception: + wx.LogError(lang.get("select_world.select_directory_failed")) + return + finally: + dir_dialog.Destroy() + + if next(os.scandir(extract_dir), None) is not None: + wx.LogError(lang.get("select_world.extracting_world_not_empty")) + return + + busy_msg = wx.BusyInfo(lang.get("select_world.extracting_world_wait")) + + try: + zipfile.ZipFile(mcworld_path).extractall(extract_dir) + except Exception as e: + del busy_msg + dialog = TracebackDialog( + self, + lang.get("select_world.extracting_world_failed"), + str(e), + traceback.format_exc(), + ) + dialog.ShowModal() + dialog.Destroy() + return + else: + del busy_msg + + wx.MessageBox(lang.get("select_world.extracting_world_finished"), "Info", wx.OK) + + self.open_world_callback(extract_dir) + class RecentWorldUI(wx.Panel): def __init__(self, parent, open_world_callback): diff --git a/amulet_map_editor/lang/en.lang b/amulet_map_editor/lang/en.lang index 914a88fd..1b813a84 100644 --- a/amulet_map_editor/lang/en.lang +++ b/amulet_map_editor/lang/en.lang @@ -123,9 +123,16 @@ update_check.ok=Ok ## The window when selecting a world to open select_world.title=World Select select_world.open_world_warning=Close the world in game and other tools before opening in Amulet. -select_world.open_world_button=Open other world +select_world.open_world_button=Open World Directory select_world.open_world_dialogue=Select a Minecraft world directory select_world.select_directory_failed=Failed to open directory! +select_world.open_mcworld_button=Open Bedrock .mcworld File +select_world.open_mcworld_dialogue=Select .mcworld file +select_world.extract_mcworld_dialogue=Select directory to extract .mcworld file into +select_world.extracting_world_wait=Extracting world. Please wait. +select_world.extracting_world_not_empty=The directory must be empty. +select_world.extracting_world_failed=Failed extracting world. +select_world.extracting_world_finished=Finished extracting world. Amulet will edit the extracted world. select_world.recent_worlds=Recently Opened Worlds select_world.no_loader_found=Could not find a loader for this world. select_world.loading_world_failed=Error loading world. diff --git a/amulet_map_editor/readme.md b/amulet_map_editor/readme.md index 95ed5491..a77c05ca 100644 --- a/amulet_map_editor/readme.md +++ b/amulet_map_editor/readme.md @@ -18,7 +18,7 @@ On the left should be some expandable panes containing the worlds stored in the Click on a world to open it with Amulet. -If you wish to open a world from a different location press the "open other world" button and select the world folder. +If you wish to open a world from a different location press the "Open World Directory" button and select the world folder. On the right will be worlds that you have recently opened in Amulet (this will be blank if you have not opened any worlds yet).