@@ -43,6 +43,9 @@ | |||||
<Compile Include="..\Discord.Net.Commands\CommandBuilder.cs"> | <Compile Include="..\Discord.Net.Commands\CommandBuilder.cs"> | ||||
<Link>CommandBuilder.cs</Link> | <Link>CommandBuilder.cs</Link> | ||||
</Compile> | </Compile> | ||||
<Compile Include="..\Discord.Net.Commands\CommandMap.cs"> | |||||
<Link>CommandMap.cs</Link> | |||||
</Compile> | |||||
<Compile Include="..\Discord.Net.Commands\CommandParser.cs"> | <Compile Include="..\Discord.Net.Commands\CommandParser.cs"> | ||||
<Link>CommandParser.cs</Link> | <Link>CommandParser.cs</Link> | ||||
</Compile> | </Compile> | ||||
@@ -1,23 +1,102 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
namespace Discord.Commands | namespace Discord.Commands | ||||
{ | { | ||||
public sealed class CommandParameter | |||||
{ | |||||
public string Name { get; } | |||||
public bool IsOptional { get; } | |||||
public bool IsCatchAll { get; } | |||||
public CommandParameter(string name, bool isOptional, bool isCatchAll) | |||||
{ | |||||
Name = name; | |||||
IsOptional = isOptional; | |||||
IsCatchAll = isCatchAll; | |||||
} | |||||
} | |||||
public sealed class Command | public sealed class Command | ||||
{ | { | ||||
public string Text { get; } | public string Text { get; } | ||||
public int? MinArgs { get; internal set; } | |||||
public int? MaxArgs { get; internal set; } | |||||
public int? MinArgs { get; private set; } | |||||
public int? MaxArgs { get; private set; } | |||||
public int MinPerms { get; internal set; } | public int MinPerms { get; internal set; } | ||||
public bool IsHidden { get; internal set; } | public bool IsHidden { get; internal set; } | ||||
public string Description { get; internal set; } | public string Description { get; internal set; } | ||||
internal Func<CommandEventArgs, Task> Handler; | |||||
public IEnumerable<string> Aliases => _aliases; | |||||
private string[] _aliases; | |||||
public IEnumerable<CommandParameter> Parameters => _parameters; | |||||
private CommandParameter[] _parameters; | |||||
private Func<CommandEventArgs, Task> _handler; | |||||
internal Command(string text) | internal Command(string text) | ||||
{ | { | ||||
Text = text; | Text = text; | ||||
IsHidden = false; // Set false by default to avoid null error | |||||
Description = "No description set for this command."; | |||||
IsHidden = false; | |||||
_aliases = new string[0]; | |||||
_parameters = new CommandParameter[0]; | |||||
} | |||||
internal void SetAliases(string[] aliases) | |||||
{ | |||||
_aliases = aliases; | |||||
} | |||||
internal void SetParameters(CommandParameter[] parameters) | |||||
{ | |||||
_parameters = parameters; | |||||
if (parameters != null) | |||||
{ | |||||
if (parameters.Length == 0) | |||||
{ | |||||
MinArgs = 0; | |||||
MaxArgs = 0; | |||||
} | |||||
else | |||||
{ | |||||
if (parameters[parameters.Length - 1].IsCatchAll) | |||||
MaxArgs = null; | |||||
else | |||||
MaxArgs = parameters.Length; | |||||
int? optionalStart = null; | |||||
for (int i = parameters.Length - 1; i >= 0; i--) | |||||
{ | |||||
if (parameters[i].IsOptional) | |||||
optionalStart = i; | |||||
else | |||||
break; | |||||
} | |||||
if (optionalStart == null) | |||||
MinArgs = MaxArgs; | |||||
else | |||||
MinArgs = optionalStart.Value; | |||||
} | |||||
} | |||||
} | |||||
internal void SetHandler(Func<CommandEventArgs, Task> func) | |||||
{ | |||||
_handler = func; | |||||
} | |||||
internal void SetHandler(Action<CommandEventArgs> func) | |||||
{ | |||||
_handler = e => { func(e); return TaskHelper.CompletedTask; }; | |||||
} | |||||
internal Task Run(CommandEventArgs args) | |||||
{ | |||||
var task = _handler(args); | |||||
if (task != null) | |||||
return task; | |||||
else | |||||
return TaskHelper.CompletedTask; | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -1,50 +1,55 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
namespace Discord.Commands | namespace Discord.Commands | ||||
{ | { | ||||
public sealed class CommandBuilder | public sealed class CommandBuilder | ||||
{ | { | ||||
private readonly CommandsPlugin _plugin; | |||||
private readonly Command _command; | private readonly Command _command; | ||||
public CommandBuilder(Command command) | |||||
private List<CommandParameter> _params; | |||||
private bool _hasOptional, _hasCatchAll; | |||||
private string _prefix; | |||||
public CommandBuilder(CommandsPlugin plugin, Command command, string prefix) | |||||
{ | { | ||||
_plugin = plugin; | |||||
_command = command; | _command = command; | ||||
} | |||||
public CommandBuilder ArgsEqual(int argCount) | |||||
{ | |||||
_command.MinArgs = argCount; | |||||
_command.MaxArgs = argCount; | |||||
return this; | |||||
} | |||||
public CommandBuilder ArgsAtLeast(int minArgCount) | |||||
{ | |||||
_command.MinArgs = minArgCount; | |||||
_command.MaxArgs = null; | |||||
return this; | |||||
} | |||||
public CommandBuilder ArgsAtMost(int maxArgCount) | |||||
_params = new List<CommandParameter>(); | |||||
_prefix = prefix; | |||||
} | |||||
public CommandBuilder Alias(params string[] aliases) | |||||
{ | { | ||||
_command.MinArgs = null; | |||||
_command.MaxArgs = maxArgCount; | |||||
aliases = aliases.Select(x => AppendPrefix(_prefix, x)).ToArray(); | |||||
_command.SetAliases(aliases); | |||||
return this; | return this; | ||||
} | } | ||||
public CommandBuilder ArgsBetween(int minArgCount, int maxArgCount) | |||||
public CommandBuilder Info(string description) | |||||
{ | { | ||||
_command.MinArgs = minArgCount; | |||||
_command.MaxArgs = maxArgCount; | |||||
_command.Description = description; | |||||
return this; | return this; | ||||
} | } | ||||
public CommandBuilder NoArgs() | |||||
public CommandBuilder Parameter(string name, bool isOptional = false, bool isCatchAll = false) | |||||
{ | { | ||||
_command.MinArgs = 0; | |||||
_command.MaxArgs = 0; | |||||
if (_hasCatchAll) | |||||
throw new Exception("No parameters may be added after the catch-all"); | |||||
if (_hasOptional && isOptional) | |||||
throw new Exception("Non-optional parameters may not be added after an optional one"); | |||||
_params.Add(new CommandParameter(name, isOptional, isCatchAll)); | |||||
if (isOptional) | |||||
_hasOptional = true; | |||||
if (isCatchAll) | |||||
_hasCatchAll = true; | |||||
return this; | return this; | ||||
} | } | ||||
public CommandBuilder AnyArgs() | |||||
public CommandBuilder IsHidden() | |||||
{ | { | ||||
_command.MinArgs = null; | |||||
_command.MaxArgs = null; | |||||
_command.IsHidden = true; | |||||
return this; | return this; | ||||
} | } | ||||
@@ -54,32 +59,45 @@ namespace Discord.Commands | |||||
return this; | return this; | ||||
} | } | ||||
public CommandBuilder Desc(string desc) | |||||
{ | |||||
_command.Description = desc; | |||||
return this; | |||||
} | |||||
public CommandBuilder IsHidden() | |||||
{ | |||||
_command.IsHidden = true; | |||||
return this; | |||||
} | |||||
public CommandBuilder Do(Func<CommandEventArgs, Task> func) | |||||
public void Do(Func<CommandEventArgs, Task> func) | |||||
{ | { | ||||
_command.Handler = func; | |||||
return this; | |||||
_command.SetHandler(func); | |||||
Build(); | |||||
} | } | ||||
public CommandBuilder Do(Action<CommandEventArgs> func) | |||||
public void Do(Action<CommandEventArgs> func) | |||||
{ | { | ||||
_command.Handler = e => { func(e); return TaskHelper.CompletedTask; }; | |||||
return this; | |||||
_command.SetHandler(func); | |||||
Build(); | |||||
} | |||||
private void Build() | |||||
{ | |||||
_command.SetParameters(_params.ToArray()); | |||||
foreach (var alias in _command.Aliases) | |||||
_plugin.Map.AddCommand(alias, _command); | |||||
_plugin.AddCommand(_command); | |||||
} | |||||
internal static string AppendPrefix(string prefix, string cmd) | |||||
{ | |||||
if (cmd != "") | |||||
{ | |||||
if (prefix != "") | |||||
return prefix + ' ' + cmd; | |||||
else | |||||
return cmd; | |||||
} | |||||
else | |||||
{ | |||||
if (prefix != "") | |||||
return prefix; | |||||
else | |||||
throw new ArgumentOutOfRangeException(nameof(cmd)); | |||||
} | |||||
} | } | ||||
} | } | ||||
public sealed class CommandGroupBuilder | public sealed class CommandGroupBuilder | ||||
{ | { | ||||
private readonly CommandsPlugin _plugin; | |||||
internal readonly CommandsPlugin _plugin; | |||||
private readonly string _prefix; | private readonly string _prefix; | ||||
private int _defaultMinPermissions; | private int _defaultMinPermissions; | ||||
@@ -104,25 +122,9 @@ namespace Discord.Commands | |||||
=> CreateCommand(""); | => CreateCommand(""); | ||||
public CommandBuilder CreateCommand(string cmd) | public CommandBuilder CreateCommand(string cmd) | ||||
{ | { | ||||
string text; | |||||
if (cmd != "") | |||||
{ | |||||
if (_prefix != "") | |||||
text = _prefix + ' ' + cmd; | |||||
else | |||||
text = cmd; | |||||
} | |||||
else | |||||
{ | |||||
if (_prefix != "") | |||||
text = _prefix; | |||||
else | |||||
throw new ArgumentOutOfRangeException(nameof(cmd)); | |||||
} | |||||
var command = new Command(text); | |||||
var command = new Command(CommandBuilder.AppendPrefix(_prefix, cmd)); | |||||
command.MinPerms = _defaultMinPermissions; | command.MinPerms = _defaultMinPermissions; | ||||
_plugin.AddCommand(command); | |||||
return new CommandBuilder(command); | |||||
return new CommandBuilder(_plugin, command, _prefix); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -0,0 +1,84 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
namespace Discord.Commands | |||||
{ | |||||
internal class CommandMap | |||||
{ | |||||
private CommandMap _parent; | |||||
private Command _command; | |||||
private readonly Dictionary<string, CommandMap> _subCommands; | |||||
public CommandMap(CommandMap parent) | |||||
{ | |||||
_parent = parent; | |||||
_subCommands = new Dictionary<string, CommandMap>(); | |||||
} | |||||
public CommandMap GetMap(string text) | |||||
{ | |||||
CommandMap map; | |||||
if (_subCommands.TryGetValue(text, out map)) | |||||
return map; | |||||
else | |||||
return null; | |||||
} | |||||
public Command GetCommand() | |||||
{ | |||||
if (_command != null) | |||||
return _command; | |||||
else if (_parent != null) | |||||
return _parent.GetCommand(); | |||||
else | |||||
return null; | |||||
} | |||||
public Command GetCommand(string text) | |||||
{ | |||||
return GetCommand(0, text.Split(' ')); | |||||
} | |||||
public Command GetCommand(int index, string[] parts) | |||||
{ | |||||
if (index != parts.Length) | |||||
{ | |||||
string nextPart = parts[index]; | |||||
CommandMap nextGroup; | |||||
if (_subCommands.TryGetValue(nextPart, out nextGroup)) | |||||
{ | |||||
var cmd = nextGroup.GetCommand(index + 1, parts); | |||||
if (cmd != null) | |||||
return cmd; | |||||
} | |||||
} | |||||
if (_command != null) | |||||
return _command; | |||||
return null; | |||||
} | |||||
public void AddCommand(string text, Command command) | |||||
{ | |||||
AddCommand(0, text.Split(' '), command); | |||||
} | |||||
public void AddCommand(int index, string[] parts, Command command) | |||||
{ | |||||
if (index != parts.Length) | |||||
{ | |||||
string nextPart = parts[index]; | |||||
CommandMap nextGroup; | |||||
if (!_subCommands.TryGetValue(nextPart, out nextGroup)) | |||||
{ | |||||
nextGroup = new CommandMap(this); | |||||
_subCommands.Add(nextPart, nextGroup); | |||||
} | |||||
nextGroup.AddCommand(index + 1, parts, command); | |||||
} | |||||
else | |||||
{ | |||||
if (_command != null) | |||||
throw new InvalidOperationException("A command has already been added with this path."); | |||||
_command = command; | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -15,37 +15,69 @@ namespace Discord.Commands | |||||
} | } | ||||
//TODO: Check support for escaping | //TODO: Check support for escaping | ||||
public static class CommandParser | |||||
internal static class CommandParser | |||||
{ | { | ||||
private enum CommandParserPart | private enum CommandParserPart | ||||
{ | { | ||||
None, | None, | ||||
CommandName, | |||||
Parameter, | Parameter, | ||||
QuotedParameter, | QuotedParameter, | ||||
DoubleQuotedParameter | DoubleQuotedParameter | ||||
} | } | ||||
public static bool Parse(string input, out string command, out CommandPart[] args) | |||||
public static bool ParseCommand(string input, CommandMap map, out Command command, out int endPos) | |||||
{ | { | ||||
return Parse(input, out command, out args, true); | |||||
} | |||||
public static bool ParseArgs(string input, out CommandPart[] args) | |||||
{ | |||||
string ignored; | |||||
return Parse(input, out ignored, out args, false); | |||||
int startPosition = 0; | |||||
int endPosition = 0; | |||||
int inputLength = input.Length; | |||||
bool isEscaped = false; | |||||
command = null; | |||||
endPos = 0; | |||||
if (input == "") | |||||
return false; | |||||
while (endPosition < inputLength) | |||||
{ | |||||
char currentChar = input[endPosition++]; | |||||
if (isEscaped) | |||||
isEscaped = false; | |||||
else if (currentChar == '\\') | |||||
isEscaped = true; | |||||
if ((!isEscaped && currentChar == ' ') || endPosition >= inputLength) | |||||
{ | |||||
int length = (currentChar == ' ' ? endPosition - 1 : endPosition) - startPosition; | |||||
string temp = input.Substring(startPosition, length); | |||||
if (temp == "") | |||||
startPosition = endPosition; | |||||
else | |||||
{ | |||||
var newMap = map.GetMap(temp); | |||||
if (newMap != null) | |||||
{ | |||||
map = newMap; | |||||
endPos = endPosition; | |||||
} | |||||
else | |||||
break; | |||||
startPosition = endPosition; | |||||
} | |||||
} | |||||
} | |||||
command = map.GetCommand(); //Work our way backwards to find a command that matches our input | |||||
return command != null; | |||||
} | } | ||||
private static bool Parse(string input, out string command, out CommandPart[] args, bool parseCommand) | |||||
public static bool ParseArgs(string input, int startPos, Command command, out CommandPart[] args) | |||||
{ | { | ||||
CommandParserPart currentPart = parseCommand ? CommandParserPart.CommandName : CommandParserPart.None; | |||||
int startPosition = 0; | |||||
int endPosition = 0; | |||||
CommandParserPart currentPart = CommandParserPart.None; | |||||
int startPosition = startPos; | |||||
int endPosition = startPos; | |||||
int inputLength = input.Length; | int inputLength = input.Length; | ||||
bool isEscaped = false; | bool isEscaped = false; | ||||
List<CommandPart> argList = new List<CommandPart>(); | List<CommandPart> argList = new List<CommandPart>(); | ||||
command = null; | |||||
args = null; | args = null; | ||||
if (input == "") | if (input == "") | ||||
@@ -61,21 +93,6 @@ namespace Discord.Commands | |||||
switch (currentPart) | switch (currentPart) | ||||
{ | { | ||||
case CommandParserPart.CommandName: | |||||
if ((!isEscaped && currentChar == ' ') || endPosition >= inputLength) | |||||
{ | |||||
int length = (currentChar == ' ' ? endPosition - 1 : endPosition) - startPosition; | |||||
string temp = input.Substring(startPosition, length); | |||||
if (temp == "") | |||||
startPosition = endPosition; | |||||
else | |||||
{ | |||||
currentPart = CommandParserPart.None; | |||||
command = temp; | |||||
startPosition = endPosition; | |||||
} | |||||
} | |||||
break; | |||||
case CommandParserPart.None: | case CommandParserPart.None: | ||||
if ((!isEscaped && currentChar == '\"')) | if ((!isEscaped && currentChar == '\"')) | ||||
{ | { | ||||
@@ -126,9 +143,6 @@ namespace Discord.Commands | |||||
} | } | ||||
} | } | ||||
if (parseCommand && (command == null || command == "")) | |||||
return false; | |||||
args = argList.ToArray(); | args = argList.ToArray(); | ||||
return true; | return true; | ||||
} | } | ||||
@@ -22,7 +22,7 @@ namespace Discord.Commands | |||||
} | } | ||||
} | } | ||||
public enum CommandErrorType { Exception, UnknownCommand, BadPermissions, BadArgCount } | |||||
public enum CommandErrorType { Exception, UnknownCommand, BadPermissions, BadArgCount, InvalidInput } | |||||
public class CommandErrorEventArgs : CommandEventArgs | public class CommandErrorEventArgs : CommandEventArgs | ||||
{ | { | ||||
public CommandErrorType ErrorType { get; } | public CommandErrorType ErrorType { get; } | ||||
@@ -10,29 +10,30 @@ namespace Discord.Commands | |||||
public partial class CommandsPlugin | public partial class CommandsPlugin | ||||
{ | { | ||||
private readonly DiscordClient _client; | private readonly DiscordClient _client; | ||||
private Func<User, int> _getPermissions; | |||||
private Dictionary<string, Command> _commands; | |||||
private readonly Func<User, int> _getPermissions; | |||||
public Dictionary<string, Command> Commands => _commands; | |||||
public IEnumerable<Command> Commands => _commands; | |||||
private readonly List<Command> _commands; | |||||
internal CommandMap Map => _map; | |||||
private readonly CommandMap _map; | |||||
public char CommandChar { get { return CommandChars[0]; } set { CommandChars = new List<char> { value }; } } // This could possibly be removed entirely. Not sure. | |||||
public List<char> CommandChars { get; set; } | |||||
public bool UseCommandChar { get; set; } | |||||
public IEnumerable<char> CommandChars { get { return _commandChars; } set { _commandChars = value.ToArray(); } } | |||||
private char[] _commandChars; | |||||
public bool RequireCommandCharInPublic { get; set; } | public bool RequireCommandCharInPublic { get; set; } | ||||
public bool RequireCommandCharInPrivate { get; set; } | public bool RequireCommandCharInPrivate { get; set; } | ||||
public bool HelpInPublic { get; set; } | public bool HelpInPublic { get; set; } | ||||
public CommandsPlugin(DiscordClient client, Func<User, int> getPermissions = null, bool builtInHelp = false) | public CommandsPlugin(DiscordClient client, Func<User, int> getPermissions = null, bool builtInHelp = false) | ||||
{ | { | ||||
_client = client; // Wait why is this even set | |||||
_client = client; | |||||
_getPermissions = getPermissions; | _getPermissions = getPermissions; | ||||
_commands = new Dictionary<string, Command>(); | |||||
_commands = new List<Command>(); | |||||
_map = new CommandMap(null); | |||||
CommandChar = '!'; // Kept around to keep from possibly throwing an error. Might not be necessary. | |||||
CommandChars = new List<char> { '!', '?', '/' }; | |||||
UseCommandChar = true; | |||||
_commandChars = new char[] { '!' }; | |||||
RequireCommandCharInPublic = true; | RequireCommandCharInPublic = true; | ||||
RequireCommandCharInPrivate = true; | RequireCommandCharInPrivate = true; | ||||
HelpInPublic = true; | HelpInPublic = true; | ||||
@@ -40,9 +41,9 @@ namespace Discord.Commands | |||||
if (builtInHelp) | if (builtInHelp) | ||||
{ | { | ||||
CreateCommand("help") | CreateCommand("help") | ||||
.ArgsBetween(0, 1) | |||||
.Parameter("command", isOptional: true) | |||||
.IsHidden() | .IsHidden() | ||||
.Desc("Returns information about commands.") | |||||
.Info("Returns information about commands.") | |||||
.Do(async e => | .Do(async e => | ||||
{ | { | ||||
if (e.Command.Text != "help") | if (e.Command.Text != "help") | ||||
@@ -50,29 +51,18 @@ namespace Discord.Commands | |||||
else | else | ||||
{ | { | ||||
if (e.Args == null) | if (e.Args == null) | ||||
{ | |||||
StringBuilder output = new StringBuilder(); | |||||
bool first = true; | |||||
{ | |||||
int permissions = getPermissions(e.User); | |||||
StringBuilder output = new StringBuilder(); | |||||
output.AppendLine("These are the commands you can use:"); | output.AppendLine("These are the commands you can use:"); | ||||
output.Append("`"); | output.Append("`"); | ||||
int permissions = getPermissions(e.User); | |||||
foreach (KeyValuePair<string, Command> k in _commands) | |||||
{ | |||||
if (permissions >= k.Value.MinPerms && !k.Value.IsHidden) | |||||
if (first) | |||||
{ | |||||
output.Append(k.Key); | |||||
first = false; | |||||
} | |||||
else | |||||
output.Append($", {k.Key}"); | |||||
} | |||||
output.Append(string.Join(", ", _commands.Select(x => permissions >= x.MinPerms && !x.IsHidden))); | |||||
output.Append("`"); | output.Append("`"); | ||||
if (CommandChars.Count == 1) | |||||
output.AppendLine($"{Environment.NewLine}You can use `{CommandChars[0]}` to call a command."); | |||||
if (_commandChars.Length == 1) | |||||
output.AppendLine($"\nYou can use `{_commandChars[0]}` to call a command."); | |||||
else | else | ||||
output.AppendLine($"{Environment.NewLine}You can use `{String.Join(" ", CommandChars.Take(CommandChars.Count - 1))}` and `{CommandChars.Last()}` to call a command."); | |||||
output.AppendLine($"\nYou can use `{string.Join(" ", CommandChars.Take(_commandChars.Length - 1))}` and `{_commandChars.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."); | ||||
@@ -80,8 +70,9 @@ namespace Discord.Commands | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
if (_commands.ContainsKey(e.Args[0])) | |||||
await Reply(e, CommandDetails(_commands[e.Args[0]])); | |||||
var cmd = _map.GetCommand(e.Args[0]); | |||||
if (cmd != null) | |||||
await Reply(e, CommandDetails(cmd)); | |||||
else | else | ||||
await Reply(e, $"`{e.Args[0]}` is not a valid command."); | await Reply(e, $"`{e.Args[0]}` is not a valid command."); | ||||
} | } | ||||
@@ -99,7 +90,7 @@ namespace Discord.Commands | |||||
string msg = e.Message.Text; | string msg = e.Message.Text; | ||||
if (msg.Length == 0) return; | if (msg.Length == 0) return; | ||||
if (UseCommandChar) | |||||
if (_commandChars.Length > 0) | |||||
{ | { | ||||
bool isPrivate = e.Message.Channel.IsPrivate; | bool isPrivate = e.Message.Channel.IsPrivate; | ||||
bool hasCommandChar = CommandChars.Contains(msg[0]); | bool hasCommandChar = CommandChars.Contains(msg[0]); | ||||
@@ -112,44 +103,41 @@ namespace Discord.Commands | |||||
return; // Same, but public. | return; // Same, but public. | ||||
} | } | ||||
string cmd; | |||||
CommandPart[] args; | |||||
if (!CommandParser.Parse(msg, out cmd, out args)) | |||||
return; | |||||
if (_commands.ContainsKey(cmd)) | |||||
{ | |||||
Command comm = _commands[cmd]; | |||||
//Clean args | |||||
//Parse command | |||||
Command command; | |||||
int argPos; | |||||
CommandParser.ParseCommand(msg, _map, out command, out argPos); | |||||
if (command == null) | |||||
{ | |||||
CommandEventArgs errorArgs = new CommandEventArgs(e.Message, null, null, null); | |||||
RaiseCommandError(CommandErrorType.UnknownCommand, errorArgs); | |||||
return; | |||||
} | |||||
else | |||||
{ | |||||
//Parse arguments | |||||
CommandPart[] args; | |||||
if (!CommandParser.ParseArgs(msg, argPos, command, out args)) | |||||
{ | |||||
CommandEventArgs errorArgs = new CommandEventArgs(e.Message, null, null, null); | |||||
RaiseCommandError(CommandErrorType.InvalidInput, errorArgs); | |||||
return; | |||||
} | |||||
int argCount = args.Length; | int argCount = args.Length; | ||||
string[] newArgs = null; | |||||
if (comm.MaxArgs != null && argCount > 0) | |||||
{ | |||||
newArgs = new string[(int)comm.MaxArgs]; | |||||
for (int j = 0; j < newArgs.Length; j++) | |||||
newArgs[j] = args[j].Value; | |||||
} | |||||
else if (comm.MaxArgs == null && comm.MinArgs == null) | |||||
{ | |||||
newArgs = new string[argCount]; | |||||
for (int j = 0; j < newArgs.Length; j++) | |||||
newArgs[j] = args[j].Value; | |||||
} | |||||
//Get information for the rest of the steps | |||||
int userPermissions = _getPermissions != null ? _getPermissions(e.Message.User) : 0; | int userPermissions = _getPermissions != null ? _getPermissions(e.Message.User) : 0; | ||||
var eventArgs = new CommandEventArgs(e.Message, comm, userPermissions, newArgs); | |||||
var eventArgs = new CommandEventArgs(e.Message, command, userPermissions, args.Select(x => x.Value).ToArray()); | |||||
// Check permissions | // Check permissions | ||||
if (userPermissions < comm.MinPerms) | |||||
if (userPermissions < command.MinPerms) | |||||
{ | { | ||||
RaiseCommandError(CommandErrorType.BadPermissions, eventArgs); | RaiseCommandError(CommandErrorType.BadPermissions, eventArgs); | ||||
return; | return; | ||||
} | } | ||||
//Check arg count | //Check arg count | ||||
if (argCount < comm.MinArgs) | |||||
if (argCount < command.MinArgs) | |||||
{ | { | ||||
RaiseCommandError(CommandErrorType.BadArgCount, eventArgs); | RaiseCommandError(CommandErrorType.BadArgCount, eventArgs); | ||||
return; | return; | ||||
@@ -159,21 +147,13 @@ namespace Discord.Commands | |||||
try | try | ||||
{ | { | ||||
RaiseRanCommand(eventArgs); | RaiseRanCommand(eventArgs); | ||||
var task = comm.Handler(eventArgs); | |||||
if (task != null) | |||||
await task.ConfigureAwait(false); | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
RaiseCommandError(CommandErrorType.Exception, eventArgs, ex); | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
CommandEventArgs eventArgs = new CommandEventArgs(e.Message, null, null, null); | |||||
RaiseCommandError(CommandErrorType.UnknownCommand, eventArgs); | |||||
return; | |||||
} | |||||
await command.Run(eventArgs).ConfigureAwait(false); | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
RaiseCommandError(CommandErrorType.Exception, eventArgs, ex); | |||||
} | |||||
} | |||||
}; | }; | ||||
} | } | ||||
@@ -198,7 +178,7 @@ namespace Discord.Commands | |||||
else if (command.MinArgs == null && command.MaxArgs != null) | else if (command.MinArgs == null && command.MaxArgs != null) | ||||
output.Append($" ≤{command.MaxArgs.ToString()} Args"); | output.Append($" ≤{command.MaxArgs.ToString()} Args"); | ||||
output.Append($": {command.Description}"); | |||||
output.Append($": {command.Description ?? "No description set for this command."}"); | |||||
return output.ToString(); | return output.ToString(); | ||||
} | } | ||||
@@ -216,13 +196,14 @@ namespace Discord.Commands | |||||
public CommandBuilder CreateCommand(string cmd) | public CommandBuilder CreateCommand(string cmd) | ||||
{ | { | ||||
var command = new Command(cmd); | var command = new Command(cmd); | ||||
_commands.Add(cmd, command); | |||||
return new CommandBuilder(command); | |||||
_commands.Add(command); | |||||
return new CommandBuilder(null, command, ""); | |||||
} | } | ||||
internal void AddCommand(Command command) | internal void AddCommand(Command command) | ||||
{ | { | ||||
_commands.Add(command.Text, command); | |||||
_commands.Add(command); | |||||
_map.AddCommand(command.Text, command); | |||||
} | } | ||||
} | } | ||||
} | } |