Пример #1
0
def load_level(path: str) -> Union[World, Structure]:
    """
    Load and return a :class:`World` or :class:`Structure` class exposing the data at ``path``

    Calls :func:`load_format` to try and find a :class:`FormatWrapper` that can open the data.

    If one is found it will wrap it with either a :class:`World` or :class:`Structure` class and return it.

    :param path: The file path to a file or directory for the object to be loaded.
    :return: A World or Structure class instance containing the data.
    :raises:
        LoaderNoneMatched: If no loader could be found that can open the data at path.

        Exception: Other errors.
    """
    log.info(f"Loading level {path}")
    format_wrapper = load_format(path)
    if isinstance(format_wrapper, WorldFormatWrapper):
        return World(path, format_wrapper)
    elif isinstance(format_wrapper, StructureFormatWrapper):
        return Structure(path, format_wrapper)
    else:
        raise Exception(
            f"FormatWrapper of type {format_wrapper.__class__.__name__} is not supported. Report this to a developer."
        )
Пример #2
0
def load_world(directory: str,
               _format: str = None,
               forced: bool = False) -> World:
    """
    Creates a Format loader from the given inputs and wraps it in a World class
    :param directory:
    :param _format:
    :param forced:
    :return:
    """
    log.info(f"Loading world {directory}")
    return World(directory, load_format(directory, _format, forced))
Пример #3
0
def load_level(path: str) -> Union[World, Structure]:
    """
    Creates a Format loader from the given inputs and wraps it in a World class
    :param path:
    :return:
    """
    log.info(f"Loading level {path}")
    format_wrapper = load_format(path)
    if isinstance(format_wrapper, WorldFormatWrapper):
        return World(path, format_wrapper)
    elif isinstance(format_wrapper, StructureFormatWrapper):
        return Structure(path, format_wrapper)
    else:
        raise Exception
Пример #4
0
    def is_valid(directory) -> bool:
        """
        Returns whether this format is able to load a given world.

        :param directory: The path to the root of the world to load.
        :return: True if the world can be loaded by this format, False otherwise.
        """
        if not check_all_exist(directory, "level.dat"):
            return False

        try:
            level_dat_root = load_leveldat(directory)
        except:
            return False

        if "Data" not in level_dat_root:
            return False

        if "FML" in level_dat_root:
            return True

        log.info("Forge support is experimental. Use at your own risk.")
        return True
Пример #5
0
def _clear_db():
    if _cache_db is not None:
        log.info("Removing cache.")
        _cache_db.close(compact=False)
        shutil.rmtree(os.path.dirname(_path))
Пример #6
0
    def save_iter(
        self,
        wrapper: api_wrapper.FormatWrapper = None
    ) -> Generator[Tuple[int, int], None, None]:
        """
        Save the level to the given :class:`FormatWrapper`.

        This will yield the progress which can be used to update a UI.

        :param wrapper: If specified will save the data to this wrapper instead of self.level_wrapper
        :return: A generator of the number of chunks completed and the total number of chunks
        """
        # TODO change the yield type to match OperationReturnType

        chunk_index = 0

        changed_chunks = list(self._chunks.changed_chunks())
        chunk_count = len(changed_chunks)

        if wrapper is None:
            wrapper = self.level_wrapper

        output_dimension_map = wrapper.dimensions

        # perhaps make this check if the directory is the same rather than if the class is the same
        save_as = wrapper is not self.level_wrapper
        if save_as:
            # The input wrapper is not the same as the loading wrapper (save-as)
            # iterate through every chunk in the input level and save them to the wrapper
            log.info(
                f"Converting level {self.level_wrapper.path} to level {wrapper.path}"
            )
            wrapper.translation_manager = (
                self.level_wrapper.translation_manager
            )  # TODO: this might cause issues in the future
            for dimension in self.level_wrapper.dimensions:
                chunk_count += len(
                    list(self.level_wrapper.all_chunk_coords(dimension)))

            for dimension in self.level_wrapper.dimensions:
                try:
                    if dimension not in output_dimension_map:
                        continue
                    for cx, cz in self.level_wrapper.all_chunk_coords(
                            dimension):
                        log.info(f"Converting chunk {dimension} {cx}, {cz}")
                        try:
                            chunk = self.level_wrapper.load_chunk(
                                cx, cz, dimension)
                            wrapper.commit_chunk(chunk, dimension)
                        except ChunkLoadError:
                            log.info(f"Error loading chunk {cx} {cz}",
                                     exc_info=True)
                        chunk_index += 1
                        yield chunk_index, chunk_count
                        if not chunk_index % 10000:
                            wrapper.save()
                            self.level_wrapper.unload()
                            wrapper.unload()
                except DimensionDoesNotExist:
                    continue

        for dimension, cx, cz in changed_chunks:
            if dimension not in output_dimension_map:
                continue
            try:
                chunk = self.get_chunk(cx, cz, dimension)
            except ChunkDoesNotExist:
                wrapper.delete_chunk(cx, cz, dimension)
            except ChunkLoadError:
                pass
            else:
                wrapper.commit_chunk(chunk, dimension)
                chunk.changed = False
            chunk_index += 1
            yield chunk_index, chunk_count
            if not chunk_index % 10000:
                wrapper.save()
                wrapper.unload()

        self.history_manager.mark_saved()
        log.info(f"Saving changes to level {wrapper.path}")
        wrapper.save()
        log.info(f"Finished saving changes to level {wrapper.path}")
