71 lines
1.8 KiB
Python
71 lines
1.8 KiB
Python
"""Command registry and dispatcher."""
|
|
|
|
from collections.abc import Awaitable, Callable
|
|
from dataclasses import dataclass, field
|
|
|
|
from mudlib.player import Player
|
|
|
|
# Type alias for command handlers
|
|
CommandHandler = Callable[[Player, str], Awaitable[None]]
|
|
|
|
|
|
@dataclass
|
|
class CommandDefinition:
|
|
"""Metadata wrapper for a registered command."""
|
|
|
|
name: str
|
|
handler: CommandHandler
|
|
aliases: list[str] = field(default_factory=list)
|
|
mode: str = "normal"
|
|
help: str = ""
|
|
hidden: bool = False
|
|
|
|
|
|
# Registry maps command names to definitions
|
|
_registry: dict[str, CommandDefinition] = {}
|
|
|
|
|
|
def register(defn: CommandDefinition) -> None:
|
|
"""Register a command definition with its aliases.
|
|
|
|
Args:
|
|
defn: The command definition to register
|
|
"""
|
|
_registry[defn.name] = defn
|
|
for alias in defn.aliases:
|
|
_registry[alias] = defn
|
|
|
|
|
|
async def dispatch(player: Player, raw_input: str) -> None:
|
|
"""Parse input, find command, call handler.
|
|
|
|
Args:
|
|
player: The player executing the command
|
|
raw_input: The raw input string from the player
|
|
"""
|
|
raw_input = raw_input.strip()
|
|
|
|
if not raw_input:
|
|
return
|
|
|
|
# Split into command and arguments
|
|
parts = raw_input.split(maxsplit=1)
|
|
command = parts[0].lower()
|
|
args = parts[1] if len(parts) > 1 else ""
|
|
|
|
# Look up the definition
|
|
defn = _registry.get(command)
|
|
|
|
if defn is None:
|
|
player.writer.write(f"Unknown command: {command}\r\n")
|
|
await player.writer.drain()
|
|
return
|
|
|
|
# Check mode restriction
|
|
if defn.mode != "*" and defn.mode != player.mode:
|
|
player.writer.write("You can't do that right now.\r\n")
|
|
await player.writer.drain()
|
|
return
|
|
|
|
# Execute the handler
|
|
await defn.handler(player, args)
|