Skip to content
This repository has been archived by the owner on Jun 30, 2023. It is now read-only.

Commit

Permalink
Add RequireMentionPrefixAttribute
Browse files Browse the repository at this point in the history
Defines that usage of a command must be prefixed with a bot mention rather than the plugin's defined prefix.

This involves having the plugin manager register CommandsNextExtension, and implementing a custom command handler which accounts for either plugin-defined prefix or mention prefix.
  • Loading branch information
oliverbooth committed Mar 20, 2022
1 parent e347fce commit 0bb57c7
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 1 deletion.
17 changes: 17 additions & 0 deletions BrackeysBot.API/Attributes/RequireMentionPrefix.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Threading.Tasks;
using DisCatSharp.CommandsNext;
using DisCatSharp.CommandsNext.Attributes;

namespace BrackeysBot.API.Attributes;

/// <summary>
/// Defines that usage of this command must require a bot mention prefix rather than the plugin's defined prefix.
/// </summary>
public sealed class RequireMentionPrefix : CheckBaseAttribute
{
/// <inheritdoc />
public override Task<bool> ExecuteCheckAsync(CommandContext ctx, bool help)
{
return Task.FromResult(MentionUtility.TryParseUser(ctx.Prefix[..^1], out ulong id) && id == ctx.Client.CurrentUser.Id);
}
}
54 changes: 53 additions & 1 deletion BrackeysBot/Plugins/SimplePluginManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Runtime.Loader;
using System.Threading;
using System.Threading.Tasks;
using BrackeysBot.API;
using BrackeysBot.API.Exceptions;
using BrackeysBot.API.Plugins;
using BrackeysBot.ArgumentConverters;
Expand All @@ -15,6 +16,9 @@
using DisCatSharp;
using DisCatSharp.CommandsNext;
using DisCatSharp.CommandsNext.Converters;
using DisCatSharp.CommandsNext.Exceptions;
using DisCatSharp.Entities;
using DisCatSharp.EventArgs;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -208,10 +212,11 @@ public IPlugin LoadPlugin(string name)
SetupPluginDataDirectory(pluginInfo, instance);
SetupPluginConfiguration(instance);
SetupPluginServices(instance, pluginInfo, pluginType);
CommandsNextExtension? commandsNext = SetupPluginCommands(instance);

instance.OnLoad().GetAwaiter().GetResult();

if (instance.DiscordClient?.GetCommandsNext() is { } commandsNext)
if (commandsNext is not null)
{
commandsNext.UnregisterConverter<TimeSpanConverter>();
commandsNext.RegisterConverter(new TimeSpanArgumentConverter());
Expand Down Expand Up @@ -312,6 +317,37 @@ public void UnloadPlugin(IPlugin plugin)
Logger.Info(string.Format(LoggerMessages.UnloadedPlugin, plugin.PluginInfo.Name, plugin.PluginInfo.Version));
}

private static Task ClientOnMessageCreated(MonoPlugin plugin, DiscordClient sender, MessageCreateEventArgs e)
{
CommandsNextExtension? commandsNext = sender.GetCommandsNext();
if (commandsNext is null) return Task.CompletedTask;

DiscordMessage? message = e.Message;
if (message.Content is not {Length: > 0} content) return Task.CompletedTask;

string prefix = plugin.Configuration.Get<string>("discord.prefix") ?? "[]";
int commandStart = message.GetStringPrefixLength(MentionUtility.MentionUser(sender.CurrentUser.Id, false) + ' ');
if (commandStart == -1)
{
commandStart = message.GetStringPrefixLength(MentionUtility.MentionUser(sender.CurrentUser.Id) + ' ');
if (commandStart == -1)
{
commandStart = message.GetStringPrefixLength(prefix);
if (commandStart == -1) return Task.CompletedTask;
}
}

prefix = content[..commandStart];
string commandString = content[commandStart..];

Command? command = commandsNext.FindCommand(commandString, out string? args);
if (command is null) return Task.CompletedTask;

CommandContext context = commandsNext.CreateContext(message, prefix, command, args);
Task.Run(async () => await commandsNext.ExecuteCommandAsync(context));
return Task.CompletedTask;
}

private static Type GetPluginType(string name, Assembly assembly, out PluginAttribute pluginAttribute)
{
Type[] pluginTypes = assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(MonoPlugin))).ToArray();
Expand Down Expand Up @@ -366,6 +402,19 @@ private IEnumerable<IPlugin> EnumeratePluginDependencies(Type pluginType)
return new PluginInfo.PluginAuthorInfo(authorAttribute.Name, authorAttribute.Email, authorAttribute.Url);
}

private static CommandsNextExtension? SetupPluginCommands(MonoPlugin plugin)
{
if (plugin.ServiceProvider.GetService<DiscordClient>() is not { } client) return null;

client.MessageCreated += (sender, e) => ClientOnMessageCreated(plugin, sender, e);

return client.UseCommandsNext(new CommandsNextConfiguration
{
ServiceProvider = plugin.ServiceProvider,
UseDefaultCommandHandler = false
});
}

private void SetupPluginDataDirectory(PluginInfo pluginInfo, MonoPlugin instance)
{
var dataDirectory = new DirectoryInfo(Path.Combine(PluginDirectory.FullName, pluginInfo.Name));
Expand Down Expand Up @@ -403,6 +452,9 @@ private static void RegisterCommandEvents(IPlugin plugin, CommandsNextExtension
commandsNext.CommandErrored += (_, args) =>
{
CommandContext context = args.Context;
if (context?.Command is null) return Task.CompletedTask;
if (args.Exception is ChecksFailedException) return Task.CompletedTask; // no need to log ChecksFailedException
var commandName = $"{context.Prefix}{context.Command.Name}";
plugin.Logger.Error(args.Exception, $"An exception was thrown when executing {commandName}");
return Task.CompletedTask;
Expand Down

0 comments on commit 0bb57c7

Please sign in to comment.