Browse Source

Added support for multiple commands at the same path

tags/docs-0.9
RogueException 9 years ago
parent
commit
d9759abf4c
3 changed files with 97 additions and 70 deletions
  1. +28
    -22
      src/Discord.Net.Commands/CommandMap.cs
  2. +9
    -6
      src/Discord.Net.Commands/CommandParser.cs
  3. +60
    -42
      src/Discord.Net.Commands/CommandService.cs

+ 28
- 22
src/Discord.Net.Commands/CommandMap.cs View File

@@ -9,14 +9,14 @@ namespace Discord.Commands
private readonly CommandMap _parent; private readonly CommandMap _parent;
private readonly string _name, _fullName; private readonly string _name, _fullName;


private Command _command;
private readonly List<Command> _commands;
private readonly Dictionary<string, CommandMap> _items; private readonly Dictionary<string, CommandMap> _items;
private bool _isHidden; private bool _isHidden;


public string Name => _name; public string Name => _name;
public string FullName => _fullName; public string FullName => _fullName;
public bool IsHidden => _isHidden; public bool IsHidden => _isHidden;
public Command Command => _command;
public IEnumerable<Command> Commands => _commands;
public IEnumerable<CommandMap> SubGroups => _items.Values; public IEnumerable<CommandMap> SubGroups => _items.Values;
/*public IEnumerable<Command> SubCommands => _items.Select(x => x.Value._command).Where(x => x != null); /*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);*/ public IEnumerable<CommandMap> SubGroups => _items.Select(x => x.Value).Where(x => x._items.Count > 0);*/
@@ -27,6 +27,7 @@ namespace Discord.Commands
_name = name; _name = name;
_fullName = fullName; _fullName = fullName;
_items = new Dictionary<string, CommandMap>(); _items = new Dictionary<string, CommandMap>();
_commands = new List<Command>();
_isHidden = true; _isHidden = true;
} }
@@ -48,20 +49,20 @@ namespace Discord.Commands
return this; return this;
} }


public Command GetCommand()
public IEnumerable<Command> GetCommands()
{ {
if (_command != null)
return _command;
if (_commands.Count > 0)
return _commands;
else if (_parent != null) else if (_parent != null)
return _parent.GetCommand();
return _parent.GetCommands();
else else
return null; return null;
} }
public Command GetCommand(string text)
public IEnumerable<Command> GetCommands(string text)
{ {
return GetCommand(0, text.Split(' '));
return GetCommands(0, text.Split(' '));
} }
public Command GetCommand(int index, string[] parts)
public IEnumerable<Command> GetCommands(int index, string[] parts)
{ {
if (index != parts.Length) if (index != parts.Length)
{ {
@@ -69,14 +70,14 @@ namespace Discord.Commands
CommandMap nextGroup; CommandMap nextGroup;
if (_items.TryGetValue(nextPart, out nextGroup)) if (_items.TryGetValue(nextPart, out nextGroup))
{ {
var cmd = nextGroup.GetCommand(index + 1, parts);
var cmd = nextGroup.GetCommands(index + 1, parts);
if (cmd != null) if (cmd != null)
return cmd; return cmd;
} }
} }


if (_command != null)
return _command;
if (_commands != null)
return _commands;
return null; return null;
} }


@@ -102,21 +103,26 @@ namespace Discord.Commands
nextGroup.AddCommand(index + 1, parts, command); nextGroup.AddCommand(index + 1, parts, command);
} }
else else
{
if (_command != null)
throw new InvalidOperationException("A command has already been added with this path.");
_command = command;
}
_commands.Add(command);
} }


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


+ 9
- 6
src/Discord.Net.Commands/CommandParser.cs View File

@@ -12,13 +12,13 @@ namespace Discord.Commands
DoubleQuotedParameter DoubleQuotedParameter
} }


