From b81d0da148910af08b4ad685f6f3e0ef118f7e2d Mon Sep 17 00:00:00 2001 From: duckboycool Date: Tue, 7 Jul 2026 16:01:26 -0600 Subject: [PATCH] Add apworld spec on new install --- worlds/LauncherComponents.py | 1 + worlds/__init__.py | 35 ++++++++++++++++++++--------------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/worlds/LauncherComponents.py b/worlds/LauncherComponents.py index e0d981c6a3fb..31ab6e3da532 100644 --- a/worlds/LauncherComponents.py +++ b/worlds/LauncherComponents.py @@ -182,6 +182,7 @@ def _install_apworld(apworld_src: str = "") -> Optional[Tuple[pathlib.Path, path "so a Launcher restart is required to use the new installation.") world_source = worlds.WorldSource(str(target), is_zip=True, relative=False) bisect.insort(worlds.world_sources, world_source) + worlds.add_apworld_spec(world_source, worlds.APWorldContainer(world_source.resolved_path)) world_source.load() return apworld_path, target diff --git a/worlds/__init__.py b/worlds/__init__.py index 8684b7424957..6c9e36e54ccf 100644 --- a/worlds/__init__.py +++ b/worlds/__init__.py @@ -15,6 +15,7 @@ from NetUtils import DataPackage from Utils import local_path, user_path, Version, version_tuple, tuplize_version, messagebox +from .Files import APWorldContainer local_folder = os.path.dirname(__file__) user_folder = user_path("worlds") if user_path() != local_path() else user_path("custom_worlds") @@ -74,6 +75,23 @@ def load(self) -> bool: return False +apworld_module_specs = {} +class APWorldModuleFinder(importlib.abc.MetaPathFinder): + def find_spec( + self, fullname: str, _path: Sequence[str] | None, _target: ModuleType | None = None + ) -> importlib.machinery.ModuleSpec | None: + return apworld_module_specs.get(fullname) +sys.meta_path.insert(0, APWorldModuleFinder()) + + +def add_apworld_spec(source: WorldSource, container: APWorldContainer): + importer = zipimport.zipimporter(source.resolved_path) + world_name = Path(container.path).stem + + spec = importer.find_spec(f"worlds.{world_name}") + apworld_module_specs[f"worlds.{world_name}"] = spec + + # find potential world containers, currently folders and zip-importable .apworld's world_sources: List[WorldSource] = [] for folder in (folder for folder in (user_folder, local_folder) if folder): @@ -125,7 +143,7 @@ def load(self) -> bool: # encapsulation for namespace / gc purposes def load_apworlds() -> None: global apworlds - from .Files import APWorldContainer, InvalidDataError + from .Files import InvalidDataError core_compatible: list[tuple[WorldSource, APWorldContainer]] = [] def fail_world(game_name: str, reason: str, add_as_failed_to_load: bool = True) -> None: @@ -174,15 +192,6 @@ def fail_world(game_name: str, reason: str, add_as_failed_to_load: bool = True) key=lambda element: element[1].world_version if element[1].world_version else Version(0, 0, 0), reverse=True) - apworld_module_specs = {} - class APWorldModuleFinder(importlib.abc.MetaPathFinder): - def find_spec( - self, fullname: str, _path: Sequence[str] | None, _target: ModuleType = None - ) -> importlib.machinery.ModuleSpec | None: - return apworld_module_specs.get(fullname) - - sys.meta_path.insert(0, APWorldModuleFinder()) - for apworld_source, apworld in core_compatible: if apworld.game and apworld.game in AutoWorldRegister.world_types: fail_world(apworld.game, @@ -190,11 +199,7 @@ def find_spec( f"as its game {apworld.game} is already loaded.", add_as_failed_to_load=False) else: - importer = zipimport.zipimporter(apworld_source.resolved_path) - world_name = Path(apworld.path).stem - - spec = importer.find_spec(f"worlds.{world_name}") - apworld_module_specs[f"worlds.{world_name}"] = spec + add_apworld_spec(apworld_source, apworld) apworld_source.load() if apworld.game in AutoWorldRegister.world_types: