from __future__ import annotations import json from pathlib import Path from engine.map import Map from engine.tile import TILE_LAYERS, Tile, TileLayerInstance def _layer_instances(fields: dict) -> dict[str, TileLayerInstance | None]: return {layer: (TileLayerInstance(def_id) if def_id else None) for layer, def_id in fields.items() if layer in TILE_LAYERS} class MapLoader: """Builds Map graphs (including embedded sub-maps) from resources/defs/maps/*.json.""" def __init__(self, maps_dir: Path): self.maps_dir = maps_dir self._cache: dict[str, Map] = {} def load(self, filename: str) -> Map: data = json.loads((self.maps_dir / filename).read_text()) map_id = data["map_id"] if map_id in self._cache: return self._cache[map_id] m = Map(map_id, data["width"], data["height"], data["depth"], source_def=filename) self._cache[map_id] = m default_tile = data.get("default_tile", {}) for z in range(m.depth): for y in range(m.height): for x in range(m.width): m.set_tile(x, y, z, Tile(**_layer_instances(default_tile))) for override in data.get("tiles", []): x, y, z = override["x"], override["y"], override["z"] fields = {k: v for k, v in override.items() if k not in ("x", "y", "z")} tile = m.get_tile(x, y, z) for layer, instance in _layer_instances(fields).items(): tile.set_layer(layer, instance) for embedding in data.get("embeddings", []): child = self.load(embedding["map_file"]) m.embed( child, tuple(embedding["anchor"]), embedding.get("rotation", 0), embedding.get("max_rotation_speed", 90.0), ) return m