public static bool ParseCommand(string input, CommandMap map, out Command command, out int endPos)
public static bool ParseCommand(string input, CommandMap map, out IEnumerable<Command> commands, out int endPos)
{ {
int startPosition = 0; int startPosition = 0;
int endPosition = 0; int endPosition = 0;
int inputLength = input.Length; int inputLength = input.Length;
bool isEscaped = false; bool isEscaped = false;
command = null;
commands = null;
endPos = 0; endPos = 0;


if (input == "") if (input == "")
@@ -52,8 +52,8 @@ namespace Discord.Commands
} }
} }
} }
command = map.GetCommand(); //Work our way backwards to find a command that matches our input
return command != null;
commands = map.GetCommands(); //Work our way backwards to find a command that matches our input
return commands != null;
} }


//TODO: Check support for escaping //TODO: Check support for escaping
@@ -78,6 +78,8 @@ namespace Discord.Commands
{ {
if (startPosition == endPosition && (parameter == null || parameter.Type != ParameterType.Multiple)) //Is first char of a new arg if (startPosition == endPosition && (parameter == null || parameter.Type != ParameterType.Multiple)) //Is first char of a new arg
{ {
if (argList.Count >= expectedArgs.Length)
return CommandErrorType.BadArgCount; //Too many args
parameter = expectedArgs[argList.Count]; parameter = expectedArgs[argList.Count];
if (parameter.Type == ParameterType.Unparsed) if (parameter.Type == ParameterType.Unparsed)
{ {
@@ -144,6 +146,7 @@ namespace Discord.Commands
} }
} }


//Too few args
for (int i = argList.Count; i < expectedArgs.Length; i++) for (int i = argList.Count; i < expectedArgs.Length; i++)
{ {
var param = expectedArgs[i]; var param = expectedArgs[i];
@@ -158,11 +161,11 @@ namespace Discord.Commands
} }
} }


if (argList.Count > expectedArgs.Length)
/*if (argList.Count > expectedArgs.Length)
{ {
if (expectedArgs.Length == 0 || expectedArgs[expectedArgs.Length - 1].Type != ParameterType.Multiple) if (expectedArgs.Length == 0 || expectedArgs[expectedArgs.Length - 1].Type != ParameterType.Multiple)
return CommandErrorType.BadArgCount; return CommandErrorType.BadArgCount;
}
}*/


args = argList.ToArray(); args = argList.ToArray();
return null; return null;


+ 60
- 42
src/Discord.Net.Commands/CommandService.cs View File

@@ -88,10 +88,10 @@ After:
} }


