- Add comprehensive configuration guide (docs/configuration.md) - Add development guide with setup instructions (docs/development.md) - Add complete API reference documentation (docs/api_reference.md) - Update README.md with new features and project structure - Update TODO.md to reflect current implementation status - Add web monitoring dashboard with FastAPI and WebSocket support - Add tests for sync integration and web monitoring - Update config example with monitoring settings The MUD AI Player is now feature-complete with full documentation.
7.8 KiB
Development Guide
This guide is for developers who want to contribute to or extend the MUD AI Player.
Development Setup
Prerequisites
- Python 3.10+
- Poetry (recommended) or pip
- Git
Installation
Using Poetry (Recommended):
# Install Poetry if not already installed
pip install poetry
# Clone the repository
git clone <repository-url>
cd mud-ai-player
# Install dependencies
poetry install
# Activate virtual environment
poetry shell
Using pip:
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
Project Structure
mud-ai-player/
├── src/ # Source code
│ ├── core/ # Core components
│ │ ├── telnet_client.py # Async telnet connection
│ │ ├── game_state.py # Game state management
│ │ ├── ansi_parser.py # ANSI color code parsing
│ │ └── parsers/ # MUD-specific parsers
│ ├── modules/ # Feature modules
│ │ ├── mapper/ # World mapping (SQLite + Memvid)
│ │ ├── decision/ # AI decision engine
│ │ ├── llm/ # LLM integration
│ │ ├── character/ # Character creation
│ │ ├── quest/ # Quest management
│ │ ├── progression/ # Grinding optimizer
│ │ └── web/ # Monitoring dashboard
│ ├── config/ # Configuration management
│ └── utils/ # Utilities
├── tests/ # Test suite
├── docs/ # Documentation
├── data/ # Persistent storage
└── examples/ # Example configurations
Adding a New Module
To add a new feature module:
- Create a directory under
src/modules/your_module/ - Create
__init__.pyand your module files - Export the main class from
__init__.py - Add tests in
tests/test_your_module.py - Update documentation
Example structure:
# src/modules/your_module/__init__.py
from .your_class import YourClass
__all__ = ["YourClass"]
# src/modules/your_module/your_class.py
class YourClass:
def __init__(self):
pass
def do_something(self):
pass
Adding a New Parser
To add support for a new MUD type:
- Create a new parser in
src/core/parsers/your_mud.py - Inherit from
BaseParser - Register in
ParserFactory
# src/core/parsers/your_mud.py
from .base import BaseParser, ParsedRoom, ParsedPrompt
class YourMudParser(BaseParser):
def parse_room(self, text: str) -> Optional[ParsedRoom]:
# Implement room parsing
pass
def parse_prompt(self, text: str) -> Optional[ParsedPrompt]:
# Implement prompt parsing
pass
Then register in factory.py:
from .your_mud import YourMudParser
PARSERS = {
"dead_souls": DeadSoulsParser,
"your_mud": YourMudParser, # Add this
}
Running Tests
# Run all tests
pytest tests/ -v
# Run with coverage
pytest --cov=src --cov-report=html
# Run specific test file
pytest tests/test_world_mapper.py -v
# Run with watch mode
pytest-watch
Code Style
We use Black and Ruff for code formatting and linting:
# Format code
black src/ tests/
# Lint code
ruff check src/ tests/
# Auto-fix linting issues
ruff check --fix src/ tests/
Style Guidelines
- Line length: 100 characters
- Use type hints where possible
- Write docstrings for public methods
- Follow PEP 8 naming conventions
Testing Guidelines
Unit Tests
Test individual components in isolation:
# tests/test_your_module.py
def test_room_parsing():
parser = YourMudParser()
room = parser.parse_room("Room Title\nDescription\n[Exits: n s]")
assert room.title == "Room Title"
assert "n" in room.exits
Integration Tests
Test component interactions:
@pytest.mark.asyncio
async def test_full_exploration():
# Setup
mapper = WorldMapper()
engine = DecisionEngine()
# Execute
await engine.tick(game_state)
action = engine.next_action()
# Assert
assert action is not None
Mocking
Use mocks to isolate tests:
from unittest.mock import Mock, patch
def test_with_mock():
mock_client = Mock()
mock_client.send.return_value = None
with patch('src.core.telnet_client.TelnetClient', return_value=mock_client):
# Test code here
pass
Debugging
Logging
The application uses Python's standard logging module:
import logging
logger = logging.getLogger(__name__)
# In your code
logger.debug("Detailed debug info")
logger.info("General information")
logger.warning("Warning message")
logger.error("Error message")
View logs in real-time:
tail -f data/logs/game.log
Debug Mode
Set logging level to DEBUG in config:
logging:
level: "DEBUG"
Web Dashboard
The monitoring dashboard provides real-time debugging:
monitoring:
enabled: true
host: "127.0.0.1"
port: 8080
Then open http://127.0.0.1:8080 in your browser.
Performance Profiling
# Profile the application
python -m cProfile -o profile.stats -m src.main
# View profile results
python -c "import pstats; p = pstats.Stats('profile.stats'); p.sort_stats('cumulative'); p.print_stats(20)"
Git Workflow
- Create a feature branch:
git checkout -b feature/my-feature - Make your changes
- Run tests:
pytest tests/ -v - Format code:
black src/ tests/ - Lint:
ruff check src/ tests/ - Commit:
git commit -m "Add my feature" - Push:
git push origin feature/my-feature - Create Pull Request
Commit Message Guidelines
Use conventional commits format:
feat: Add new featurefix: Fix bug in parserdocs: Update documentationtest: Add testsrefactor: Refactor modulechore: Update dependencies
Common Development Tasks
Adding a New Behavior State
# src/modules/decision/behavior_states.py
class MyCustomState(BaseBehaviorState):
@property
def name(self) -> str:
return "my_state"
def get_actions(self, game_state: GameState) -> List[Action]:
actions = []
# Your logic here
return actions
Then register in DecisionEngine:
self._states = {
# ... existing states
"my_state": MyCustomState(),
}
Extending the Mapper
To add custom room metadata:
# In world_mapper.py
def on_room_enter(self, title, description, exits, **kwargs):
room_data = {
# ... existing fields
"custom_field": kwargs.get("custom_field"),
}
# ... rest of method
Troubleshooting
Import Errors
If you get import errors, ensure you're in the virtual environment:
poetry shell
# or
source venv/bin/activate
Telnet Connection Issues
Test connection manually:
telnet your-mud-server.com 4000
Database Locked
If SQLite reports "database is locked":
# Kill any hanging Python processes
pkill -f "python -m src.main"
# Remove lock file if it exists
rm data/maps/active/*.db-journal
Contributing
- Check existing issues before creating new ones
- Discuss major changes in an issue first
- Write tests for new features
- Update documentation
- Follow code style guidelines
- Be respectful in communications