Skip to content

Wilderness System Guide

Overview

The MAID Wilderness System provides on-demand procedural generation of outdoor areas. As players explore, rooms are generated using deterministic noise-based terrain generation, creating consistent, reproducible wilderness landscapes that can expand infinitely within defined boundaries.

Key features: - On-Demand Generation: Rooms created as players explore - Deterministic Terrain: Same coordinates always produce same terrain - Biome System: Multiple biome types with unique characteristics - Landmark Support: Fixed points of interest that anchor procedural terrain - Resource/Encounter Spawning: Procedural content spawning based on biome - Automatic Cleanup: Stale empty rooms cleaned up to manage memory - Player Tracking: Track players across wilderness rooms

Quick Start

from maid_engine.world import WildernessManager, WildernessConfig, Landmark
from maid_engine.core.world import World

# Create wilderness manager
world = World()
config = WildernessConfig(
    seed=42,  # Deterministic seed
    min_x=-1000, max_x=1000,
    min_y=-1000, max_y=1000,
    cleanup_interval=300.0,  # Clean up every 5 minutes
    room_max_age=600.0,  # Rooms stale after 10 minutes empty
)

wilderness = WildernessManager(world=world, config=config)

# Add a town landmark
wilderness.add_landmark(Landmark(
    coord=(0, 0),
    name="Starting Town",
    room_id=town_room_id,
    radius=5,
    biome_override="plains",
))

# Get or create a room at coordinates
room = wilderness.get_or_create_room(100, 200)
print(f"Room: {room.room_id}, Biome: {room.biome}")

# Get spawned content for the room
content = wilderness.get_spawned_content(100, 200)
print(f"Resources: {content.resources}")
print(f"Encounters: {content.encounters}")

# Start cleanup loop
await wilderness.start()

Core Classes

WildernessConfig

Configuration for wilderness generation and management.

from maid_engine.world import WildernessConfig

config = WildernessConfig(
    seed=42,  # Random seed for deterministic generation
    terrain_config=None,  # Custom TerrainConfig (optional)
    min_x=-5000, max_x=5000,  # X boundaries
    min_y=-5000, max_y=5000,  # Y boundaries
    cleanup_interval=300.0,  # Seconds between cleanup runs
    room_max_age=600.0,  # Seconds before stale room cleanup
    default_z=0,  # Z-level for wilderness rooms
)
Field Type Default Description
seed int 0 Random seed for deterministic terrain
terrain_config TerrainConfig \| None None Custom terrain configuration
min_x, max_x int -1000, 1000 X coordinate boundaries
min_y, max_y int -1000, 1000 Y coordinate boundaries
cleanup_interval float 300.0 Seconds between cleanup runs
room_max_age float 600.0 Seconds before stale room cleanup
default_z int 0 Z-level for all wilderness rooms

WildernessManager

The main interface for wilderness generation and management.

from maid_engine.world import WildernessManager, WildernessConfig
from maid_engine.core.world import World

# Create with world reference
world = World()
wilderness = WildernessManager(
    world=world,
    config=WildernessConfig(seed=42),
)

# Or standalone for testing
wilderness = WildernessManager(config=WildernessConfig(seed=42))

GeneratedRoom

Metadata for a procedurally generated room.

from maid_engine.world import GeneratedRoom
from uuid import UUID
import time

room = GeneratedRoom(
    room_id=UUID("..."),
    coord=(100, 200),
    biome="forest",
    created_at=time.time(),
    last_visited=time.time(),
    player_count=0,
)

# Check if room is stale
if room.is_stale(max_age=600.0):
    print("Room can be cleaned up")

Landmark

Fixed points of interest in the wilderness.

from maid_engine.world import Landmark
from uuid import uuid4

# Landmark with pre-existing room
town = Landmark(
    coord=(0, 0),
    name="Starting Town",
    room_id=town_room_id,
    radius=5,  # Influence radius
    biome_override="plains",  # Force biome in radius
)

