mud_server.core.engine

Main game engine with game logic.

This module contains the GameEngine class which implements all core game mechanics and business logic for the MUD server. It acts as the interface between the API routes and the underlying world/database systems.

The engine handles: - Player authentication and sessions - Movement between rooms - Inventory management (pickup/drop items) - Chat systems (say, yell, whisper) - Room observation and interaction - Player presence and status

Design Pattern:

The GameEngine uses the Facade pattern, providing a simplified interface to the complex subsystems (World, Database). API routes call engine methods which coordinate between the world data and database operations.

Architecture:

API Routes → GameEngine → World + Database

  • Routes validate sessions and call engine methods

  • Engine implements game logic and coordinates subsystems

  • World provides static game data (rooms, items)

  • Database provides persistent player state

Attributes

logger

Classes

GameEngine

Main game engine managing all game logic and mechanics.

Functions

sanitize_chat_message(message)

Sanitize a chat message to prevent XSS attacks.

Module Contents

mud_server.core.engine.logger
mud_server.core.engine.sanitize_chat_message(message)[source]

Sanitize a chat message to prevent XSS attacks.

Escapes HTML special characters to prevent injection of malicious scripts through chat messages. This is critical for security when messages are displayed in web interfaces.

Parameters:

message (str) – Raw message text from user input

Returns:

Sanitized message with HTML entities escaped

Return type:

str

Example

>>> sanitize_chat_message("Hello <script>alert('xss')</script>")
"Hello &lt;script&gt;alert('xss')&lt;/script&gt;"
class mud_server.core.engine.GameEngine[source]

Main game engine managing all game logic and mechanics.

This class is instantiated once at server startup and handles all game operations. It coordinates between the World (static game data) and the Database (dynamic player state) to implement game mechanics.

world_registry

WorldRegistry instance for loading worlds on demand

Responsibilities:
  • Player login/logout with authentication

  • Movement validation and execution

  • Inventory operations (pickup, drop, view)

  • Chat message handling (say, yell, whisper)

  • Room descriptions and observation

  • Player status and presence queries

Design Notes:
  • All methods return (success: bool, message: str) tuples for API responses

  • Database operations are called directly (no repository pattern)

  • Broadcasting to other players is stubbed (not yet implemented)

  • All game state is persisted to database immediately

Initialize the game engine.

Loads the world data from JSON and initializes the database schema. This is called once when the server starts.

Side Effects:
  • Loads world_data.json into memory

  • Creates database tables if they don’t exist

  • Creates default superuser if no players exist

world_registry
login(username, password, session_id, client_type='unknown')[source]

Handle account login with authentication and session creation.

This method validates the account and creates a session, but does not select a character. Character selection happens separately.

logout(username)[source]

Handle player logout by removing their session.

Removes the player’s sessions from the database, effectively logging them out on all devices.

Parameters:

username (str) – Username of the player logging out

Returns:

True if session removed successfully, False otherwise

Return type:

bool

Side Effects:
  • Removes session record from database sessions table

  • Player will no longer appear in active players list

Note

This removes all sessions for the user. If you want to remove a single session (multi-device support), use database.remove_session_by_id().

move(username, direction, *, world_id)[source]

Handle player movement between rooms.

Validates the move, updates player location in database, and generates appropriate response messages. Also broadcasts movement notifications to other players in the affected rooms (currently stubbed).

Movement Process: 1. Get player’s current room from database 2. Check if move is valid (exit exists, destination valid) 3. Update player’s room in database 4. Emit PLAYER_MOVED event (the move is now a fact) 5. Generate room description for new location 6. Broadcast departure message to old room 7. Broadcast arrival message to new room

Parameters:
  • username (str) – Player attempting to move

  • direction (str) – Direction to move (“north”, “south”, “east”, “west”)

Returns:

Tuple of (success, message) - success: True if move succeeded, False otherwise - message: New room description OR error message

Return type:

tuple[bool, str]

Failure Cases:
  • Player not in a valid room

  • No exit in that direction

  • Database update failed

Events Emitted:
  • PLAYER_MOVED: When movement succeeds

  • PLAYER_MOVE_FAILED: When movement fails

Example

