Mi2dRPGamEng/engine/map_loader.py

48 lines
1.7 KiB
Python

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))
return m