# Landmark without pre-existing room
dungeon = Landmark(
    coord=(500, 300),
    name="Dragon's Lair",
    room_id=None,  # Will generate room when visited
    radius=3,
    description="A dark cave entrance looms in the mountainside.",
    biome_override="mountain",
    metadata={"dungeon_id": "dragons_lair", "level_range": (15, 20)},
)

Terrain Generation

The wilderness uses noise-based terrain generation to create biomes.

TerrainConfig

from maid_engine.world import TerrainConfig

config = TerrainConfig(
    seed=42,
    scale=100.0,  # Larger = wider terrain features
    octaves=4,  # Detail layers
    persistence=0.5,  # Amplitude decrease per octave
    lacunarity=2.0,  # Frequency increase per octave
    water_level=0.3,  # Below this = water
    mountain_level=0.7,  # Above this = mountains
    moisture_scale=80.0,  # Moisture noise scale
    moisture_octaves=3,  # Moisture detail
    temperature_scale=150.0,  # Temperature noise scale
    base_temperature=0.5,  # 0=arctic, 1=tropical
)

TerrainGenerator

from maid_engine.world import TerrainGenerator, TerrainConfig

generator = TerrainGenerator(TerrainConfig(seed=42))

# Get terrain type at coordinate
terrain = generator.get_terrain(100, 200)  # "forest"

# Get full terrain data
data = generator.get_terrain_data(100, 200)
print(f"Type: {data.terrain_type}")
print(f"Elevation: {data.elevation}")  # 0-1
print(f"Moisture: {data.moisture}")  # 0-1
print(f"Temperature: {data.temperature}")  # 0-1
print(f"Movement Cost: {data.movement_cost}")

# Individual values
elevation = generator.get_elevation(100, 200)
moisture = generator.get_moisture(100, 200)
temperature = generator.get_temperature(100, 200)

Biome Types

The terrain generator produces these biome types:

Biome Movement Cost Conditions
water 3.0 Low elevation (< 0.3)
plains 0.8 Default for moderate elevation
forest 1.0 Moderate moisture (> 0.5)
desert 1.5 Hot (> 0.7) and dry (< 0.3)
tundra 1.5 Cold (< 0.25)
mountain 2.0 High elevation (> 0.7)
swamp 2.0 High moisture near water level
hills 1.3 Elevated terrain with moderate moisture

Biome Definitions

Biomes define room characteristics, resources, and encounters.

BiomeDefinition

from maid_engine.world import BiomeDefinition, ResourceSpawn, EncounterSpawn
from maid_engine.world.procedural import register_biome

custom_biome = BiomeDefinition(
    name="enchanted_forest",
    display_name="Enchanted Forest",
    movement_cost=1.5,
    sector_type="outdoor",
    description_templates=[
        "Ethereal light filters through ancient trees.",
        "Magical energies crackle in the air.",
    ],
    name_templates=["Mystical Grove", "Fey Crossing", "Ancient Woods"],
    resources=[
        ResourceSpawn("fey_dust", spawn_chance=0.2, min_quantity=1, max_quantity=3),
        ResourceSpawn("moonflower", spawn_chance=0.1),
    ],
    encounters=[
        EncounterSpawn("sprite", spawn_chance=0.15, min_level=3, max_level=8),
        EncounterSpawn("treant", spawn_chance=0.05, min_level=10, max_level=15),
    ],
    ambient_sounds=["Bells chime softly in the distance."],
    ambient_messages=["A butterfly made of light dances past."],
)

register_biome(custom_biome)

ResourceSpawn

from maid_engine.world import ResourceSpawn
from random import Random

resource = ResourceSpawn(
    resource_type="iron_ore",
    spawn_chance=0.15,  # 15% chance to spawn
    min_quantity=1,
    max_quantity=3,
)

# Roll for quantity when spawned
rng = Random(42)
quantity = resource.roll_quantity(rng)

EncounterSpawn

from maid_engine.world import EncounterSpawn
from random import Random

encounter = EncounterSpawn(
    encounter_type="wolf",
    spawn_chance=0.20,
    min_level=3,
    max_level=7,
    group_size_min=2,
    group_size_max=5,
)

rng = Random(42)
level = encounter.roll_level(rng)
group_size = encounter.roll_group_size(rng)