>>> engine.move("player1", "north")
(True, "You move north.\n=== Enchanted Forest ===...")
>>> engine.move("player1", "west")
(False, "You cannot move west from here.")
recall(username, *, world_id)[source]

Recall player to their current zone’s spawn point.

This is the “hearthstone” equivalent - a way for players to return to a known safe location. The destination is the spawn_room defined in the player’s current zone.

If the player is not in a known zone, they are sent to the world’s default spawn point instead.

Parameters:

username (str) – Player recalling

Returns:

Tuple of (success, message) - success: True if recall succeeded - message: Description of new location

Return type:

tuple[bool, str]

Side Effects:
  • Updates player’s current_room in database

  • Broadcasts departure/arrival messages (when implemented)

chat(username, message, *, world_id)[source]

Handle player chat messages within their current room.

Sends a chat message to all players in the same room. The message is stored in the database and can be retrieved by other players in the room.

Parameters:
  • username (str) – Player sending the message

  • message (str) – Chat message text

Returns:

Tuple of (success, message) - success: True if message sent, False otherwise - message: Confirmation message OR error message

Return type:

tuple[bool, str]

Failure Cases:
  • Player not in a valid room

  • Database insert failed

Side Effects:
  • Adds message to chat_messages table with room association

  • Message will appear in other players’ chat history

Example

>>> engine.chat("player1", "Hello everyone!")
(True, "You say: Hello everyone!")
Security Note:

Messages are sanitized to prevent XSS attacks before storage.

yell(username, message, *, world_id)[source]

Yell a message to current room and all adjoining rooms.

Unlike regular chat which only reaches the current room, yell sends the message to: 1. The player’s current room 2. All rooms directly connected via exits

The message is prefixed with [YELL] to distinguish it from normal chat.

Parameters:
  • username (str) – Player yelling the message

  • message (str) – Message text to yell

Returns:

Tuple of (success, message) - success: True if yell sent, False otherwise - message: Confirmation message OR error message

Return type:

tuple[bool, str]

Failure Cases:
  • Player not in a valid room

  • Room data invalid

  • Database insert failed

Side Effects:
  • Adds [YELL] message to current room’s chat

  • Adds [YELL] message to all adjoining rooms’ chat

  • Players in multiple affected rooms will see the message

Example

If player in “spawn” with exits to “forest” and “desert”: >>> engine.yell(“player1”, “Can anyone hear me?”) (True, “You yell: Can anyone hear me?”) # Message appears in spawn, forest, and desert rooms

Security Note:

Messages are sanitized to prevent XSS attacks before storage.

whisper(username, target, message, *, world_id)[source]

Send a private whisper to a specific player in the same room.

Whispers are private messages that only the sender and recipient can see. They are filtered by recipient when retrieving room chat messages.

Validation Checks: 1. Sender must be in a valid room 2. Target player must exist in database 3. Target must be online (have an active session) 4. Target must be in the same room as sender

The message is prefixed with [WHISPER: sender → target] to clearly indicate it’s a private message and show the direction.

Parameters:
  • username (str) – Character sending the whisper

  • target (str) – Character name to whisper to (case-sensitive)

  • message (str) – Private message text

Returns:

Tuple of (success, message) - success: True if whisper sent, False otherwise - message: Confirmation message OR error message explaining failure

Return type:

tuple[bool, str]

Failure Cases:
  • Sender not in a valid room

  • Target player doesn’t exist

  • Target player is not online

  • Target player is in a different room

  • Database insert failed

Side Effects:
  • Adds message to chat_messages with recipient field set

  • Only sender and target can see this message in their chat

  • Extensive logging for debugging whisper issues

Security Note:

Character names are case-sensitive. Command parser preserves case for arguments to ensure exact identity targeting.

Example

>>> engine.whisper("player1", "Admin", "Help me please")
(True, "You whisper to Admin: Help me please")
# Only player1 and Admin see: [WHISPER: player1 → Admin] Help me please
>>> engine.whisper("player1", "Player2", "Hi")
(False, "Player 'Player2' is not in this room.")
kick_character(actor_name, target, *, world_id)[source]

Disconnect all active sessions for a target character.

This is a moderation primitive used by admin/superuser command flows. Permission checks are intentionally handled at the API route layer so this method focuses on deterministic target resolution + session revoke.

