예제 #1
0
        /// <summary>
        /// Create a <see cref="XanBotMember"/> from a <seealso cref="DiscordUser"/> and a <seealso cref="DiscordGuild"/>
        /// </summary>
        /// <param name="server">The server that this <see cref="XanBotMember"/> exists in.</param>
        /// <param name="user">The <seealso cref="DiscordUser"/> to create the member from.</param>
        /// <returns></returns>
        public static XanBotMember GetMemberFromUser(DiscordGuild server, DiscordUser user)
        {
            if (user == null)
            {
                return(null);
            }
            BotContext ctxForServer = BotContextRegistry.GetContext(server);

            return(GetMemberFromUser(ctxForServer, user));
        }
예제 #2
0
        /// <summary>
        /// Runs the <see cref="PassiveHandler"/>s for the server that <paramref name="originalMessage"/> was sent in based on the content from the message.
        /// </summary>
        /// <param name="originalMessage">The chat message.</param>
        public static async Task RunPassiveHandlersForMessage(DiscordMessage originalMessage)
        {
            BotContext   targetContext = BotContextRegistry.GetContext(originalMessage.Channel.Guild);
            XanBotMember sender        = XanBotMember.GetMemberFromUser(targetContext, originalMessage.Author);

            if (!targetContext.Virtual)
            {
                foreach (PassiveHandler handler in targetContext.Handlers)
                {
                    XanBotLogger.WriteDebugLine(handler.Name);
                    if (await handler.RunHandlerAsync(targetContext, sender, originalMessage))
                    {
                        XanBotLogger.WriteDebugLine("... returned true");
                        return;
                    }
                    XanBotLogger.WriteDebugLine("... returned false");
                }
            }
            else
            {
                XanBotLogger.WriteDebugLine("Target context is virtual. Skipping passive handlers.");
            }
        }
예제 #3
0
        /// <summary>
        /// Automatically creates <see cref="Client"/> and connects it, creates <see cref="VoiceClient"/> (if requested), instantiates all bot contexts automatically, starts the <see cref="XanBotConsoleCore"/> update loop, and binds the windows console CTRL+C/CTRL+BREAK to <see cref="Exit(int)>"/>
        /// </summary>
        /// <param name="botToken">The token of this discord bot.</param>
        /// <param name="createVoiceNextClient">If true, <see cref="VoiceClient"/> will be instantiated and allow this bot to connect to voice channels.</param>
        /// <param name="isTargettingWindows7">Whether or not this bot is running on Windows 7. This is necessary for some init code.</param>
        /// <param name="yieldUntilGuildsDownloaded">If true, this task will yield until <see cref="DiscordClient.GuildDownloadCompleted"/> is fired.</param>
        /// <returns></returns>
        public static async Task InitializeBotAsync(string botToken, bool createVoiceNextClient = false, bool isTargettingWindows7 = false, bool yieldUntilGuildsDownloaded = false)
        {
            Console.ForegroundColor = ConsoleColor.Green;

            XanBotLogger.IsPathLocked = true;
            if (IsDebugMode)
            {
                XanBotLogger.WriteLine("§eInitializing in Debug Mode...");
            }
            else
            {
                XanBotLogger.WriteLine("§2Initializing...");
            }
            if (isTargettingWindows7)
            {
                Client = new DiscordClient(new DiscordConfiguration
                {
                    Token     = botToken,
                    TokenType = TokenType.Bot,
                    WebSocketClientFactory = new WebSocketClientFactoryDelegate(WebSocket4NetClient.CreateNew), // Remove if this bot is running on machine with Windows 10.
                });
            }
            else
            {
                Client = new DiscordClient(new DiscordConfiguration
                {
                    Token     = botToken,
                    TokenType = TokenType.Bot
                });
            }
            XanBotLogger.WriteDebugLine("Created DiscordClient.");

            if (createVoiceNextClient)
            {
                VoiceClient = Client.UseVoiceNext(new VoiceNextConfiguration
                {
                    AudioFormat = new AudioFormat(48000, 2, VoiceApplication.LowLatency)
                });
                XanBotLogger.WriteDebugLine("Created VoiceNextClient.");
            }

            XanBotLogger.WriteLine("§2Connecting to Discord...");
            await Client.ConnectAsync();

            // Client is connected. Create contexts!
            XanBotLogger.WriteLine("§2Initializing User-Defined Bot Contexts...");
            BotContextRegistry.InitializeAllContexts();

            XanBotLogger.WriteLine("§2Connecting CommandMarshaller to chat events...");
            Client.MessageCreated += async evt =>
            {
                //XanBotLogger.WriteLine("Hey the message created event fired");
                if (evt.Author == Client.CurrentUser)
                {
                    return;
                }
                if (evt.Author.IsBot)
                {
                    return;
                }
                if (CommandMarshaller.IsCommand(evt.Message.Content))
                {
                    XanBotLogger.WriteDebugLine("Message was sent and was detected as a command.");
                    await CommandMarshaller.HandleMessageCommand(evt.Message);
                }
                else
                {
                    XanBotLogger.WriteDebugLine("Message was sent but was not a command. Throwing it into the passive handlers.");
                    await CommandMarshaller.RunPassiveHandlersForMessage(evt.Message);
                }
            };

#pragma warning disable CS1998
            if (yieldUntilGuildsDownloaded)
            {
                XanBotLogger.WriteLine("§2Downloading server data from Discord...");
                ManualResetEvent completedSignal = new ManualResetEvent(false);
                Client.GuildDownloadCompleted += async evt =>
                {
                    HasFinishedGettingGuildData = true;
                    completedSignal?.Set();
                };
                completedSignal.WaitOne();
                completedSignal.Dispose();
                completedSignal = null;
            }
            else
            {
                Client.GuildDownloadCompleted += async evt =>
                {
                    HasFinishedGettingGuildData = true;
                };
            }
#pragma warning restore CS1998

            XanBotLogger.WriteLine("§2Setting up frontend console...");
            Console.CancelKeyPress += new ConsoleCancelEventHandler(OnCtrlCExit);
            XanBotConsoleCore.StartUpdateConsoleTask();

            Created = true;
            XanBotLogger.WriteLine("§aInitialization complete!"); // This fixes an occasional formatting issue where it renders in the typing text color.
        }
