diff --git a/amulet_map_editor/__init__.py b/amulet_map_editor/__init__.py index 0067cdd4..728cd2cd 100644 --- a/amulet_map_editor/__init__.py +++ b/amulet_map_editor/__init__.py @@ -1,4 +1,5 @@ -import logging +import os +import platformdirs experimental_bedrock_resources = False @@ -6,6 +7,22 @@ __version__ = get_versions()["version"] del get_versions + +# Initialise default paths. These should be initialised in main before this is imported +# but the tests don't run main so a default is required for that case. +data_dir = platformdirs.user_data_dir("AmuletMapEditor", "AmuletTeam") +os.environ.setdefault("DATA_DIR", data_dir) +config_dir = platformdirs.user_config_dir("AmuletMapEditor", "AmuletTeam") +if config_dir == data_dir: + config_dir = os.path.join(data_dir, "Config") +os.environ.setdefault("CONFIG_DIR", config_dir) +os.environ.setdefault( + "CACHE_DIR", platformdirs.user_cache_dir("AmuletMapEditor", "AmuletTeam") +) +os.environ.setdefault( + "LOG_DIR", platformdirs.user_log_dir("AmuletMapEditor", "AmuletTeam") +) + from amulet_map_editor.api import config as CONFIG, lang from amulet_map_editor.api.framework.app import open_level, close_level diff --git a/amulet_map_editor/__main__.py b/amulet_map_editor/__main__.py index 3c73cf83..8b6b9a0e 100644 --- a/amulet_map_editor/__main__.py +++ b/amulet_map_editor/__main__.py @@ -3,24 +3,31 @@ def _on_error(e): """Code to handle errors""" - err_list = [] try: import traceback + import sys + import os - err_list.append(traceback.format_exc()) - except: - pass - if isinstance(e, ImportError): - err_list.append( - f"Failed to import requirements. Check that you extracted correctly." + except ImportError as e: + # Something has gone seriously wrong + print(e) + print("Failed to import requirements. Check that you extracted correctly.") + input("Press ENTER to continue.") + else: + err = "\n".join( + [traceback.format_exc()] + + ["Failed to import requirements. Check that you extracted correctly."] + * isinstance(e, ImportError) + + [str(e)] ) - err_list.append(str(e)) - err = "\n".join(err_list) - print(err) - with open("./logs/crash.log", "w") as f: - f.write(err) - input("Press ENTER to continue.") - sys.exit(1) + print(err) + try: + with open("crash.log", "w") as f: + f.write(err) + except OSError: + pass + input("Press ENTER to continue.") + sys.exit(1) try: @@ -34,16 +41,17 @@ def _on_error(e): import glob import time import wx + import platformdirs if sys.platform == "linux" and wx.VERSION >= (4, 1, 1): # bug 247 os.environ["PYOPENGL_PLATFORM"] = "egl" -except Exception as e: - _on_error(e) +except Exception as e_: + _on_error(e_) def _init_log(): - logs_path = os.path.join(".", "logs") + logs_path = os.environ["LOG_DIR"] # set up handlers os.makedirs(logs_path, exist_ok=True) # remove all log files older than a week @@ -72,22 +80,36 @@ def _init_log(): def main(): try: + # Initialise default paths. + data_dir = platformdirs.user_data_dir("AmuletMapEditor", "AmuletTeam") + os.environ.setdefault("DATA_DIR", data_dir) + config_dir = platformdirs.user_config_dir("AmuletMapEditor", "AmuletTeam") + if config_dir == data_dir: + config_dir = os.path.join(data_dir, "Config") + os.environ.setdefault("CONFIG_DIR", config_dir) + os.environ.setdefault( + "CACHE_DIR", platformdirs.user_cache_dir("AmuletMapEditor", "AmuletTeam") + ) + os.environ.setdefault( + "LOG_DIR", platformdirs.user_log_dir("AmuletMapEditor", "AmuletTeam") + ) + _init_log() from amulet_map_editor.api.framework import AmuletApp except Exception as e: _on_error(e) - AmuletApp = None + else: + try: + app = AmuletApp(0) + app.MainLoop() + except Exception as e: + log = logging.getLogger(__name__) + log.critical( + f"Amulet Crashed. Sorry about that. Please report it to a developer if you think this is an issue. \n{traceback.format_exc()}" + ) + input("Press ENTER to continue.") - try: - app = AmuletApp(0) - app.MainLoop() - except Exception as e: - log = logging.getLogger(__name__) - log.critical( - f"Amulet Crashed. Sorry about that. Please report it to a developer if you think this is an issue. \n{traceback.format_exc()}" - ) - input("Press ENTER to continue.") sys.exit(0) diff --git a/amulet_map_editor/api/config.py b/amulet_map_editor/api/config.py index 0f9ac2b1..58beedbe 100644 --- a/amulet_map_editor/api/config.py +++ b/amulet_map_editor/api/config.py @@ -3,7 +3,7 @@ import gzip from typing import Any -_path = os.path.abspath(os.path.join(".", "config")) +_path = os.path.abspath(os.path.join(os.environ["CONFIG_DIR"])) def get(identifier: str, default: Any = None) -> Any: diff --git a/amulet_map_editor/api/opengl/resource_pack/resource_pack.py b/amulet_map_editor/api/opengl/resource_pack/resource_pack.py index 9f2b54b8..6bf067c9 100644 --- a/amulet_map_editor/api/opengl/resource_pack/resource_pack.py +++ b/amulet_map_editor/api/opengl/resource_pack/resource_pack.py @@ -113,7 +113,7 @@ def setup(self) -> Generator[float, None, None]: default=0, ) - cache_dir = os.path.join(".", "cache", "resource_pack") + cache_dir = os.path.join(os.environ["CACHE_DIR"], "resource_packs", "atlas") img_path = os.path.join(cache_dir, f"{cache_id}.png") bounds_path = os.path.join(cache_dir, f"{cache_id}.json") try: diff --git a/amulet_map_editor/programs/edit/api/canvas/base_edit_canvas.py b/amulet_map_editor/programs/edit/api/canvas/base_edit_canvas.py index 07b8befc..70a8d05c 100644 --- a/amulet_map_editor/programs/edit/api/canvas/base_edit_canvas.py +++ b/amulet_map_editor/programs/edit/api/canvas/base_edit_canvas.py @@ -77,16 +77,13 @@ def __init__(self, parent: wx.Window, world: BaseLevel): self._mouse: MouseMovement = MouseMovement(self) self._mouse.set_middle() + resource_packs_dir = os.path.join(os.environ["DATA_DIR"], "resource_packs") + readme_path = os.path.join(resource_packs_dir, "readme.txt") # create the resource packs location - try: - os.makedirs("resource_packs", exist_ok=True) - if not os.path.isfile("resource_packs/readme.txt"): - with open("resource_packs/readme.txt", "w") as f: - f.write("Put the Java resource pack you want loaded in here.") - except PermissionError as e: - raise PermissionError( - "Amulet is not able to write to the install directory. Try moving Amulet to somewhere else on your computer." - ) from e + os.makedirs(resource_packs_dir, exist_ok=True) + if not os.path.isfile(readme_path): + with open(readme_path, "w") as f: + f.write("Put the Java resource pack you want loaded in here.") self._renderer: Optional[Renderer] = None self._opengl_resource_pack = None @@ -97,10 +94,11 @@ def thread_setup(self) -> Generator[OperationYieldType, None, None]: All code in here must be thread safe and not touch the OpenGL state. """ packs = [] + resource_packs_dir = os.path.join(os.environ["DATA_DIR"], "resource_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)) + load_resource_pack(os.path.join(resource_packs_dir, rp)) + for rp in os.listdir(resource_packs_dir) + if os.path.isdir(os.path.join(resource_packs_dir, rp)) ] if ( self.world.level_wrapper.platform == "bedrock" diff --git a/amulet_map_editor/programs/edit/api/operations/manager/loader/ui_operation_loader.py b/amulet_map_editor/programs/edit/api/operations/manager/loader/ui_operation_loader.py index 14345f56..5ee94477 100644 --- a/amulet_map_editor/programs/edit/api/operations/manager/loader/ui_operation_loader.py +++ b/amulet_map_editor/programs/edit/api/operations/manager/loader/ui_operation_loader.py @@ -36,7 +36,8 @@ def _setup(self, export_dict: dict): """Parse the export dictionary and setup as required.""" options_path = os.path.abspath( os.path.join( - "config", + os.environ["CONFIG_DIR"], + "plugins", "edit_plugins", f"""{''.join(c for c in self._name if c in ValidChrs)}_{ struct.unpack( diff --git a/amulet_map_editor/programs/edit/api/operations/manager/util.py b/amulet_map_editor/programs/edit/api/operations/manager/util.py index 5ac9b94d..3949cf0d 100644 --- a/amulet_map_editor/programs/edit/api/operations/manager/util.py +++ b/amulet_map_editor/programs/edit/api/operations/manager/util.py @@ -1,13 +1,8 @@ import os -import pkgutil -import sys -from typing import Optional -from types import ModuleType -import importlib.util from amulet_map_editor.programs.edit.plugins.operations import stock_plugins STOCK_PLUGINS_DIR: str = stock_plugins.__path__[0] STOCK_PLUGINS_NAME: str = stock_plugins.__name__ -CUSTOM_PLUGINS_DIR = os.path.abspath("plugins") +CUSTOM_PLUGINS_DIR = os.path.join(os.environ["DATA_DIR"], "plugins") diff --git a/setup.cfg b/setup.cfg index a0607e37..583e6c3b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -25,6 +25,7 @@ install_requires = amulet-nbt~=2.0 pymctranslate~=1.2 minecraft-resource-pack~=1.3 + platformdirs~=3.1 packages = find: