James Connor
James Connor

Reputation: 37

My Discord Bot won't accept Users as parameters for commands

I'm currently working on a Discord bot to learn how to code one. I thought I had it down, but when I try to use the following command, it does nothing:

[Command("ping")]
public async Task Ping(IUser user)
{
  await Context.Channel.SendMessageAsync(user.ToString());
}

It's part of a public class, and if I use any other parameter type (e.g. IChannel, bool, int) it works. It's just this one parameter type. It also doesn't log any errors or exceptions. Any ideas?

Upvotes: 1

Views: 1492

Answers (3)

James Connor
James Connor

Reputation: 37

I ended up taking Reynevan's advice, and wrote a method for converting a mention into an IUser. Just call CustomUserTypereader.GetUser(mention_parameter, Context.Guild);

using System.Threading.Tasks;
using Discord;

public class CustomUserTypereader
{
    public static async Task<IUser> GetUserFromString(string s, IGuild server)
    {
        if (s.IndexOf('@') == -1 || s.Replace("<", "").Replace(">", "").Length != s.Length - 2)
            throw new System.Exception("Not a valid user mention.");

        string idStr = s.Replace("<", "").Replace(">", "").Replace("@", "");

        try
        {
            ulong id = ulong.Parse(idStr);
            return await server.GetUserAsync(id);
        }
        catch
        {
            throw new System.Exception("Could not parse User ID. Are you sure the user is still on the server?");
        }
    }
}

Upvotes: 0

Rishav
Rishav

Reputation: 4078

[Command("ping")]
public async Task Ping(IUser user)
{
  await Context.Channel.SendMessageAsync(user.ToString());
}

Your code id perfect. But think about this, the user is of the type IUser and your conversion to sting makes it vague. Instead try this:

[Command("ping")]
public async Task Ping(SocketGuildUser user)
{
   await Context.Channel.SendMessageAsync(user.Username);
}

If you want to ping the user try user.Mention.

Also when I started learning I made a bot as well. Here is the source code. Its very very very basic. It definitely will help.

Upvotes: 1

Reynevan
Reynevan

Reputation: 1545

You could try using this workaround for your bot:

public async Task SampleCommand(string user="", [Remainder]string message="")
{
    IUser subject = null;
    if (user != "")
    {
        var guilds = (await Context.Client.GetGuildsAsync(Discord.CacheMode.AllowDownload));
        var users = new List<IUser>();
        foreach (var g in guilds)
            users.AddRange(await g.GetUsersAsync(CacheMode.AllowDownload));
        users = users.GroupBy(o => o.Id).Select(o => o.First()).ToList();
        var search = users.Where(o => o.Username.ToLower().Contains(user.ToLower()) || Context.Message.MentionedUserIds.Contains(o.Id) || o.ToString().ToLower().Contains(user.ToLower())).ToArray();
        if (search.Length == 0)
        {
            await ReplyAsync("***Error!*** *Couldn't find that user.*");
            return;
        }
        else if (search.Length > 1)
        {
            await ReplyAsync("***Error!*** *Found more than one matching users.*");
            return;
        }
        subject = search.First();
    }
    // ...
    // execute command

Or you could wrap that in a method for easier access and reusability.

Basically, what it does is it looks for available users that match the given string (in nickname, username or mentions. You could also make it check for IDs if you so desire).

Edit: In my case I'm allowing people to mention anyone who shares the server with the bot, but in your case it might be more benefitial to just use the Context.Guild instead and cancel the command in case of DMs.

Upvotes: 0

Related Questions