pipeworks_mud_mapper.models.map_file

MapFile model for authoring exports.

This module defines the MapFile model - the JSON export format used for authoring data when exporting from SQLite. Map files contain everything needed for visual map editing: rooms, exits, items, AND coordinates.

SQLite + Export Workflow

As described in goblin_cartography.md Section 2.4, the mapper now stores authoring data in SQLite and exports MapFile/Zone JSON on demand.

File Naming Convention

Map files use the .map.json extension to distinguish from zone files:

data/exports/maps/crooked_pipe.map.json  # Authoring export (has coords)
data/zones/crooked_pipe.json             # Game truth (no coords)

This makes it clear which file is the source and which is generated.

Data Flow

SQLite DB  ──► MapFile ──┬──► Export ──► exports/maps/zone.map.json
                          │
                          └──► Export ──► zones/zone.json
                                   (strips coords)

Examples

Loading a map file:

from pathlib import Path
from pipeworks_mud_mapper.models import MapFile

content = Path("data/exports/maps/my_zone.map.json").read_text()
map_file = MapFile.model_validate_json(content)

Creating a new map:

map_file = MapFile(
    id="new_zone",
    name="New Zone",
    spawn_room="spawn",
    rooms={
        "spawn": MapRoom(
            id="spawn",
            name="Spawn Room",
            coords=Coords(x=0, y=0, z=0),
        ),
    },
)

Exporting to zone (strips coordinates):

zone = map_file.to_zone()
Path("data/zones/new_zone.json").write_text(
    zone.model_dump_json(indent=2, exclude_none=True)
)

See also

Zone

Game truth format (no coordinates).

MapRoom

Room with coordinates.

Classes

MapFile

A map file in authoring format (includes coordinates).

Module Contents

class pipeworks_mud_mapper.models.map_file.MapFile(/, **data)[source]

Bases: pydantic.BaseModel

A map file in authoring format (includes coordinates).

MapFile is the primary data structure used by the mapper tool during editing. It contains all zone data plus coordinates for visualization.

When exporting to a zone file (for the MUD server), use to_zone() which strips coordinates and converts MapRooms to Rooms.

id

Unique zone identifier. Becomes the filename for both map and zone files.

Type:

str

name

Human-readable display name.

Type:

str

metadata

Versioning metadata used to pair map and zone exports.

Type:

MapMetadata

description

Optional zone description.

Type:

str

spawn_room

Room ID where players enter. Must exist in rooms dict.

Type:

str

rooms

Mapping of room ID to MapRoom objects (with coordinates).

Type:

dict[str, MapRoom]

items

Mapping of item ID to item definitions.

Type:

dict[str, dict]

Examples

>>> map_file = MapFile(
...     id="tutorial",
...     name="Tutorial Area",
...     spawn_room="spawn",
...     rooms={
...         "spawn": MapRoom(
...             id="spawn",
...             name="Start",
...             coords=Coords(x=0, y=0, z=0),
...         ),
...     },
... )

Converting to zone format:

>>> zone = map_file.to_zone()
>>> type(zone)
<class 'pipeworks_mud_mapper.models.zone.Zone'>

See also

Zone

Game truth format without coordinates.

MapRoom

Room model with coordinates.

classmethod validate_id(v)[source]

Validate zone ID format.

Zone IDs must start with a letter and contain only lowercase letters, numbers, and underscores.

validate_spawn_room_exists()[source]

Ensure spawn_room references an existing room.

validate_room_ids_match_keys()[source]

Ensure room IDs match their dictionary keys.

to_zone()[source]

Convert to game truth format by stripping coordinates.

Creates a Zone instance suitable for export to the MUD server. All MapRooms are converted to Rooms (without coordinates). Versioning metadata is carried into the Zone metadata.

Returns:

A Zone instance without coordinates.

Return type:

Zone

Examples

>>> map_file = MapFile(
...     id="test",
...     name="Test",
...     spawn_room="spawn",
...     rooms={"spawn": MapRoom(id="spawn", name="S", coords=Coords())},
... )
>>> zone = map_file.to_zone()
>>> hasattr(zone.rooms["spawn"], 'coords')
False
bump_revision()[source]

Increment the authoring revision counter.

This is called on every map save to provide a lightweight edit history.

bump_version()[source]

Increment the authoring milestone version.

Map versions are stored as strings for flexibility, but must be numeric for auto-increment. If non-numeric, raise a clear error.

get_room(room_id)[source]

Get a room by ID.

Parameters:

