"""Zone registry and loading.""" from __future__ import annotations import logging import tomllib from pathlib import Path from mudlib.portal import Portal from mudlib.zone import SpawnRule, 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"] description = data.get("description", "") width = data["width"] height = data["height"] toroidal = data.get("toroidal", True) spawn_x = data.get("spawn_x", 0) spawn_y = data.get("spawn_y", 0) # 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 {"^", "~"} # Parse ambient messages ambient_data = data.get("ambient", {}) ambient_messages = ambient_data.get("messages", []) ambient_interval = ambient_data.get("interval", 120) # Parse spawn rules spawns_data = data.get("spawns", []) spawn_rules = [ SpawnRule( mob=spawn["mob"], max_count=spawn.get("max_count", 1), respawn_seconds=spawn.get("respawn_seconds", 300), ) for spawn in spawns_data ] zone = Zone( name=name, description=description, width=width, height=height, toroidal=toroidal, terrain=terrain, impassable=impassable, spawn_x=spawn_x, spawn_y=spawn_y, ambient_messages=ambient_messages, ambient_interval=ambient_interval, spawn_rules=spawn_rules, ) # Load portals portals_data = data.get("portals", []) for portal_dict in portals_data: # Parse target string "zone_name:x,y" target = portal_dict["target"] try: target_zone, coords = target.split(":") target_x, target_y = map(int, coords.split(",")) except ValueError: log.warning( "skipping portal '%s' at (%d, %d): malformed target '%s'", portal_dict["label"], portal_dict["x"], portal_dict["y"], target, ) continue # Create portal (automatically added to zone._contents via Object.__post_init__) Portal( name=portal_dict["label"], aliases=portal_dict.get("aliases", []), target_zone=target_zone, target_x=target_x, target_y=target_y, location=zone, x=portal_dict["x"], y=portal_dict["y"], ) 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