eq2go/internal/commands/context.go

292 lines
7.4 KiB
Go

package commands
import (
"fmt"
"strconv"
"strings"
"eq2emu/internal/entity"
"eq2emu/internal/spawn"
)
// NewCommandContext creates a new command context
func NewCommandContext(commandType CommandType, commandName string, arguments []string) *CommandContext {
return &CommandContext{
CommandType: commandType,
CommandName: commandName,
Arguments: arguments,
RawArguments: strings.Join(arguments, " "),
Messages: make([]CommandMessage, 0),
Results: make(map[string]any),
}
}
// WithClient adds a client to the context
func (ctx *CommandContext) WithClient(client ClientInterface) *CommandContext {
ctx.Client = client
if client != nil {
ctx.Player = client.GetPlayer()
ctx.Zone = client.GetZone()
ctx.AdminLevel = client.GetAdminLevel()
}
return ctx
}
// WithPlayer adds a player to the context
func (ctx *CommandContext) WithPlayer(player *entity.Entity) *CommandContext {
ctx.Player = player
return ctx
}
// WithTarget adds a target to the context
func (ctx *CommandContext) WithTarget(target *spawn.Spawn) *CommandContext {
ctx.Target = target
return ctx
}
// WithZone adds a zone to the context
func (ctx *CommandContext) WithZone(zone ZoneInterface) *CommandContext {
ctx.Zone = zone
return ctx
}
// WithAdminLevel sets the admin level for the context
func (ctx *CommandContext) WithAdminLevel(level int) *CommandContext {
ctx.AdminLevel = level
return ctx
}
// GetArgument retrieves an argument by index
func (ctx *CommandContext) GetArgument(index int) (string, bool) {
if index < 0 || index >= len(ctx.Arguments) {
return "", false
}
return ctx.Arguments[index], true
}
// GetArgumentInt retrieves an integer argument by index
func (ctx *CommandContext) GetArgumentInt(index int, defaultValue int) int {
if arg, exists := ctx.GetArgument(index); exists {
if value, err := strconv.Atoi(arg); err == nil {
return value
}
}
return defaultValue
}
// GetArgumentFloat retrieves a float argument by index
func (ctx *CommandContext) GetArgumentFloat(index int, defaultValue float64) float64 {
if arg, exists := ctx.GetArgument(index); exists {
if value, err := strconv.ParseFloat(arg, 64); err == nil {
return value
}
}
return defaultValue
}
// GetArgumentBool retrieves a boolean argument by index
func (ctx *CommandContext) GetArgumentBool(index int, defaultValue bool) bool {
if arg, exists := ctx.GetArgument(index); exists {
switch strings.ToLower(arg) {
case "true", "yes", "on", "1":
return true
case "false", "no", "off", "0":
return false
}
}
return defaultValue
}
// GetRemainingArguments gets all arguments from index onwards as a string
func (ctx *CommandContext) GetRemainingArguments(fromIndex int) string {
if fromIndex < 0 || fromIndex >= len(ctx.Arguments) {
return ""
}
return strings.Join(ctx.Arguments[fromIndex:], " ")
}
// HasArgument checks if an argument exists at the given index
func (ctx *CommandContext) HasArgument(index int) bool {
_, exists := ctx.GetArgument(index)
return exists
}
// ArgumentCount returns the number of arguments
func (ctx *CommandContext) ArgumentCount() int {
return len(ctx.Arguments)
}
// AddMessage adds a message to be sent to the client
func (ctx *CommandContext) AddMessage(channel, color int, message string) {
ctx.mutex.Lock()
defer ctx.mutex.Unlock()
ctx.Messages = append(ctx.Messages, CommandMessage{
Channel: channel,
Color: color,
Message: message,
})
}
// AddDefaultMessage adds a message with default channel and color
func (ctx *CommandContext) AddDefaultMessage(message string) {
ctx.AddMessage(ChannelDefault, ColorWhite, message)
}
// AddErrorMessage adds an error message
func (ctx *CommandContext) AddErrorMessage(message string) {
ctx.AddMessage(ChannelError, ColorRed, message)
}
// AddStatusMessage adds a status message
func (ctx *CommandContext) AddStatusMessage(message string) {
ctx.AddMessage(ChannelStatus, ColorYellow, message)
}
// SendMessages sends all queued messages to the client
func (ctx *CommandContext) SendMessages() {
if ctx.Client == nil {
return
}
ctx.mutex.RLock()
messages := make([]CommandMessage, len(ctx.Messages))
copy(messages, ctx.Messages)
ctx.mutex.RUnlock()
for _, msg := range messages {
ctx.Client.SendMessage(msg.Channel, msg.Color, msg.Message)
}
}
// ClearMessages clears all queued messages
func (ctx *CommandContext) ClearMessages() {
ctx.mutex.Lock()
defer ctx.mutex.Unlock()
ctx.Messages = ctx.Messages[:0]
}
// SetResult sets a result value
func (ctx *CommandContext) SetResult(name string, value any) {
ctx.mutex.Lock()
defer ctx.mutex.Unlock()
if ctx.Results == nil {
ctx.Results = make(map[string]any)
}
ctx.Results[name] = value
}
// GetResult retrieves a result value
func (ctx *CommandContext) GetResult(name string) (any, bool) {
ctx.mutex.RLock()
defer ctx.mutex.RUnlock()
value, exists := ctx.Results[name]
return value, exists
}
// GetResultString retrieves a string result
func (ctx *CommandContext) GetResultString(name string, defaultValue string) string {
if value, exists := ctx.GetResult(name); exists {
if str, ok := value.(string); ok {
return str
}
}
return defaultValue
}
// GetResultInt retrieves an integer result
func (ctx *CommandContext) GetResultInt(name string, defaultValue int) int {
if value, exists := ctx.GetResult(name); exists {
switch v := value.(type) {
case int:
return v
case int32:
return int(v)
case int64:
return int(v)
case float32:
return int(v)
case float64:
return int(v)
}
}
return defaultValue
}
// ValidateArgumentCount validates that the command has the required number of arguments
func (ctx *CommandContext) ValidateArgumentCount(min, max int) error {
argCount := len(ctx.Arguments)
if argCount < min {
return fmt.Errorf("command '%s' requires at least %d arguments, got %d", ctx.CommandName, min, argCount)
}
if max >= 0 && argCount > max {
return fmt.Errorf("command '%s' accepts at most %d arguments, got %d", ctx.CommandName, max, argCount)
}
return nil
}
// RequirePlayer ensures a player is present in the context
func (ctx *CommandContext) RequirePlayer() error {
if ctx.Player == nil {
return fmt.Errorf("command '%s' requires a player", ctx.CommandName)
}
return nil
}
// RequireTarget ensures a target is present in the context
func (ctx *CommandContext) RequireTarget() error {
if ctx.Target == nil {
return fmt.Errorf("command '%s' requires a target", ctx.CommandName)
}
return nil
}
// RequireZone ensures a zone is present in the context
func (ctx *CommandContext) RequireZone() error {
if ctx.Zone == nil {
return fmt.Errorf("command '%s' requires a zone", ctx.CommandName)
}
return nil
}
// RequireAdminLevel ensures the user has the required admin level
func (ctx *CommandContext) RequireAdminLevel(requiredLevel int) error {
if ctx.AdminLevel < requiredLevel {
return fmt.Errorf("command '%s' requires admin level %d, you have %d",
ctx.CommandName, requiredLevel, ctx.AdminLevel)
}
return nil
}
// GetPlayerName safely gets the player's name
func (ctx *CommandContext) GetPlayerName() string {
if ctx.Player != nil {
return ctx.Player.GetName()
}
if ctx.Client != nil {
return ctx.Client.GetName()
}
return "Unknown"
}
// GetTargetName safely gets the target's name
func (ctx *CommandContext) GetTargetName() string {
if ctx.Target != nil {
return ctx.Target.GetName()
}
return "No Target"
}
// GetZoneName safely gets the zone's name
func (ctx *CommandContext) GetZoneName() string {
if ctx.Zone != nil {
return ctx.Zone.GetName()
}
return "No Zone"
}