//Parse command //Parse command
Command command;
IEnumerable<Command> commands;
int argPos; int argPos;
CommandParser.ParseCommand(msg, _map, out command, out argPos);
if (command == null)
CommandParser.ParseCommand(msg, _map, out commands, out argPos);
if (commands == null)
{ {
CommandEventArgs errorArgs = new CommandEventArgs(e.Message, null, null); CommandEventArgs errorArgs = new CommandEventArgs(e.Message, null, null);
RaiseCommandError(CommandErrorType.UnknownCommand, errorArgs); RaiseCommandError(CommandErrorType.UnknownCommand, errorArgs);
@@ -99,35 +99,46 @@ After:
} }
else else
{ {
//Parse arguments
string[] args;
var error = CommandParser.ParseArgs(msg, argPos, command, out args);
if (error != null)
foreach (var command in commands)
{ {
var errorArgs = new CommandEventArgs(e.Message, command, null);
RaiseCommandError(error.Value, errorArgs);
return;
}
var eventArgs = new CommandEventArgs(e.Message, command, args);
//Parse arguments
string[] args;
var error = CommandParser.ParseArgs(msg, argPos, command, out args);
if (error != null)
{
if (error == CommandErrorType.BadArgCount)
continue;
else
{
var errorArgs = new CommandEventArgs(e.Message, command, null);
RaiseCommandError(error.Value, errorArgs);
return;
}
}


// Check permissions
if (!command.CanRun(eventArgs.User, eventArgs.Channel))
{
RaiseCommandError(CommandErrorType.BadPermissions, eventArgs);
return;
}
var eventArgs = new CommandEventArgs(e.Message, command, args);


// Run the command
try
{
RaiseRanCommand(eventArgs);
await command.Run(eventArgs).ConfigureAwait(false);
}
catch (Exception ex)
{
RaiseCommandError(CommandErrorType.Exception, eventArgs, ex);
// Check permissions
if (!command.CanRun(eventArgs.User, eventArgs.Channel))
{
RaiseCommandError(CommandErrorType.BadPermissions, eventArgs);
return;
}

// Run the command
try
{
RaiseRanCommand(eventArgs);
await command.Run(eventArgs).ConfigureAwait(false);
}
catch (Exception ex)
{
RaiseCommandError(CommandErrorType.Exception, eventArgs, ex);
}
return;
} }
var errorArgs2 = new CommandEventArgs(e.Message, null, null);
RaiseCommandError(CommandErrorType.BadArgCount, errorArgs2);
} }
}; };
} }
@@ -208,9 +219,19 @@ After:
{ {
StringBuilder output = new StringBuilder(); StringBuilder output = new StringBuilder();


Command cmd = map.Command;
if (cmd != null)
ShowCommandHelpInternal(cmd, user, channel, output);
IEnumerable<Command> cmds = map.Commands;
bool isFirstCmd = true;
if (cmds != null)
{
foreach (var cmd in cmds)
{
if (isFirstCmd)
isFirstCmd = false;
/*else
output.AppendLine();*/
ShowCommandHelpInternal(cmd, user, channel, output);
}
}
else else
{ {
output.Append('`'); output.Append('`');
@@ -218,12 +239,12 @@ After:
output.Append("`\n"); output.Append("`\n");
} }


bool isFirst = true;
bool isFirstSubCmd = true;
foreach (var subCmd in map.SubGroups.Where(x => x.CanRun(user, channel) && !x.IsHidden)) foreach (var subCmd in map.SubGroups.Where(x => x.CanRun(user, channel) && !x.IsHidden))
{ {
if (isFirst)
if (isFirstSubCmd)
{ {
isFirst = false;
isFirstSubCmd = false;
output.AppendLine("Sub Commands: "); output.AppendLine("Sub Commands: ");
} }
else else
@@ -235,7 +256,7 @@ After:
output.Append('`'); output.Append('`');
} }


if (isFirst)
if (isFirstCmd && isFirstSubCmd) //Had no commands and no subcommands
{ {
output.Clear(); output.Clear();
output.AppendLine("You do not have permission to access this command."); output.AppendLine("You do not have permission to access this command.");
@@ -246,17 +267,14 @@ After:
public Task ShowCommandHelp(Command command, User user, Channel channel, Channel replyChannel = null) public Task ShowCommandHelp(Command command, User user, Channel channel, Channel replyChannel = null)
{ {
StringBuilder output = new StringBuilder(); StringBuilder output = new StringBuilder();
ShowCommandHelpInternal(command, user, channel, output);
if (!command.CanRun(user, channel))
output.AppendLine("You do not have permission to access this command.");
else
ShowCommandHelpInternal(command, user, channel, output);
return _client.SendMessage(replyChannel ?? channel, output.ToString()); return _client.SendMessage(replyChannel ?? channel, output.ToString());
} }
private void ShowCommandHelpInternal(Command command, User user, Channel channel, StringBuilder output) private void ShowCommandHelpInternal(Command command, User user, Channel channel, StringBuilder output)
{ {
if (!command.CanRun(user, channel))
{
output.AppendLine("You do not have permission to access this command.");
return;
}

output.Append('`'); output.Append('`');
output.Append(command.Text); output.Append(command.Text);
foreach (var param in command.Parameters) foreach (var param in command.Parameters)


Loading…
Cancel
Save