Examples
Demo applications showcasing the MUD server’s REST API.
ASCII Movement Demo
A minimal browser-based client demonstrating keyboard-controlled movement through the game world. Features a retro terminal aesthetic with green-on-black styling.
The demo displays an ASCII map like this:
+----------+
| FOREST |
+----+-----+
|
+--------+ | +----------+
| LAKE |----+--------+----| MOUNTAIN |
+--------+ | SPAWN | +----------+
+---+----+
|
+---+----+
| DESERT |
+--------+
Features
ASCII Map: Visual representation of 5 rooms in a cross pattern
Keyboard Controls: WASD or Arrow keys for movement
Visual Feedback: Current room highlighted in yellow, movement keys light up
Room Descriptions: Updates dynamically as you move
Login/Logout: Full authentication flow via REST API
World Layout
The demo uses the default world with spawn at the center:
[FOREST]
|
[LAKE] -- [SPAWN] -- [MOUNTAIN]
|
[DESERT]
Each room has one exit back to spawn, and spawn has exits to all four cardinal directions.
Running the Demo
Step 1: Start the MUD server
mud-server run
Step 2: Configure CORS (if needed)
The demo requires its origin to be allowed by the server. Add http://localhost:8080
to your config/server.ini:
[security]
cors_origins = http://localhost:8000, http://localhost:8080
Step 3: Serve the demo
# From the project root
python -m http.server 8080 -d examples
Step 4: Open in browser
Navigate to http://localhost:8080/ascii_demo.html
Step 5: Login and play
Enter your username and password, then use WASD or arrow keys to move!
API Endpoints Used
The demo uses these REST API endpoints:
Method |
Endpoint |
Purpose |
|---|---|---|
POST |
|
Authenticate and receive session ID |
POST |
|
End the session |
GET |
|
Get current room, inventory, active players |
POST |
|
Send movement commands (north, south, east, west) |
Request/Response Examples
Login:
// Request
POST /login
{ "username": "player1", "password": "secret123" }
// Response
{ "success": true, "session_id": "uuid-here", "message": "Welcome..." }
Movement:
// Request
POST /command
{ "session_id": "uuid-here", "command": "north" }
// Response
{ "success": true, "message": "You move north.\n=== Enchanted Forest ===" }
Status:
// Request
GET /status/uuid-here
// Response
{
"current_room": "forest",
"inventory": "Your inventory is empty.",
"active_players": ["player1"]
}
Code Structure
The demo is a single self-contained HTML file with embedded CSS and JavaScript:
examples/ascii_demo.html
├── <style> - Retro terminal CSS styling
├── Login Section - Username/password form
├── Game Section - Map, description, controls
└── <script> - API client and game logic
├── State - sessionId, currentRoom, username
├── ROOMS - Static room data (name, description)
├── apiCall() - Generic fetch wrapper
├── login() - POST /login handler
├── logout() - POST /logout handler
├── updateStatus()- GET /status handler
├── move() - POST /command handler
├── renderMap() - ASCII map generation
└── keydown - Keyboard event listener
Extending the Demo
The demo is intentionally minimal. Here are some ideas for extending it:
Add inventory display: Show items from the
/statusresponseAdd chat: Implement
saycommand and poll for room messagesAdd player list: Show other players from
active_playersAdd sound effects: Play sounds on movement success/failure
Mobile support: Add touch controls for mobile devices
WebSocket upgrade: Replace polling with real-time updates
Event Bus Integration
While the demo client doesn’t interact with the event bus directly, the server emits events for every movement command. This enables future plugin systems to react to player actions.
When you move in the demo, the server’s GameEngine.move() method emits events:
Successful Movement:
# Server-side (engine.py)
bus.emit(Events.PLAYER_MOVED, {
"username": "player1",
"from_room": "spawn",
"to_room": "forest",
"direction": "north"
})
Failed Movement (no exit in that direction):
bus.emit(Events.PLAYER_MOVE_FAILED, {
"username": "player1",
"room": "spawn",
"direction": "west",
"reason": "No exit west"
})
These events are recorded in the bus’s event log with:
Sequence number: Monotonic counter for deterministic ordering
Timestamp: When the event occurred
Source: Which system emitted it (e.g., “engine”)
Why This Matters:
Future plugins can subscribe to these events to add behavior:
from mud_server.core.bus import bus
from mud_server.core.events import Events
# Weather plugin reacting to movement
def on_player_moved(event):
if event.detail["to_room"] == "mountain":
# Trigger weather effects
pass
bus.on(Events.PLAYER_MOVED, on_player_moved)
The event bus follows the principle: “Plugins react, don’t intervene.” Events record facts about what happened (Ledger truth), and plugins respond to those facts without blocking or modifying the original action.
See Architecture for more details on the event bus design.
CORS Troubleshooting
If you see “Connection failed” or CORS errors in the browser console:
Check the server output - Look for
OPTIONS /login 400 Bad RequestVerify cors_origins - Ensure your origin is in the list
Restart the server - Config changes require a restart
Check the origin -
file://origins show asnull
For development, serve the file via HTTP rather than opening directly:
# Good - origin is http://localhost:8080
python -m http.server 8080 -d examples
# Problematic - origin is null
open examples/ascii_demo.html