room_id (str) – The room ID to look up.

Returns:

The room if found, None otherwise.

Return type:

MapRoom or None

get_room_at_coords(coords)[source]

Find a room at the given coordinates.

Parameters:

coords (Coords) – The coordinates to search for.

Returns:

The room at those coordinates, or None if no room exists there.

Return type:

MapRoom or None

Examples

>>> room = map_file.get_room_at_coords(Coords(x=0, y=0, z=0))
find_room_in_direction(from_coords, direction, exclude_room=None)[source]

Find the nearest room in a given direction from coordinates.

This method searches for rooms that lie in the specified direction from the given coordinates, regardless of distance. It’s used for auto-connecting exits when the target room may not be at the exact adjacent coordinate.

Parameters:
  • from_coords (Coords) – Starting position to search from.

  • direction (Direction) – Direction to search in (north, south, east, west, up, down).

  • exclude_room (str, optional) – Room ID to exclude from search (typically the source room).

Returns:

The nearest room in that direction, or None if no room found.

Return type:

MapRoom or None

Examples

>>> room = map_file.find_room_in_direction(
...     Coords(x=0, y=0, z=0),
...     "north",
...     exclude_room="spawn",
... )
add_room(room_id, name, coords, description='')[source]

Add a new room to the map.

Parameters:
  • room_id (str) – Unique identifier for the room.

  • name (str) – Display name for the room.

  • coords (Coords) – Position in 3D space.

  • description (str, optional) – Room description text.

Returns:

The newly created room.

Return type:

MapRoom

Raises:

ValueError – If a room with that ID already exists.

Examples

>>> room = map_file.add_room(
...     room_id="new_room",
...     name="New Room",
...     coords=Coords(x=5, y=0, z=0),
... )
create_exit(from_room_id, direction, to_room_id, bidirectional=True)[source]

Create an exit between two rooms.

Parameters:
  • from_room_id (str) – Source room ID.

  • direction (Direction) – Direction of the exit.

  • to_room_id (str) – Target room ID.

  • bidirectional (bool, default True) – If True, also create the reverse exit.

Raises:

ValueError – If either room doesn’t exist.

Examples

>>> map_file.create_exit("spawn", "north", "hallway")
# Creates spawn->north->hallway AND hallway->south->spawn
remove_exit(from_room_id, direction, bidirectional=True)[source]

Remove an exit from a room.

Parameters:
  • from_room_id (str) – Source room ID.

  • direction (Direction) – Direction of the exit to remove.

  • bidirectional (bool, default True) – If True, also remove the reverse exit from the target room.

Examples

>>> map_file.remove_exit("spawn", "north")
# Removes spawn->north AND (if exists) target->south->spawn
classmethod from_dict(data)[source]

Create MapFile from a dictionary (legacy format support).

This method handles the legacy format where rooms have coords as lists rather than Coords objects.

Parameters:

data (dict) – Map file data, potentially in legacy format.

Returns:

New MapFile instance.

Return type:

MapFile

Examples

>>> data = {
...     "id": "test",
...     "name": "Test",
...     "spawn_room": "spawn",
...     "rooms": {
...         "spawn": {
...             "id": "spawn",
...             "name": "Spawn",
...             "coords": [0, 0, 0],
...             "exits": {},
...             "items": [],
...         }
...     },
...     "items": {},
... }
>>> map_file = MapFile.from_dict(data)
to_dict_with_list_coords()[source]

Export to dictionary with coords as lists (legacy format).

This method produces output compatible with existing map files. It handles two format conversions:

  1. Coords as lists: Converts {"x": 0, "y": 0, "z": 0} to [0, 0, 0] for backwards compatibility with existing map files.

  2. Datetime as ISO string: Uses mode="json" serialization to convert datetime objects (like llm_generation.generated_at) to ISO 8601 strings. This ensures JSON compatibility when saving map files.

The llm_generation field (if present) contains a generated_at datetime that must be serialized for JSON storage. Using mode="json" handles this automatically, producing strings like "2024-01-15T10:30:00+00:00".

Returns:

Map file data with coords as [x, y, z] lists and datetimes as ISO strings.

Return type:

dict

Examples

>>> data = map_file.to_dict_with_list_coords()
>>> data["rooms"]["spawn"]["coords"]
[0, 0, 0]

With llm_generation metadata:

>>> room_data = data["rooms"]["spawn"]
>>> room_data["llm_generation"]["generated_at"]
'2024-01-15T10:30:00+00:00'