This uses a dictionary for the commands list, if a command has a max
args set it'll only get that amount, will call the UnkownCommand event,
and now has a built in help command that can be optionally enabled.
CommandChar is now a list, but a single character can still be used.
Externally, not much should have changed, but commands can be hidden
from the help command and a description can be set. There's probably
more that I've forgotten about.
public IEnumerable<Command> Commands => _commands;
private Dictionary<string, Command> _commands;
public Dictionary<string, Command> Commands => _commands;
public char CommandChar { get; set; }
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 bool RequireCommandCharInPublic { get; set; }
public bool RequireCommandCharInPrivate { get; set; }
public CommandsPlugin(DiscordClient client, Func<User, int> getPermissions = null)
{
_client = client;
_getPermissions = getPermissions;
_commands = new List<Command>();
CommandChar = '/';
UseCommandChar = false;
RequireCommandCharInPublic = true;
RequireCommandCharInPrivate = true;
client.MessageReceived += async (s, e) =>
{
//If commands aren't being used, don't bother processing them
if (_commands.Count == 0)
return;
//Ignore messages from ourselves
if (e.Message.User == client.CurrentUser)
return;
//Check for the command character
string msg = e.Message.Text;
if (UseCommandChar)
{
if (msg.Length == 0)
return;
bool isPrivate = e.Message.Channel.IsPrivate;
bool hasCommandChar = msg[0] == CommandChar;
if (hasCommandChar)
msg = msg.Substring(1);
if (!isPrivate && RequireCommandCharInPublic && !hasCommandChar)
return;
if (isPrivate && RequireCommandCharInPrivate && !hasCommandChar)
return;
}
CommandPart[] args;
if (!CommandParser.ParseArgs(msg, out args))
return;
for (int i = 0; i < _commands.Count; i++)
{
Command cmd = _commands[i];
//Check Command Parts
if (args.Length < cmd.Parts.Length)
continue;
bool isValid = true;
for (int j = 0; j < cmd.Parts.Length; j++)
{
if (!string.Equals(args[j].Value, cmd.Parts[j], StringComparison.OrdinalIgnoreCase))
{
isValid = false;
break;
}
}
if (!isValid)
continue;
//Check Arg Count
int argCount = args.Length - cmd.Parts.Length;
if (argCount < cmd.MinArgs || argCount > cmd.MaxArgs)
CommandChar = '!'; // Kept around to keep from possibly throwing an error. Might not be necessary.
CommandChars = new List<char> { '!', '?', '/' };
UseCommandChar = true;
RequireCommandCharInPublic = true;
RequireCommandCharInPrivate = true;
HelpInPublic = true;
if (builtInHelp)
{
CreateCommand("help")
.ArgsBetween(0, 1)
.IsHidden()
.Desc("Returns information about commands.")
.Do(async e =>
{
if (e.Command.Text != "help")
{
await Reply(e, CommandDetails(e.Command));
}
else
{
if (e.Args == null)
{
StringBuilder output = new StringBuilder();
bool first = true;
output.AppendLine("These are the commands you can use:");
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("`");
if (CommandChars.Count == 1)
output.AppendLine($"{Environment.NewLine}You can use `{CommandChars[0]}` to call a command.");
else
output.AppendLine($"{Environment.NewLine}You can use `{String.Join(" ", CommandChars.Take(CommandChars.Count - 1))}` and `{CommandChars.Last()}` to call a command.");
output.AppendLine("`help <command>` can tell you more about how to use a command.");