327 lines
9.4 KiB
Markdown
327 lines
9.4 KiB
Markdown
# EQ2Go Command System
|
|
|
|
The EQ2Go command system provides a comprehensive framework for handling player commands, admin commands, and console commands in the EverQuest II server emulator. This system is converted from the original C++ EQ2EMu codebase while leveraging modern Go patterns and practices.
|
|
|
|
## Architecture Overview
|
|
|
|
The command system consists of several key components:
|
|
|
|
- **CommandManager**: Central registry for all commands with thread-safe operations
|
|
- **CommandContext**: Execution context providing access to players, zones, arguments, and messaging
|
|
- **Command Types**: Different command categories (Player, Admin, Console, etc.)
|
|
- **Subcommand Support**: Hierarchical command structure for complex operations
|
|
|
|
## Core Components
|
|
|
|
### CommandManager
|
|
|
|
The `CommandManager` is the central hub that:
|
|
- Registers commands by name with case-insensitive lookup
|
|
- Manages subcommands under parent commands
|
|
- Executes commands with proper admin level checking
|
|
- Parses raw command strings into structured contexts
|
|
|
|
### CommandContext
|
|
|
|
The `CommandContext` provides:
|
|
- Type-safe argument parsing (string, int, float, bool)
|
|
- Message queuing with channel and color support
|
|
- Validation helpers for argument counts and requirements
|
|
- Access to game objects (player, zone, target)
|
|
- Result storage for complex operations
|
|
|
|
### Command Types
|
|
|
|
Commands are categorized by type:
|
|
|
|
- **Player Commands** (`CommandTypePlayer`): Basic player actions like `/say`, `/tell`, `/who`
|
|
- **Admin Commands** (`CommandTypeAdmin`): GM/Admin tools like `/kick`, `/ban`, `/summon`
|
|
- **Console Commands** (`CommandTypeConsole`): Server management from console
|
|
- **Specialized Types**: Spawn, Zone, Guild, Item, and Quest commands
|
|
|
|
## Admin Levels
|
|
|
|
The system supports four admin levels:
|
|
|
|
- **Player** (0): Basic player commands
|
|
- **Guide** (100): Helper/guide commands
|
|
- **GM** (200): Game master commands
|
|
- **Admin** (300): Full administrative access
|
|
|
|
## Usage Examples
|
|
|
|
### Basic Command Registration
|
|
|
|
```go
|
|
// Initialize the command system
|
|
cm, err := InitializeCommands()
|
|
if err != nil {
|
|
log.Fatalf("Failed to initialize commands: %v", err)
|
|
}
|
|
|
|
// Register a custom command
|
|
customCmd := &Command{
|
|
Name: "custom",
|
|
Type: CommandTypePlayer,
|
|
Description: "A custom command",
|
|
Usage: "/custom <arg>",
|
|
RequiredLevel: AdminLevelPlayer,
|
|
Handler: func(ctx *CommandContext) error {
|
|
if err := ctx.ValidateArgumentCount(1, 1); err != nil {
|
|
ctx.AddErrorMessage("Usage: /custom <arg>")
|
|
return nil
|
|
}
|
|
|
|
arg := ctx.Arguments[0]
|
|
ctx.AddStatusMessage(fmt.Sprintf("You used custom command with: %s", arg))
|
|
return nil
|
|
},
|
|
}
|
|
|
|
err = cm.Register(customCmd)
|
|
if err != nil {
|
|
log.Printf("Failed to register custom command: %v", err)
|
|
}
|
|
```
|
|
|
|
### Executing Commands
|
|
|
|
```go
|
|
// Parse and execute a command from a client
|
|
err := ExecuteCommand(cm, "/say Hello everyone!", client)
|
|
if err != nil {
|
|
log.Printf("Command execution failed: %v", err)
|
|
}
|
|
```
|
|
|
|
### Subcommand Registration
|
|
|
|
```go
|
|
// Register a parent command
|
|
parentCmd := &Command{
|
|
Name: "manage",
|
|
Type: CommandTypeAdmin,
|
|
RequiredLevel: AdminLevelGM,
|
|
Handler: func(ctx *CommandContext) error {
|
|
ctx.AddErrorMessage("Usage: /manage <player|item|zone> [options]")
|
|
return nil
|
|
},
|
|
}
|
|
cm.Register(parentCmd)
|
|
|
|
// Register subcommands
|
|
playerSubCmd := &Command{
|
|
Name: "player",
|
|
Type: CommandTypeAdmin,
|
|
RequiredLevel: AdminLevelGM,
|
|
Handler: func(ctx *CommandContext) error {
|
|
// Handle player management
|
|
return nil
|
|
},
|
|
}
|
|
cm.RegisterSubCommand("manage", playerSubCmd)
|
|
```
|
|
|
|
## Command Implementation
|
|
|
|
### Player Commands
|
|
|
|
Located in `player.go`, these include:
|
|
|
|
- **Communication**: `/say`, `/tell`, `/yell`, `/shout`, `/ooc`, `/emote`
|
|
- **Group Management**: `/group`, `/groupsay`, `/gsay`
|
|
- **Guild Management**: `/guild`, `/guildsay`, `/officersay`
|
|
- **Information**: `/who`, `/time`, `/location`, `/consider`
|
|
- **Character**: `/afk`, `/anon`, `/lfg`, `/inventory`
|
|
- **Utilities**: `/help`, `/quit`, `/trade`, `/quest`
|
|
|
|
### Admin Commands
|
|
|
|
Located in `admin.go`, these include:
|
|
|
|
- **Player Management**: `/kick`, `/ban`, `/unban`, `/summon`, `/goto`
|
|
- **Communication**: `/broadcast`, `/announce`
|
|
- **Spawn Management**: `/spawn`, `/npc`
|
|
- **Item Management**: `/item`, `/giveitem`
|
|
- **Character Modification**: `/modify`, `/setlevel`, `/setclass`
|
|
- **Server Management**: `/reload`, `/shutdown`, `/cancelshutdown`
|
|
- **GM Utilities**: `/invisible`, `/invulnerable`, `/speed`, `/flymode`
|
|
- **Information**: `/info`, `/version`
|
|
|
|
### Console Commands
|
|
|
|
Located in `console.go`, these include prefixed versions of admin commands for console use:
|
|
|
|
- **Player Management**: `console_ban`, `console_kick`, `console_unban`
|
|
- **Communication**: `console_broadcast`, `console_announce`, `console_tell`
|
|
- **Information**: `console_guild`, `player`, `console_zone`, `console_who`
|
|
- **Server Management**: `console_reload`, `console_shutdown`, `exit`
|
|
- **MOTD Management**: `getmotd`, `setmotd`
|
|
- **Rules Management**: `rules`
|
|
|
|
## Message Channels and Colors
|
|
|
|
Commands can send messages through various channels:
|
|
|
|
### Channels
|
|
- `ChannelSay` (8): Local say messages
|
|
- `ChannelTell` (28): Private messages
|
|
- `ChannelBroadcast` (92): Server-wide broadcasts
|
|
- `ChannelError` (3): Error messages
|
|
- `ChannelStatus` (4): Status updates
|
|
|
|
### Colors
|
|
- `ColorWhite` (254): Standard text
|
|
- `ColorRed` (3): Errors and warnings
|
|
- `ColorYellow` (5): Status messages
|
|
- `ColorChatRelation` (4): Relationship text
|
|
|
|
## Error Handling
|
|
|
|
The command system provides comprehensive error handling:
|
|
|
|
```go
|
|
func HandleExampleCommand(ctx *CommandContext) error {
|
|
// Validate player is present
|
|
if err := ctx.RequirePlayer(); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Validate argument count
|
|
if err := ctx.ValidateArgumentCount(1, 3); err != nil {
|
|
ctx.AddErrorMessage("Usage: /example <required> [optional1] [optional2]")
|
|
return nil
|
|
}
|
|
|
|
// Validate admin level
|
|
if err := ctx.RequireAdminLevel(AdminLevelGM); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Command logic here...
|
|
return nil
|
|
}
|
|
```
|
|
|
|
## Testing
|
|
|
|
The command system includes comprehensive tests in `commands_test.go`:
|
|
|
|
```bash
|
|
# Run all command tests
|
|
go test ./internal/commands -v
|
|
|
|
# Run specific test
|
|
go test ./internal/commands -run TestCommandManager_Execute
|
|
```
|
|
|
|
Tests cover:
|
|
- Command registration and retrieval
|
|
- Argument parsing and validation
|
|
- Message handling
|
|
- Admin level checking
|
|
- Subcommand functionality
|
|
- Error conditions
|
|
|
|
## Integration with Server
|
|
|
|
To integrate the command system with the server:
|
|
|
|
```go
|
|
// Initialize commands during server startup
|
|
commandManager, err := commands.InitializeCommands()
|
|
if err != nil {
|
|
log.Fatalf("Failed to initialize commands: %v", err)
|
|
}
|
|
|
|
// Handle incoming command from client
|
|
func handleClientCommand(client ClientInterface, rawCommand string) {
|
|
err := commands.ExecuteCommand(commandManager, rawCommand, client)
|
|
if err != nil {
|
|
log.Printf("Command execution error: %v", err)
|
|
}
|
|
}
|
|
```
|
|
|
|
## Thread Safety
|
|
|
|
The command system is designed to be thread-safe:
|
|
- CommandManager uses read/write mutexes for concurrent access
|
|
- CommandContext uses mutexes for message and result storage
|
|
- All operations are safe for concurrent use
|
|
|
|
## Extension Points
|
|
|
|
The system is designed for easy extension:
|
|
|
|
### Custom Command Types
|
|
```go
|
|
const CommandTypeCustom CommandType = 100
|
|
|
|
func (ct CommandType) String() string {
|
|
switch ct {
|
|
case CommandTypeCustom:
|
|
return "custom"
|
|
default:
|
|
return CommandType(ct).String()
|
|
}
|
|
}
|
|
```
|
|
|
|
### Custom Handlers
|
|
```go
|
|
func MyCustomHandler(ctx *CommandContext) error {
|
|
// Custom command logic
|
|
ctx.AddStatusMessage("Custom command executed!")
|
|
return nil
|
|
}
|
|
```
|
|
|
|
## Performance Considerations
|
|
|
|
- Commands are indexed by name in a hash map for O(1) lookup
|
|
- Case-insensitive matching uses normalized lowercase keys
|
|
- Message batching reduces client communication overhead
|
|
- Argument parsing is lazy and type-safe
|
|
|
|
## Migration from C++
|
|
|
|
Key differences from the original C++ implementation:
|
|
|
|
1. **Type Safety**: Go's type system prevents many runtime errors
|
|
2. **Memory Management**: Automatic garbage collection eliminates memory leaks
|
|
3. **Concurrency**: Native goroutine support for concurrent operations
|
|
4. **Error Handling**: Explicit error returns instead of exceptions
|
|
5. **Testing**: Built-in testing framework with comprehensive coverage
|
|
|
|
## Future Enhancements
|
|
|
|
Planned improvements:
|
|
|
|
- Lua script integration for dynamic commands
|
|
- Command aliasing system
|
|
- Advanced permission system
|
|
- Command cooldowns and rate limiting
|
|
- Audit logging for admin commands
|
|
- Dynamic command loading/unloading
|
|
|
|
## Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
**Command Not Found**: Ensure command is registered and name matches exactly
|
|
**Insufficient Privileges**: Check admin level requirements
|
|
**Argument Validation**: Use proper argument count validation
|
|
**Interface Errors**: Ensure client implements ClientInterface correctly
|
|
|
|
### Debug Output
|
|
|
|
Enable debug output for command execution:
|
|
```go
|
|
ctx.AddDefaultMessage(fmt.Sprintf("Debug: Command %s executed with %d args",
|
|
ctx.CommandName, ctx.ArgumentCount()))
|
|
```
|
|
|
|
## Conclusion
|
|
|
|
The EQ2Go command system provides a robust, extensible framework for handling all types of game commands while maintaining compatibility with the original EverQuest II protocol. The system's modular design and comprehensive testing ensure reliability and ease of maintenance. |