Default Biomes

Access default biome definitions:

from maid_engine.world.procedural import (
    get_biome,
    get_all_biome_names,
    DEFAULT_BIOMES,
)

# Get specific biome
forest = get_biome("forest")
print(f"Movement cost: {forest.movement_cost}")

# List all biomes
names = get_all_biome_names()  # ['desert', 'forest', 'hills', ...]

# Access default definitions
plains = DEFAULT_BIOMES["plains"]

Room Generation

On-Demand Generation

# Get existing room or generate new one
room = wilderness.get_or_create_room(100, 200)

# Check if room exists
if wilderness.is_generated(100, 200):
    room = wilderness.get_generated_room(100, 200)

# Get biome without generating room
biome = wilderness.get_biome(100, 200)  # "forest"

# Preview terrain without generating
info = wilderness.preview_terrain(100, 200)
print(f"Biome: {info['biome']}")
print(f"Elevation: {info['elevation']:.2f}")
print(f"Movement Cost: {info['movement_cost']}")
print(f"In Bounds: {info['in_bounds']}")

Spawned Content

# Get spawned content for a room
content = wilderness.get_spawned_content(100, 200)
if content:
    print(f"Room Name: {content.room_name}")
    print(f"Description: {content.room_description}")
    print(f"Resources: {content.resources}")  # ['wood', 'mushroom']
    print(f"Encounters: {content.encounters}")  # ['deer']

Custom Room Factory

def my_room_factory(x, y, biome_name, biome_def, rng):
    """Create actual room entity in the world."""
    room = world.create_entity()
    room.add(RoomComponent(
        name=biome_def.generate_name(rng),
        description=biome_def.generate_description(rng),
    ))
    room.add(PositionComponent(x=x, y=y))
    return room.id

wilderness = WildernessManager(
    world=world,
    config=config,
    room_factory=my_room_factory,
)

Landmark Management

Adding Landmarks

from maid_engine.world import Landmark

# Add a landmark
wilderness.add_landmark(Landmark(
    coord=(0, 0),
    name="Starting Town",
    room_id=town_id,
    radius=5,
))

# Add landmark with biome override
wilderness.add_landmark(Landmark(
    coord=(100, 100),
    name="Oasis",
    radius=10,
    biome_override="plains",  # Force plains in desert area
))

Querying Landmarks

# Get landmark at exact coordinate
landmark = wilderness.get_landmark(0, 0)

# Get landmark influencing coordinate (checks radius)
landmark = wilderness.get_landmark_at(3, 3)  # Within Starting Town radius

# Get all landmarks
landmarks = wilderness.get_all_landmarks()

# Find landmarks in range
nearby = wilderness.get_landmarks_in_range(50, 50, radius=100)
nearby = wilderness.landmarks_in_radius(50, 50, radius=100.0)

# Remove landmark
removed = wilderness.remove_landmark(0, 0)

Player Tracking

Tracking Player Movement

# Track player entering room
wilderness.player_entered(room_id, player_id)

# Track player leaving room
wilderness.player_left(room_id, player_id)

# Alternative: update by coordinates
wilderness.increment_player_count(100, 200)
wilderness.decrement_player_count(100, 200)

# Update last visited timestamp
wilderness.update_last_visited(100, 200)

Querying Player Locations

# Get players in a room
players = wilderness.get_players_in_room(room_id)

# Get room where player is located
room_id = wilderness.get_player_room(player_id)

# Get all occupied rooms
occupied = wilderness.get_occupied_rooms()
for room in occupied:
    print(f"{room.coord}: {room.player_count} players")

Cleanup System

Automatic Cleanup

# Start the cleanup loop
await wilderness.start()

# ... game runs ...

# Stop the cleanup loop
await wilderness.stop()

# Check if running
if wilderness.is_running:
    print("Cleanup loop active")

Manual Cleanup

# Get stale rooms
stale = wilderness.get_stale_rooms()

# Manual cleanup
removed = wilderness.cleanup_stale_rooms_sync()
print(f"Removed {removed} rooms")

# Clear all generated rooms
wilderness.clear()

