command system ============== commands are registered as CommandDefinition objects with metadata. from mudlib.commands import CommandDefinition, register async def my_command(player: Player, args: str) -> None: player.writer.write("hello\r\n") await player.writer.drain() register(CommandDefinition("mycommand", my_command, aliases=["mc"])) CommandDefinition fields: name primary command name handler async function(player, args) aliases alternative names (default: []) mode required player mode (default: "normal", "*" = any mode) help help text (default: "") dispatch parses input, looks up the definition, calls its handler: await dispatch(player, "mycommand some args") if the command isn't found, the player gets "Unknown command: ..." movement -------- 8 directions, each with short and long aliases: n/north s/south e/east w/west ne/northeast nw/northwest se/southeast sw/southwest movement checks passability before updating position. impassable terrain gives "You can't go that way." nearby players see arrival/departure messages: jared leaves east. jared arrives from the west. "nearby" = within viewport range (10 tiles) of old or new position. look ---- look/l renders the viewport. player is always @ at center. other players show as *. output is ANSI-colored. adding commands --------------- 1. create src/mudlib/commands/yourcommand.py 2. import CommandDefinition and register from mudlib.commands 3. define async handler(player, args) 4. call register(CommandDefinition(...)) 5. import the module in server.py so registration runs at startup code ---- src/mudlib/commands/__init__.py registry + dispatch + CommandDefinition src/mudlib/commands/movement.py direction commands src/mudlib/commands/look.py look/l src/mudlib/commands/fly.py fly src/mudlib/commands/quit.py quit/q (mode="*") src/mudlib/player.py Player dataclass + registry