예제 #4
0
        /// <summary>
        /// Handles a command issued via a Discord message. This does not test if it is a command. Please test with <see cref="IsCommand(string)"/> before running this.
        /// </summary>
        /// <param name="originalMessage">The Discord message sent by the command.</param>
        public static async Task HandleMessageCommand(DiscordMessage originalMessage)
        {
            DiscordUser author         = originalMessage.Author;
            BotContext  commandContext = BotContextRegistry.GetContext(originalMessage.Channel.Guild);

            XanBotLogger.WriteDebugLine("Executing command in bot context. Info:");
            XanBotLogger.WriteLine(commandContext.ToConsoleString(), isDebugModeOnly: true);

            XanBotMember member = XanBotMember.GetMemberFromUser(commandContext, author);
            string       text   = originalMessage.Content;

            if (text.ToLower().StartsWith(CommandPrefix.ToLower()))
            {
                text = text.Substring(CommandPrefix.Length);
            }
            while (AllowSpacesAfterPrefix && text.StartsWith(" "))
            {
                text = text.Substring(1);
            }
            string[] allArgs = ArgumentSplitter.SplitArgs(text);
            string   command = allArgs[0];

            string[] args = new string[0];
            if (allArgs.Length > 1)
            {
                args = allArgs.Skip(1).ToArray();
            }

            // Catch case: Prevent excessive command length.
            if (command.Length > 32)
            {
                await ResponseUtil.RespondToAsync(originalMessage, "The command you input is too long.");

                XanBotLogger.WriteLine(string.Format("§aUser \"§6{0}§a\" issued a command that was considered too long to parse.", member.FullName));
                return;
            }
            // Catch case: Strip color formatting
            command.Replace(XanBotLogger.COLOR_CODE_SYM.ToString(), "");

            XanBotLogger.WriteDebugLine("Searching for command...");
            Command execCommand = null;
            string  cmdLower    = command.ToLower();

            // Search the context FIRST. That ensures that context commands can override stock commands.
            foreach (Command cmd in commandContext.Commands)
            {
                if (cmd.Name.ToLower() == cmdLower)
                {
                    execCommand = cmd;
                    XanBotLogger.WriteDebugLine($"Found command [{cmd.Name}] in context.");
                    break;
                }
                else
                {
                    if (cmd.AlternateNames != null)
                    {
                        foreach (string altName in cmd.AlternateNames)
                        {
                            if (altName.ToLower() == cmdLower)
                            {
                                execCommand = cmd;
                                break;
                            }
                        }
                    }
                }
            }

            if (execCommand == null)
            {
                foreach (Command cmd in Commands)
                {
                    if (cmd.Name.ToLower() == command.ToLower())
                    {
                        execCommand = cmd;
                        XanBotLogger.WriteDebugLine($"Found command [{cmd.Name}] globally.");
                        break;
                    }
                }
            }


            if (execCommand != null)
            {
                UsagePermissionPacket usagePerms = execCommand.CanUseCommand(member);
                if (usagePerms.CanUse)
                {
                    if (execCommand.CanUseCommandInThisChannel(member, originalMessage.Channel, out DiscordChannel optimalTargetChannel))
                    {
                        try
                        {
                            string allArgsText = "";
                            if (args.Length > 0)
                            {
                                allArgsText = text.Substring(command.Length + 1);
                            }
                            originalMessage.Channel.TriggerTypingAsync().GetAwaiter().GetResult();
                            await execCommand.ExecuteCommandAsync(commandContext, member, originalMessage, args, allArgsText);

                            XanBotLogger.WriteLine(string.Format("§aUser \"§6{0}§a\" issued command \"§6{1}§a\" with args {2}", member.FullName, command, ArrayToText(args)));
                        }
                        catch (CommandException commandErr)
                        {
                            string message = string.Format("§cFailed to issue command `{0}`: §1{1}", commandErr.Command.Name, commandErr.Message);
                            await ResponseUtil.RespondToAsync(originalMessage, message);

                            XanBotLogger.WriteLine(string.Format("§aUser \"§6{0}§a\" attempted to issue command \"§6{1}§a\" but it failed. The command gave the reason: §2{2}", member.FullName, commandErr.Command.Name, commandErr.Message));
                        }
                        catch (ArchonCommandException commandErr)
                        {
                            string message = string.Format("§cFailed to issue Archon Command `{0}`: §1{1}", commandErr.Command.Name, commandErr.Message);
                            await ResponseUtil.RespondToAsync(originalMessage, message);

                            XanBotLogger.WriteLine(string.Format("§aUser \"§6{0}§a\" attempted to issue Archon Command \"§6{1}§a\" but it failed. The command gave the reason: §2{2}", member.FullName, commandErr.Command.Name, commandErr.Message));
                        }
                        catch (TaskCanceledException taskCancel)
                        {
                            XanBotLogger.WriteException(taskCancel);
                        }
                    }
                    else
                    {
                        string message = string.Format($"You can't use this command here. Go to <#{optimalTargetChannel.Id}> instead.");
                        await ResponseUtil.RespondToAsync(originalMessage, message);
                    }
                }
                else
                {
                    //string message = string.Format("You are not authorized to use `{0}`. It is only available to permission level `{1}` and above (You are at `{2}`)", execCommand.Name, execCommand.RequiredPermissionLevel, member.PermissionLevel);
                    await ResponseUtil.RespondToAsync(originalMessage, usagePerms.ErrorMessage);

                    XanBotLogger.WriteLine(string.Format("§aUser \"§6{0}§a\" attempted to issue command \"§6{1}§a\" but it failed because they don't have a high enough permission level or because the command's CanUseCommand method returned false.", member.FullName, execCommand.Name));
                }
            }
            else
            {
                await ResponseUtil.RespondToAsync(originalMessage, "The command `" + command + "` does not exist.");

                XanBotLogger.WriteLine(string.Format("§aUser \"§6{0}§a\" attempted to issue command \"§6{1}§a\" but it failed because it doesn't exist.", member.FullName, command));
            }
        }