mud/src/mudlib/zones.py
Jared Miller d18f21a031
Add zone TOML loader and tavern interior zone
Implements load_zone() and load_zones() functions to parse zone
definitions from TOML files. Wires zone loading into server startup
to register all zones from content/zones/ directory. Updates player
zone lookup to use the registry instead of hardcoded overworld check.

Includes tavern.toml as first hand-built interior zone (8x6 bounded).
2026-02-11 20:58:55 -05:00

102 lines
2.3 KiB
Python

"""Zone registry and loading."""
from __future__ import annotations
import logging
import tomllib
from pathlib import Path
from mudlib.zone import Zone
log = logging.getLogger(__name__)
# Module-level zone registry
zone_registry: dict[str, Zone] = {}
def register_zone(name: str, zone: Zone) -> None:
"""Register a zone by name.
Args:
name: Unique name for the zone
zone: Zone instance to register
"""
zone_registry[name] = zone
def get_zone(name: str) -> Zone | None:
"""Look up a zone by name.
Args:
name: Zone name to look up
Returns:
Zone instance if found, None otherwise
"""
return zone_registry.get(name)
def load_zone(path: Path) -> Zone:
"""Load a zone from a TOML file.
Args:
path: Path to TOML file
Returns:
Zone instance loaded from file
"""
with open(path, "rb") as f:
data = tomllib.load(f)
# Extract basic properties
name = data["name"]
width = data["width"]
height = data["height"]
toroidal = data.get("toroidal", True)
# Parse terrain rows into 2D list
terrain_rows = data.get("terrain", {}).get("rows", [])
terrain = []
for row in terrain_rows:
terrain.append(list(row))
# Parse impassable tiles
impassable_list = data.get("terrain", {}).get("impassable", {}).get("tiles", [])
impassable = set(impassable_list) if impassable_list else {"^", "~"}
zone = Zone(
name=name,
width=width,
height=height,
toroidal=toroidal,
terrain=terrain,
impassable=impassable,
)
return zone
def load_zones(directory: Path) -> dict[str, Zone]:
"""Load all zones from a directory.
Args:
directory: Path to directory containing zone TOML files
Returns:
Dict mapping zone names to Zone instances
"""
zones = {}
if not directory.exists():
log.warning("zones directory does not exist: %s", directory)
return zones
for toml_file in directory.glob("*.toml"):
try:
zone = load_zone(toml_file)
zones[zone.name] = zone
log.debug("loaded zone '%s' from %s", zone.name, toml_file)
except Exception as e:
log.error("failed to load zone from %s: %s", toml_file, e, exc_info=True)
return zones