Add pluggable parser system, perception loop, and project infrastructure

Phase 0 (housekeeping):
- Add .gitignore to protect credentials and runtime files
- Track all project source code, docs, and config

Phase 1 (perception loop):
- Implement pluggable parser architecture (BaseMudParser ABC + ParserFactory)
- Add DeadSoulsParser with regex for HP/MP/SP prompt, room descriptions,
  exits (multiple formats), NPC/item detection, and combat events
- Add OutputBuffer for accumulating text between prompts
- Update GameState with SP support and update_from_prompt/room/combat methods
- Rewire main loop to use parser + buffer for real-time game state updates
- Add reconnection logic to TelnetClient (retry with backoff)
- Remove old TextParser (replaced by pluggable system)
- Add mud_type config field for selecting parser at runtime
- Add comprehensive test suite (50 tests, all passing)
This commit is contained in:
truetype committed 2026-02-08 19:08:59 +01:00
1 parent 0f370ec089
commit f85c27a742
42 files changed
+3490 -134

No files matched your search

+95
View File
@@ -0,0 +1,95 @@
"""Configuration loading and validation"""
import yaml
from pydantic import BaseModel, Field
from typing import List, Optional
class MudConfig(BaseModel):
"""MUD server configuration"""
host: str
port: int
mud_type: str = "dead_souls"
username: str = ""
password: str = ""
keep_alive_interval: int = 60
keep_alive_command: str = ""
class CharacterConfig(BaseModel):
"""Character preferences"""
name: str = "AIPlayer"
preferred_class: str = "warrior"
preferred_race: str = "human"
play_style: str = "balanced"
class AIConfig(BaseModel):
"""AI engine configuration"""
engine: str = "rule_based"
llm_model: str = "llama3.2"
decision_delay_ms: List[int] = Field(default=[200, 2000])
exploration_strategy: str = "depth_first"
class MapperConfig(BaseModel):
"""Mapper configuration"""
class ActiveStorageConfig(BaseModel):
db_path: str = "data/maps/active/world.db"
graph_cache_size: int = 10000
class HistoricalStorageConfig(BaseModel):
archive_dir: str = "data/maps/archive"
class SnapshotTriggers(BaseModel):
room_count: int = 500
session_end: bool = True
time_interval_hours: int = 24
snapshot_triggers: SnapshotTriggers = Field(default_factory=SnapshotTriggers)
active_storage: ActiveStorageConfig = Field(default_factory=ActiveStorageConfig)
historical_storage: HistoricalStorageConfig = Field(default_factory=HistoricalStorageConfig)
class BehaviorConfig(BaseModel):
"""Behavior simulation configuration"""
reaction_time_min_ms: int = 200
reaction_time_max_ms: int = 2000
pause_probability: float = 0.05
typo_probability: float = 0.0
class LoggingConfig(BaseModel):
"""Logging configuration"""
level: str = "INFO"
file: str = "data/logs/game.log"
console: bool = True
max_file_size_mb: int = 10
backup_count: int = 5
class Config(BaseModel):
"""Main configuration"""
mud: MudConfig
character: CharacterConfig = Field(default_factory=CharacterConfig)
ai: AIConfig = Field(default_factory=AIConfig)
mapper: MapperConfig = Field(default_factory=MapperConfig)
behavior: BehaviorConfig = Field(default_factory=BehaviorConfig)
logging: LoggingConfig = Field(default_factory=LoggingConfig)
def load_config(config_path: str = "config.yaml") -> Config:
"""
Load configuration from YAML file
Args:
config_path: Path to config file
Returns:
Validated Config object
"""
with open(config_path, 'r') as f:
config_dict = yaml.safe_load(f)
return Config(**config_dict)