package main import ( "math/rand" "strconv" "strings" "sync" ) type Command struct { commandHandlerFunc CommandHandlerFunc description string } type CommandHandlerFunc func(args []string, clientID int) string type CommandRegistry struct { commands map[string]Command mutex sync.Mutex // Mutex to safely access commands map } func NewCommandRegistry() *CommandRegistry { return &CommandRegistry{ commands: make(map[string]Command), } } func (cr *CommandRegistry) RegisterCommand(command string, handler CommandHandlerFunc, desc string) { cr.mutex.Lock() defer cr.mutex.Unlock() cr.commands[command] = Command{ commandHandlerFunc: handler, description: desc, } } func (cr *CommandRegistry) GetCommandHandler(command string, clientID int) (CommandHandlerFunc, bool, int) { cr.mutex.Lock() defer cr.mutex.Unlock() commandEntry, ok := cr.commands[command] handler := commandEntry.commandHandlerFunc return handler, ok, clientID } func RegisterCommands(registry *CommandRegistry) { registry.RegisterCommand("clear", ClearCommand, `Clears your screen (clear)`) registry.RegisterCommand("setname", SetNameCommand, `Sets your name (setname yourname[string])`) registry.RegisterCommand("list", ListClientsCommand, `Lists clients (list)`) registry.RegisterCommand("rng", RandomCommand, `Generates a random integer (rng from[int] to[int{bigger than from}], both need to be above zero)`) registry.RegisterCommand("tell", TellClientCommand, `Tell a client (tell client[id or string{username}])`) registry.RegisterCommand("challenge", StartCommand, `Challenge a client (challenge client[id or string{username}])`) registry.RegisterCommand("accept", AcceptCommand, `Accepts a challenge (accept)`) registry.RegisterCommand("shoot", ShootCommand, `Shoots at a client (shoot target[int or string], accepts self as a parameter) {Shooting self with a blank keeps your turn}`) registry.RegisterCommand("useitem", UseItemCommand, `Uses an item in a match (useitem index[number])`) // Add more commands here... } func UseItemCommand(args []string, clientID int) string { param := -1 itemID := -1 if len(args) >= 2 { var err error param, err = strconv.Atoi(args[1]) if err != nil { param = -1 } } if len(args) >= 1 { var err error itemID, err = strconv.Atoi(args[0]) if err != nil { itemID = -1 } } if itemID >= 0 && itemID < clients[clientID].match.itemCount { clients[clientID].items[itemID].useItem(param) clients[clientID].match.SendMessage("\r\nUsing item "+clients[clientID].items[itemID].name(), clients[clientID]) return "Used" } else { return "ERROR using item" } } func ShootCommand(args []string, clientID int) string { if clients[clientID].match != nil && clients[clientID].match.round > 0 && clients[clientID].match.Guestturn != clients[clientID].isHost { defer clients[clientID].match.CheckStatus() defer clients[clientID].match.announceHP() defer clients[clientID].match.announceRounds() self := false if len(args) == 1 { if strings.ToLower(args[0]) == "self" { self = true } else if getByIDOrName(args[0]) == clientID { self = true } } var fired int var target *Client if self { target = clients[clientID] fired, clients[clientID].match.gun.magazine = clients[clientID].match.gun.Shoot(target) if fired == 1 { clients[clientID].match.Guestturn = clients[clientID].isHost clients[clientID].match.SendMessage("Shot myself with a live", clients[clientID]) } else { clients[clientID].match.SendMessage("Shot myself with a blank", clients[clientID]) } } else { if clients[clientID].isHost { target = clients[clientID].match.guest } else { target = clients[clientID].match.host } fired, clients[clientID].match.gun.magazine = clients[clientID].match.gun.Shoot(target) if fired == 1 { clients[clientID].match.Guestturn = clients[clientID].isHost clients[clientID].match.SendMessage("Shot "+target.Username+"("+strconv.Itoa(target.ID)+")"+"with a live", clients[clientID]) } else { clients[clientID].match.Guestturn = clients[clientID].isHost clients[clientID].match.SendMessage("Shot "+target.Username+"("+strconv.Itoa(target.ID)+")"+"with a blank", clients[clientID]) } } return "SHOT" } return "Error" } func AcceptCommand(args []string, clientID int) string { clientsMutex.Lock() defer clientsMutex.Unlock() matchesMutex.Lock() defer matchesMutex.Unlock() if clients[clientID].match != nil && clients[clientID].match.guest == clients[clientID] { clients[clientID].match.host.sendMessage("Accepted", clients[clientID]) clients[clientID].isHost = false clients[clientID].match.Guestturn = false clients[clientID].match.Start() return "Accepted" } return "No match to accept" } func StartCommand(args []string, clientID int) string { if len(args) == 1 { targetID := getByIDOrName(args[0]) if targetID >= 0 && targetID != clientID && (clients[clientID].match == nil || clients[clientID].match.round <= 0) { match := Match{ host: clients[clientID], guest: clients[targetID], round: 0, gun: Gun{ doubled: false, }, } clientsMutex.Lock() clients[clientID].match = &match clients[targetID].match = &match clients[clientID].isHost = true clients[targetID].sendMessage("Type \"accept\" to accept a match.", clients[clientID]) clientsMutex.Unlock() matchesMutex.Lock() matches = append(matches, &match) matchesMutex.Unlock() return "Successfully challenged" } else { return "Unknown user" } } return "Invalid argument" } func RandomCommand(args []string, clientID int) string { // Handle help command if len(args) == 2 { from, err1 := strconv.Atoi(args[0]) to, err2 := strconv.Atoi(args[1]) if err1 != nil || err2 != nil { return "Invalid argument" } if to-from <= 0 { return "Invalid range" } return "The number is " + strconv.Itoa(rand.Intn(to-from)+from) } return "No range provided" } func ClearCommand(args []string, clientID int) string { // Handle help command return "\033[H\033[2J\033[K" } func SetNameCommand(args []string, clientID int) string { // Handle help command if len(args) >= 1 { newName := args[0] clients[clientID].Username = newName return "Name set to " + newName } return "No name provided" } func ListClientsCommand(args []string, clientID int) string { message := "" for i, client := range clients { message += strconv.Itoa(i) + ": " + client.Username + "\n" } return message } func TellClientCommand(args []string, clientID int) string { message := "Message not delivered" if len(args) >= 2 { toClientID := getByIDOrName(args[0]) if toClientID >= 0 { toClientName := clients[toClientID].Username newMessage := "" //all the remaining arguments are a part of the message, join them with space for i, arg := range args { if i > 0 { newMessage += arg + " " } } clients[toClientID].sendMessage(newMessage, clients[clientID]) return "Message sent to " + toClientName } else { message = "Invalid recipient" } } return message }