Resolution behavior: 1. Resolve target as a character name in the current world. 2. Remove all sessions for the resolved character id.

Parameters:
  • actor_name (str) – Character issuing the kick command.

  • target (str) – Character name to disconnect.

  • world_id (str) – Active world context for resolution.

Returns:

Tuple of (success, message) suitable for command responses.

Return type:

tuple[bool, str]

get_room_chat(username, limit=20, *, world_id)[source]

Get recent chat messages from the player’s current room.

Retrieves and formats chat messages, including regular chat, yells, and whispers. Whispers are filtered so each player only sees: - Public messages (no recipient) - Whispers sent by them - Whispers sent to them

Args:

username: Player requesting chat history limit: Maximum number of messages to retrieve (default 20)

Returns:

Formatted string with recent messages Format: “[Recent messages]:

username: message …”

Returns “[No messages in this room yet]” if empty Returns “No messages.” if player not in valid room

Example:
>>> engine.get_room_chat("player1", limit=5)
'''[Recent messages]:
player2: Hello!
player1: [WHISPER: player1 → player2] Hi there
player3: [YELL] Can anyone help?
'''
get_inventory(username, *, world_id)[source]

Get formatted player inventory listing.

Retrieves the player’s inventory from the database and formats it as a readable list with item names.

Args:

username: Player whose inventory to retrieve

Returns:

Formatted inventory string - “Your inventory:

  • Item1

  • Item2…” if items present
    • “Your inventory is empty.” if no items

    Example:
    >>> engine.get_inventory("player1")
    "Your inventory:
    
  • Torch

  • Rope

>>> engine.get_inventory("new_player")
"Your inventory is empty."
pickup_item(username, item_name, *, world_id)[source]

Pick up an item from the current room and add to inventory.

Searches for an item with matching name (case-insensitive) in the current room. If found, adds it to the player’s inventory.

Design Note:

Items are NOT removed from the room when picked up. This allows multiple players to pick up the same item. This is intentional for the current proof-of-concept design.

Parameters:
  • username (str) – Player picking up the item

  • item_name (str) – Name of item to pick up (case-insensitive match)

Returns:

Tuple of (success, message) - success: True if item picked up, False otherwise - message: Success confirmation OR error message

Return type:

tuple[bool, str]

Failure Cases:
  • Player not in a valid room

  • Room doesn’t exist in world data

  • No item with that name in the room

Example

>>> engine.pickup_item("player1", "torch")
(True, "You picked up the Torch.")
>>> engine.pickup_item("player1", "sword")
(False, "There is no 'sword' here.")
drop_item(username, item_name, *, world_id)[source]

Drop an item from player’s inventory.

Searches inventory for an item with matching name (case-insensitive) and removes it from the player’s inventory.

Design Note:

Dropped items are NOT added back to the room. They simply disappear from the player’s inventory. This is intentional for the current proof-of-concept design.

Parameters:
  • username (str) – Player dropping the item

  • item_name (str) – Name of item to drop (case-insensitive match)

Returns:

Tuple of (success, message) - success: True if item dropped, False otherwise - message: Success confirmation OR error message

Return type:

tuple[bool, str]

Failure Cases:
  • Player doesn’t have an item with that name

Example

>>> engine.drop_item("player1", "torch")
(True, "You dropped the Torch.")
>>> engine.drop_item("player1", "sword")
(False, "You don't have a 'sword'.")
look(username, *, world_id)[source]

Look around the current room to get a full description.

Generates a detailed description of the player’s current room including room name, description, items, other players, and available exits.

Parameters:

username (str) – Player looking around

Returns:

Formatted room description string Returns “You are not in a valid room.” if player location invalid

Return type:

str

Example

>>> engine.look("player1")
'''
=== Spawn Zone ===
You stand in a peaceful plaza...
[Items here]:
  • Torch

  • Rope

[Players here]:
  • player2

[Exits]:
  • north: Enchanted Forest

  • south: Golden Desert

‘’’

get_active_players(*, world_id)[source]

Get list of all currently active (logged in) characters.

Queries the database sessions table to get all characters with active sessions. These are characters currently logged into the server.

Returns:

List of character names for all active players

Return type:

list[str]

Example

>>> engine.get_active_players(world_id="pipeworks_web")
['player1', 'Admin', 'Mendit']