292 lines
7.4 KiB
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"
|
|
}
|