Browse Source

Added command categories, removed old permission resolver.

tags/docs-0.9
RogueException 9 years ago
parent
commit
7f8780d749
6 changed files with 136 additions and 67 deletions
  1. +9
    -4
      src/Discord.Net.Commands/Command.cs
  2. +15
    -16
      src/Discord.Net.Commands/CommandBuilder.cs
  3. +13
    -5
      src/Discord.Net.Commands/CommandMap.cs
  4. +2
    -4
      src/Discord.Net.Commands/CommandService.Events.cs
  5. +95
    -36
      src/Discord.Net.Commands/CommandService.cs
  6. +2
    -2
      src/Discord.Net.Commands/CommandServiceConfig.cs

+ 9
- 4
src/Discord.Net.Commands/Command.cs View File

@@ -30,11 +30,11 @@ namespace Discord.Commands
public sealed class Command
{
public string Text { get; }
public int? MinArgs { get; private set; }
public int? MaxArgs { get; private set; }
public int MinPermissions { get; internal set; }
public string Category { get; internal set; }
public bool IsHidden { get; internal set; }
public string Description { get; internal set; }
public int? MinArgs { get; private set; }
public int? MaxArgs { get; private set; }

public IEnumerable<string> Aliases => _aliases;
private string[] _aliases;
@@ -98,7 +98,12 @@ namespace Discord.Commands
{
_handler = e => { func(e); return TaskHelper.CompletedTask; };
}

internal bool CanRun(User user, Channel channel)
{
return true;
}

internal Task Run(CommandEventArgs args)
{
var task = _handler(args);


+ 15
- 16
src/Discord.Net.Commands/CommandBuilder.cs View File

@@ -13,10 +13,11 @@ namespace Discord.Commands
private bool _allowRequired, _isClosed;
private string _prefix;

public CommandBuilder(CommandService service, Command command, string prefix)
internal CommandBuilder(CommandService service, Command command, string prefix, string category)
{
_service = service;
_command = command;
_command.Category = category;
_params = new List<CommandParameter>();
_prefix = prefix;
_allowRequired = true;
@@ -29,6 +30,11 @@ namespace Discord.Commands
_command.SetAliases(aliases);
return this;
}
/*public CommandBuilder Category(string category)
{
_command.Category = category;
return this;
}*/
public CommandBuilder Info(string description)
{
_command.Description = description;
@@ -55,12 +61,6 @@ namespace Discord.Commands
return this;
}

public CommandBuilder MinPermissions(int level)
{
_command.MinPermissions = level;
return this;
}

public void Do(Func<CommandEventArgs, Task> func)
{
_command.SetHandler(func);
@@ -101,23 +101,23 @@ namespace Discord.Commands
{
internal readonly CommandService _service;
private readonly string _prefix;
private int _defaultMinPermissions;
private string _category;

internal CommandGroupBuilder(CommandService service, string prefix, int defaultMinPermissions)
internal CommandGroupBuilder(CommandService service, string prefix)
{
_service = service;
_prefix = prefix;
_defaultMinPermissions = defaultMinPermissions;
}

public void DefaultMinPermissions(int level)
public CommandGroupBuilder Category(string category)
{
_defaultMinPermissions = level;
_category = category;
return this;
}

public CommandGroupBuilder CreateCommandGroup(string cmd, Action<CommandGroupBuilder> config = null)
public CommandGroupBuilder CreateGroup(string cmd, Action<CommandGroupBuilder> config = null)
{
config(new CommandGroupBuilder(_service, _prefix + ' ' + cmd, _defaultMinPermissions));
config(new CommandGroupBuilder(_service, _prefix + ' ' + cmd));
return this;
}
public CommandBuilder CreateCommand()
@@ -125,8 +125,7 @@ namespace Discord.Commands
public CommandBuilder CreateCommand(string cmd)
{
var command = new Command(CommandBuilder.AppendPrefix(_prefix, cmd));
command.MinPermissions = _defaultMinPermissions;
return new CommandBuilder(_service, command, _prefix);
return new CommandBuilder(_service, command, _prefix, _category);
}
}
}

+ 13
- 5
src/Discord.Net.Commands/CommandMap.cs View File

@@ -12,12 +12,11 @@ namespace Discord.Commands

private Command _command;
private readonly Dictionary<string, CommandMap> _items;
private int _minPermission;
private bool _isHidden;

public string Text => _text;
public int MinPermissions => _minPermission;
public bool IsHidden => _isHidden;
public IEnumerable<KeyValuePair<string, CommandMap>> Items => _items;
public IEnumerable<Command> SubCommands => _items.Select(x => x.Value._command).Where(x => x != null);
public IEnumerable<CommandMap> SubGroups => _items.Select(x => x.Value).Where(x => x._items.Count > 0);

@@ -26,7 +25,6 @@ namespace Discord.Commands
_parent = parent;
_text = text;
_items = new Dictionary<string, CommandMap>();
_minPermission = int.MaxValue;
_isHidden = true;
}
@@ -88,8 +86,6 @@ namespace Discord.Commands
{
if (index != parts.Length)
{
if (command.MinPermissions < _minPermission)
_minPermission = command.MinPermissions;
if (!command.IsHidden && _isHidden)
_isHidden = false;

@@ -109,5 +105,17 @@ namespace Discord.Commands
_command = command;
}
}

public bool CanRun(User user, Channel channel)
{
if (_command != null && _command.CanRun(user, channel))
return true;
foreach (var item in _items)
{
if (item.Value.CanRun(user, channel))
return true;
}
return false;
}
}
}