Пример #7
0
def clear_db():
    log.info("Removing cache.")
    CacheDB.close(compact=False)
    shutil.rmtree(_path)
Пример #8
0
    def save_iter(
        self, wrapper: "WorldFormatWrapper" = None
    ) -> Generator[Tuple[int, int], None, None]:
        """Save the world using the given wrapper.
        Leave as None to save back to the input wrapper."""
        chunk_index = 0
        if self._needs_undo_point or any(
            chunk is not None and chunk.changed for chunk in self._chunk_cache.values()
        ):
            self.create_undo_point()
            self._needs_undo_point = False

        changed_chunks = list(self._chunk_history_manager.changed_chunks())
        chunk_count = len(changed_chunks)

        if wrapper is None:
            wrapper = self._world_wrapper

        output_dimension_map = wrapper.dimensions

        # perhaps make this check if the directory is the same rather than if the class is the same
        save_as = wrapper is not self._world_wrapper
        if save_as:
            # The input wrapper is not the same as the loading wrapper (save-as)
            # iterate through every chunk in the input world and save them to the wrapper
            log.info(
                f"Converting world {self._world_wrapper.path} to world {wrapper.path}"
            )
            wrapper.translation_manager = (
                self._world_wrapper.translation_manager
            )  # TODO: this might cause issues in the future
            for dimension in self._world_wrapper.dimensions:
                chunk_count += len(
                    list(self._world_wrapper.all_chunk_coords(dimension))
                )

            for dimension in self._world_wrapper.dimensions:
                try:
                    if dimension not in output_dimension_map:
                        continue
                    for cx, cz in self._world_wrapper.all_chunk_coords(dimension):
                        log.info(f"Converting chunk {dimension} {cx}, {cz}")
                        try:
                            chunk = self._world_wrapper.load_chunk(cx, cz, dimension)
                            wrapper.commit_chunk(chunk, dimension)
                        except ChunkLoadError:
                            log.info(f"Error loading chunk {cx} {cz}", exc_info=True)
                        chunk_index += 1
                        yield chunk_index, chunk_count
                        if not chunk_index % 10000:
                            wrapper.save()
                            self._world_wrapper.unload()
                            wrapper.unload()
                except LevelDoesNotExist:
                    continue

        for dimension, cx, cz in changed_chunks:
            if dimension not in output_dimension_map:
                continue
            chunk = self._chunk_history_manager.get_current(
                dimension, cx, cz, self._block_palette, self._biome_palette
            )
            if chunk is None:
                wrapper.delete_chunk(cx, cz, dimension)
            else:
                wrapper.commit_chunk(chunk, dimension)
            chunk_index += 1
            yield chunk_index, chunk_count
            if not chunk_index % 10000:
                wrapper.save()
                wrapper.unload()

        self._chunk_history_manager.mark_saved()
        log.info(f"Saving changes to world {wrapper.path}")
        wrapper.save()
        log.info(f"Finished saving changes to world {wrapper.path}")
Пример #9
0
 def world_path(self) -> str:
     """The path to the world directory"""
     log.info(
         f"Format.world_path is depreciated. Please used Format.path{traceback.format_exc()}"
     )
     return self._path