Cleanup Configuration

Config Default Description
cleanup_interval 300.0 Seconds between automatic cleanup
room_max_age 600.0 Seconds before empty room is stale

Set cleanup_interval=0 to disable automatic cleanup.

Statistics and Debugging

stats = wilderness.get_stats()
print(f"Generated Rooms: {stats['total_generated']}")
print(f"Landmarks: {stats['total_landmarks']}")
print(f"Stale Rooms: {stats['stale_count']}")
print(f"Players in Wilderness: {stats['player_count']}")
print(f"Biome Distribution: {stats['biome_counts']}")
print(f"Bounds: {stats['bounds']}")

Boundary Handling

# Check if coordinate is in bounds
if wilderness.is_in_bounds(500, 500):
    room = wilderness.get_or_create_room(500, 500)
else:
    print("Outside wilderness boundaries")

# Get boundary message for movement
msg = wilderness.get_edge_description(1000, 500, "east")
if msg:
    print(msg)  # "You cannot travel further east..."

Serialization

Export State

import json

state = wilderness.export_state()
with open("wilderness.json", "w") as f:
    json.dump(state, f)

Import State

with open("wilderness.json", "r") as f:
    state = json.load(f)

wilderness.import_state(state)

The export includes: - Configuration settings - All generated rooms - All landmarks - Spawned content - Last cleanup timestamp

Builder Commands

MAID provides in-game commands for wilderness management (BUILDER access level):

@wilderness info                        - Show wilderness statistics
@wilderness biome <x> <y>               - Show biome at coordinate
@wilderness preview <x> <y>             - Preview terrain at coordinate
@wilderness landmark add <name> <x> <y> [radius]  - Add landmark
@wilderness landmark remove <x> <y>     - Remove landmark
@wilderness landmark list               - List all landmarks
@wilderness cleanup                     - Manually trigger cleanup
@wilderness generate <x> <y>            - Force generate room
@wilderness stats                       - Detailed statistics

Integration with Content Packs

Content packs can extend the wilderness system:

from maid_engine.plugins.protocol import ContentPack
from maid_engine.world import WildernessManager, BiomeDefinition
from maid_engine.world.procedural import register_biome

class MyContentPack(ContentPack):
    async def on_load(self, engine):
        # Register custom biomes
        register_biome(BiomeDefinition(
            name="haunted_forest",
            display_name="Haunted Forest",
            movement_cost=2.0,
            # ...
        ))

        # Configure wilderness
        wilderness = engine.world.wilderness
        wilderness.add_landmark(Landmark(
            coord=(0, 0),
            name="Starting Area",
            radius=10,
        ))

Example: Creating a Wilderness Zone

from maid_engine.world import (
    WildernessManager,
    WildernessConfig,
    TerrainConfig,
    Landmark,
)

# Configure terrain for a temperate climate
terrain_config = TerrainConfig(
    seed=12345,
    scale=150.0,  # Larger features
    water_level=0.25,  # Less water
    mountain_level=0.75,  # Higher mountains
    base_temperature=0.6,  # Slightly warm
)

# Configure wilderness
config = WildernessConfig(
    seed=12345,
    terrain_config=terrain_config,
    min_x=-500, max_x=500,
    min_y=-500, max_y=500,
    cleanup_interval=120.0,  # Aggressive cleanup
    room_max_age=300.0,
)

wilderness = WildernessManager(world=world, config=config)

# Add key locations
wilderness.add_landmark(Landmark(
    coord=(0, 0),
    name="Central Town",
    room_id=town_id,
    radius=8,
    biome_override="plains",
))

wilderness.add_landmark(Landmark(
    coord=(200, 150),
    name="Ancient Ruins",
    radius=5,
    description="Crumbling stone pillars mark the entrance to forgotten ruins.",
    metadata={"dungeon_id": "ancient_ruins"},
))

wilderness.add_landmark(Landmark(
    coord=(-100, 300),
    name="Hermit's Hut",
    radius=2,
    description="A small wooden hut sits alone in the wilderness.",
))

# Start the wilderness system
await wilderness.start()