Command System¶
MAID uses a layered command system with priority-based resolution.
Overview¶
The command system allows multiple content packs to provide commands, with higher-priority packs able to override or extend lower-priority commands.
from maid_engine.commands.registry import LayeredCommandRegistry
registry = LayeredCommandRegistry()
# Register at default priority
registry.register("look", look_handler)
# Register at higher priority (overrides default)
registry.register("look", enhanced_look_handler, priority=100)
Command Structure¶
When a player types a command, MAID:
- Parses the input into command name and arguments
- Finds registered handlers for that command
- Runs handlers in priority order (highest first)
- Stops when a handler returns
True(handled)
Player Input: "attack goblin with sword"
|
v
+----------------------------------+
| LayeredCommandRegistry |
| +---------+ +---------+ |
| |priority | |priority | |
| | 100 | | 50 | |
| +---------+ +---------+ |
| | | |
| v v |
| [handler1] [handler2] |
+----------------------------------+
|
v
CommandContext(
command="attack",
args=["goblin", "with", "sword"],
raw_input="attack goblin with sword",
session=player_session,
player_id=player.id,
world=game_world
)
Registration¶
Commands are registered during content pack loading:
class MyContentPack(ContentPack):
def register_commands(self, registry: CommandRegistry) -> None:
# Simple registration
registry.register("greet", cmd_greet, pack=self.manifest.name)
# With priority (higher = runs first)
registry.register("look", enhanced_look, pack=self.manifest.name, priority=50)
# With aliases
registry.register(
"attack",
cmd_attack,
pack=self.manifest.name,
aliases=["kill", "hit", "strike"]
)
Command Handlers¶
Command handlers are async functions that process player input:
from maid_engine.commands import CommandContext
async def cmd_greet(ctx: CommandContext) -> bool:
"""Greet other players in the room."""
target = ctx.args[0] if ctx.args else "everyone"
await ctx.session.send(f"You greet {target}!")
return True # Command was handled
The handler returns:
- True - Command handled, stop processing
- False - Not handled, try next handler
Advanced Features¶
Argument Parsing¶
from maid_engine.commands.arguments import arguments, ArgumentSpec, ArgumentType
@arguments(
ArgumentSpec("target", ArgumentType.ENTITY, required=True),
ArgumentSpec("weapon", ArgumentType.ITEM, required=False),
)
async def cmd_attack(ctx: CommandContext, args: ParsedArguments) -> bool:
target = args["target"]
weapon = args.get("weapon")
# ...
Lock Expressions¶
from maid_engine.commands.decorators import command
@command(name="admin_cmd", locks="perm(admin)")
async def admin_command(ctx: CommandContext) -> bool:
# Only admins can use this
pass
@command(name="guild_skill", locks="level(10) AND in_guild(warriors)")
async def guild_skill(ctx: CommandContext) -> bool:
# Requires level 10 AND membership in warriors guild
pass
Pre/Post Hooks¶
from maid_engine.commands.hooks import PreCommandHook, HookPriority
class LoggingHook(PreCommandHook):
async def execute(self, ctx: CommandContext) -> bool:
logger.info(f"Command: {ctx.command} by {ctx.session.player_id}")
return True # Continue execution
registry.register_pre_hook("logging", LoggingHook(), priority=HookPriority.FIRST)