+ 2
- 4
src/Discord.Net.Commands/CommandService.Events.cs View File

@@ -6,18 +6,16 @@ namespace Discord.Commands
{
public Message Message { get; }
public Command Command { get; }
public int? UserPermissions { get; }
public string[] Args { get; }
public User User => Message.User;
public Channel Channel => Message.Channel;
public Server Server => Message.Channel.Server;

public CommandEventArgs(Message message, Command command, int? userPermissions, string[] args)
public CommandEventArgs(Message message, Command command, string[] args)
{
Message = message;
Command = command;
UserPermissions = userPermissions;
Args = args;
}
}
@@ -29,7 +27,7 @@ namespace Discord.Commands
public Exception Exception { get; }

public CommandErrorEventArgs(CommandErrorType errorType, CommandEventArgs baseArgs, Exception ex)
: base(baseArgs.Message, baseArgs.Command, baseArgs.UserPermissions, baseArgs.Args)
: base(baseArgs.Message, baseArgs.Command, baseArgs.Args)
{
Exception = ex;
ErrorType = errorType;


+ 95
- 36
src/Discord.Net.Commands/CommandService.cs View File

@@ -10,27 +10,35 @@ namespace Discord.Commands
public partial class CommandService : IService
{
private DiscordClient _client;
public CommandServiceConfig Config { get; }

CommandServiceConfig Config { get; }
public IEnumerable<Command> Commands => _commands;
private readonly List<Command> _commands;
//AllCommands store a flattened collection of all commands
public IEnumerable<Command> AllCommands => _allCommands;
private readonly List<Command> _allCommands;

//Command map stores all commands by their input text, used for fast resolving and parsing
internal CommandMap Map => _map;
private readonly CommandMap _map;

//Groups store all commands by their module, used for more informative help
internal IEnumerable<CommandMap> Categories => _categories.Values;
private readonly Dictionary<string, CommandMap> _categories;


public CommandService(CommandServiceConfig config)
{
Config = config;
_commands = new List<Command>();
_allCommands = new List<Command>();
_map = new CommandMap(null, null);
}
_categories = new Dictionary<string, CommandMap>();
}

void IService.Install(DiscordClient client)
{
_client = client;
Config.Lock();

if (Config.HelpMode != HelpMode.Disable)
if (Config.HelpMode != HelpMode.Disable)
{
CreateCommand("help")
.Parameter("command", ParameterType.Multiple)
@@ -54,7 +62,7 @@ namespace Discord.Commands

client.MessageReceived += async (s, e) =>
{
if (_commands.Count == 0) return;
if (_allCommands.Count == 0) return;
if (e.Message.IsAuthor) return;

string msg = e.Message.Text;
@@ -75,28 +83,26 @@ namespace Discord.Commands
CommandParser.ParseCommand(msg, _map, out command, out argPos);
if (command == null)
{
CommandEventArgs errorArgs = new CommandEventArgs(e.Message, null, null, null);
CommandEventArgs errorArgs = new CommandEventArgs(e.Message, null, null);
RaiseCommandError(CommandErrorType.UnknownCommand, errorArgs);
return;
}
else
{
int userPermissions = Config.PermissionResolver?.Invoke(e.Message.User) ?? 0;

//Parse arguments
string[] args;
var error = CommandParser.ParseArgs(msg, argPos, command, out args);
if (error != null)
{
var errorArgs = new CommandEventArgs(e.Message, command, userPermissions, null);
var errorArgs = new CommandEventArgs(e.Message, command, null);
RaiseCommandError(error.Value, errorArgs);
return;
}
var eventArgs = new CommandEventArgs(e.Message, command, userPermissions, args);
var eventArgs = new CommandEventArgs(e.Message, command, args);

// Check permissions
if (userPermissions < command.MinPermissions)
if (!command.CanRun(eventArgs.User, eventArgs.Channel))
{
RaiseCommandError(CommandErrorType.BadPermissions, eventArgs);
return;
@@ -118,29 +124,72 @@ namespace Discord.Commands

public Task ShowHelp(User user, Channel channel)
{
int permissions = Config.PermissionResolver(user);

StringBuilder output = new StringBuilder();
output.AppendLine("These are the commands you can use:");
output.Append(string.Join(", ", _map.SubCommands.Distinct()
.Where(x => permissions >= x.MinPermissions && !x.IsHidden)
/*output.AppendLine("These are the commands you can use:");
output.Append(string.Join(", ", _map.SubCommands
.Where(x => x.CanRun(user, channel) && !x.IsHidden)
.Select(x => '`' + x.Text + '`' +
(x.Aliases.Count() > 0 ? ", `" + string.Join("`, `", x.Aliases) + '`' : ""))));
output.AppendLine("\nThese are the groups you can access:");
output.Append(string.Join(", ", _map.SubGroups.Distinct()
.Where(x => permissions >= x.MinPermissions && !x.IsHidden)
.Select(x => '`' + x.Text + '`')));
output.Append(string.Join(", ", _map.SubGroups
.Where(x => /*x.CanRun(user, channel)*//* && !x.IsHidden)
.Select(x => '`' + x.Text + '`')));*/

bool isFirstCategory = true;
foreach (var category in _categories)
{
bool isFirstItem = true;
foreach (var item in category.Value.Items)
{
var map = item.Value;
if (!map.IsHidden && map.CanRun(user, channel))
{
if (isFirstItem)
{
isFirstItem = false;
//This is called for the first item in each category. If we never get here, we dont bother writing the header for a category type (since it's empty)
if (isFirstCategory)
{
isFirstCategory = false;
//Called for the first non-empty category
output.AppendLine("These are the commands you can use:");
}
else
output.AppendLine();
if (category.Key != "")
{
output.Append(Format.Bold(category.Key));
output.Append(": ");
}
}
else
output.Append(", ");
output.Append('`');
output.Append(map.Text);
if (map.Items.Any())
output.Append(@"\*");
output.Append('`');
}
}
}

var chars = Config.CommandChars;
if (chars.Length > 0)
{
if (chars.Length == 1)
output.AppendLine($"\nYou can use `{chars[0]}` to call a command.");
else
output.AppendLine($"\nYou can use `{string.Join(" ", chars.Take(chars.Length - 1))}` or `{chars.Last()}` to call a command.");
}
if (output.Length == 0)
output.Append("There are no commands you have permission to run.");
else
{
output.AppendLine();

var chars = Config.CommandChars;
if (chars.Length > 0)
{
if (chars.Length == 1)
output.AppendLine($"You can use `{chars[0]}` to call a command.");
else
output.AppendLine($"You can use `{string.Join(" ", chars.Take(chars.Length - 1))}` or `{chars.Last()}` to call a command.");
}

output.AppendLine("`help` `<command>` can tell you more about how to use a command.");
output.AppendLine("`help <command>` can tell you more about how to use a command.");
}

return _client.SendMessage(channel, output.ToString());
}
@@ -168,8 +217,7 @@ namespace Discord.Commands
var sub = _map.GetItem(command.Text).SubCommands;
if (sub.Count() > 0)
{
int permissions = Config.PermissionResolver(user);
output.AppendLine("Sub Commands: `" + string.Join("`, `", sub.Where(x => permissions >= x.MinPermissions && !x.IsHidden)
output.AppendLine("Sub Commands: `" + string.Join("`, `", sub.Where(x => x.CanRun(user, channel) && !x.IsHidden)
.Select(x => x.Text.Substring(command.Text.Length + 1))) + '`');
}

@@ -179,17 +227,28 @@ namespace Discord.Commands
return _client.SendMessage(channel, output.ToString());
}

public void CreateCommandGroup(string cmd, Action<CommandGroupBuilder> config = null)
=> config(new CommandGroupBuilder(this, cmd, 0));
public void CreateGroup(string cmd, Action<CommandGroupBuilder> config = null)
{
var builder = new CommandGroupBuilder(this, cmd);
if (config != null)
config(builder);
}
public CommandBuilder CreateCommand(string cmd)
{
var command = new Command(cmd);
return new CommandBuilder(this, command, "");
return new CommandBuilder(this, command, "", "");
}

internal void AddCommand(Command command)
{
_commands.Add(command);
_allCommands.Add(command);
CommandMap category;
string categoryName = command.Category ?? "";
if (!_categories.TryGetValue(categoryName, out category))
{
category = new CommandMap(null, "");
_categories.Add(categoryName, category);
}
_map.AddCommand(command.Text, command);
}
}


+ 2
- 2
src/Discord.Net.Commands/CommandServiceConfig.cs View File

@@ -13,8 +13,8 @@ namespace Discord.Commands
}
public class CommandServiceConfig
{
public Func<User, int> PermissionResolver { get { return _permissionsResolver; } set { SetValue(ref _permissionsResolver, value); } }
private Func<User, int> _permissionsResolver;
/*public Func<User, int> PermissionResolver { get { return _permissionsResolver; } set { SetValue(ref _permissionsResolver, value); } }
private Func<User, int> _permissionsResolver;*/

public char? CommandChar
{


Loading…
Cancel
Save