Source code for api.world_loader

from __future__ import annotations

import os
import glob
import sys
import traceback
from importlib import import_module
from typing import Tuple, List

from api.paths import DEFINITIONS_DIR
from api.world import World

from api.errors import (
    FormatLoaderInvalidFormat,
    FormatLoaderMismatched,
    FormatLoaderNoneMatched,
)


[docs]class _WorldLoader: """ Class responsible for loading worlds """ def __init__(self): self._identifiers = {} for definition in glob.iglob(os.path.join(DEFINITIONS_DIR, "**", "*.py")): module_name = os.path.basename(os.path.dirname(definition)) if not definition.endswith(f"{module_name}.py"): continue sys.path.insert(0, os.path.dirname(definition)) definition_name = os.path.basename(os.path.dirname(definition)) try: module = import_module(os.path.basename(definition)[:-3]) if not ( hasattr(module, "load") or hasattr(module, "identify") or hasattr(module, "FORMAT") ): raise ValueError() self._identifiers[definition_name] = module except: if __debug__: traceback.print_exc() pass sys.path.remove(os.path.dirname(definition))
[docs] def identify(self, directory: str) -> Tuple[str, str]: """ Identifies the level format the world is in and the versions definitions that match the world. Note: Since Minecraft Java versions below 1.12 lack version identifiers, they will always be loaded with 1.12 definitions. :param directory: The directory of the world :return: The version definitions name for the world and the format loader that would be used """ for name, module in self._identifiers.items(): if module.identify(directory): return name, module.FORMAT elif __debug__: print(f"{name} rejected the world") raise FormatLoaderNoneMatched("Could not find a matching format loader")
[docs] def load_world( self, directory: str, format: str = None, forced: bool = False ) -> World: """ Loads the world located at the given directory with the appropriate version/format loader. :param directory: The directory of the world :param format: The loader name to use :param forced: Whether to force load the world even if incompatible :return: The loaded world """ if format is not None: if not format in self._identifiers: raise FormatLoaderInvalidFormat( f"Could not find format loader {format}" ) if not forced and not self.identify(directory)[0] == format: raise FormatLoaderMismatched(f"{format} is incompatible") else: format = loader.identify(directory)[0] module = self._identifiers[format] return module.load(directory)
[docs] def get_loaded_identifiers(self) -> List[str]: """ List all format loader identifiers :return: List of all format identifiers """ return list(self._identifiers.keys())
loader = _WorldLoader() load_world = loader.load_world identify = loader.identify