package main import ( "fmt" "time" "github.com/bwmarrin/discordgo" "strings" "log" "regexp" ) type CommandType int const ( CommandTypePrefix CommandType = 0 CommandTypeFullMatch CommandType = 1 CommandTypeRegex CommandType = 2 CommandTypeContains CommandType = 3 ) type Command struct { Trigger string // must be specified Output string // no output if unspecified OutputEmbed *discordgo.MessageEmbed // no embed output if unspecified Type CommandType // defaults to Prefix Cooldown int // defaults to 0 (no cooldown) OutputIsReply bool // defaults to false RequiresMention bool // defaults to false DeleteInput bool // defaults to false DMOnly bool // defaults to false AdminOnly bool // defaults to false IgnoreCase bool // defaults to false // for custom commands that go beyond prints and deletions Function func(*discordgo.Session, *discordgo.MessageCreate) IsOnCooldown bool // don’t set this manually (it’s overwritten anyway) } func registerCommand(command Command) { if command.Trigger == "" { fmt.Println("Cannot register a command with no trigger. Skipping.") return } if command.IgnoreCase { command.Trigger = strings.ToLower(command.Trigger) } commands = append(commands, command) } func evaluateMessage(s *discordgo.Session, m *discordgo.MessageCreate) { if m.Author.ID == s.State.User.ID { log.Printf(" %s", m.Content) return } fmt.Println(m.Content) for i, command := range commands { content := m.Content if command.IgnoreCase { content = strings.ToLower(content) } if command.RequiresMention { command.Trigger = fmt.Sprintf(command.Trigger, s.State.User.ID) } switch command.Type { case CommandTypePrefix: if strings.HasPrefix(content, command.Trigger) { executeCommand(s, m, command, i) return } case CommandTypeFullMatch: if content == command.Trigger { executeCommand(s, m, command, i) return } case CommandTypeRegex: match, _ := regexp.MatchString(command.Trigger, content) if match { executeCommand(s, m, command, i) return } case CommandTypeContains: if strings.Contains(content, command.Trigger) { executeCommand(s, m, command, i) return } } } } func executeCommand(session *discordgo.Session, message *discordgo.MessageCreate, command Command, commandIndex int) { if (!command.DMOnly || (getChannel(session.State, message.ChannelID).Type == discordgo.ChannelTypeDM)) && (!command.AdminOnly || (message.Author.ID == config.AdminID)) && !command.IsOnCooldown { log.Printf("Executed command %s triggered by user %s", command.Trigger, userToString(message.Author)) fmt.Printf("Executed command %s triggered by user %s", command.Trigger, userToString(message.Author)) if command.Cooldown > 0 { commands[commandIndex].IsOnCooldown = true go removeCooldown(commandIndex) } if command.Function == nil { // simple reply if command.OutputEmbed == nil { messageContent := generateReply(message, command) session.ChannelMessageSend(message.ChannelID, messageContent) } else { session.ChannelMessageSendEmbed(message.ChannelID, command.OutputEmbed) } if command.DeleteInput { session.ChannelMessageDelete(message.ChannelID, message.ID) } } else { // execute custom function command.Function(session, message) } } else { log.Printf("Denied command %s to user %s.", command.Trigger, userToString(message.Author)) } } func removeCooldown(commandIndex int) { time.Sleep(time.Duration(commands[commandIndex].Cooldown) * time.Second) commands[commandIndex].IsOnCooldown = false } func generateReply(message *discordgo.MessageCreate, command Command) string { output := command.Output if command.OutputIsReply { output = fmt.Sprintf(output, message.Author.ID) } return output } func redirectComplaint(s *discordgo.Session, m *discordgo.MessageCreate) { embed := &discordgo.MessageEmbed { Author: &discordgo.MessageEmbedAuthor{}, Color: 0xbb0000, Description: m.Content, } s.ChannelMessageSendEmbed(config.ModChannel, embed) } func echoMessage(s *discordgo.Session, m *discordgo.MessageCreate) { s.ChannelMessageSend(m.ChannelID, m.Content) }