Added new parameter scoring, support multiple matches

This commit is contained in:
RogueException
2016-08-21 11:03:50 -03:00
parent ed7710fbef
commit 324664917d
14 changed files with 316 additions and 177 deletions

View File

@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
@@ -9,40 +11,37 @@ namespace Discord.Commands
{
public override async Task<TypeReaderResult> Read(IMessage context, string input)
{
IGuildChannel guildChannel = context.Channel as IGuildChannel;
IChannel result = null;
var guild = (context.Channel as IGuildChannel)?.Guild;
if (guildChannel != null)
if (guild != null)
{
//By Id
var results = new Dictionary<ulong, TypeReaderValue>();
var channels = await guild.GetChannelsAsync().ConfigureAwait(false);
ulong id;
if (MentionUtils.TryParseChannel(input, out id) || ulong.TryParse(input, out id))
{
var channel = await guildChannel.Guild.GetChannelAsync(id).ConfigureAwait(false);
if (channel != null)
result = channel;
}
//By Name
if (result == null)
{
var channels = await guildChannel.Guild.GetChannelsAsync().ConfigureAwait(false);
var filteredChannels = channels.Where(x => string.Equals(input, x.Name, StringComparison.OrdinalIgnoreCase)).ToArray();
if (filteredChannels.Length > 1)
return TypeReaderResult.FromError(CommandError.MultipleMatches, "Multiple channels found.");
else if (filteredChannels.Length == 1)
result = filteredChannels[0];
}
//By Mention (1.0)
if (MentionUtils.TryParseChannel(input, out id))
AddResult(results, await guild.GetUserAsync(id).ConfigureAwait(false) as T, 1.00f);
//By Id (0.9)
if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out id))
AddResult(results, await guild.GetChannelAsync(id).ConfigureAwait(false) as T, 0.90f);
//By Name (0.7-0.8)
foreach (var channel in channels.Where(x => string.Equals(input, x.Name, StringComparison.OrdinalIgnoreCase)))
AddResult(results, channel as T, channel.Name == input ? 0.80f : 0.70f);
if (results.Count > 0)
return TypeReaderResult.FromSuccess(results.Values);
}
if (result == null)
return TypeReaderResult.FromError(CommandError.ObjectNotFound, "Channel not found.");
return TypeReaderResult.FromError(CommandError.ObjectNotFound, "Channel not found.");
}
T castResult = result as T;
if (castResult == null)
return TypeReaderResult.FromError(CommandError.CastFailed, $"Channel is not a {typeof(T).Name}.");
else
return TypeReaderResult.FromSuccess(castResult);
private void AddResult(Dictionary<ulong, TypeReaderValue> results, T channel, float score)
{
if (channel != null && !results.ContainsKey(channel.Id))
results.Add(channel.Id, new TypeReaderValue(channel, score));
}
}
}

View File

@@ -52,14 +52,14 @@ namespace Discord.Commands
if (_enumsByValue.TryGetValue(baseValue, out enumValue))
return Task.FromResult(TypeReaderResult.FromSuccess(enumValue));
else
return Task.FromResult(TypeReaderResult.FromError(CommandError.CastFailed, $"Value is not a {_enumType.Name}"));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, $"Value is not a {_enumType.Name}"));
}
else
{
if (_enumsByName.TryGetValue(input.ToLower(), out enumValue))
return Task.FromResult(TypeReaderResult.FromSuccess(enumValue));
else
return Task.FromResult(TypeReaderResult.FromError(CommandError.CastFailed, $"Value is not a {_enumType.Name}"));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, $"Value is not a {_enumType.Name}"));
}
}
}

View File

@@ -7,18 +7,17 @@ namespace Discord.Commands
{
public override Task<TypeReaderResult> Read(IMessage context, string input)
{
//By Id
ulong id;
//By Id (1.0)
if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out id))
{
var msg = context.Channel.GetCachedMessage(id);
if (msg == null)
return Task.FromResult(TypeReaderResult.FromError(CommandError.ObjectNotFound, "Message not found."));
else
if (msg != null)
return Task.FromResult(TypeReaderResult.FromSuccess(msg));
}
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Failed to parse Message Id."));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ObjectNotFound, "Message not found."));
}
}
}

View File

@@ -1,36 +1,46 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
namespace Discord.Commands
{
internal class RoleTypeReader : TypeReader
internal class RoleTypeReader<T> : TypeReader
where T : class, IRole
{
public override Task<TypeReaderResult> Read(IMessage context, string input)
{
IGuildChannel guildChannel = context.Channel as IGuildChannel;
var guild = (context.Channel as IGuildChannel)?.Guild;
ulong id;
if (guildChannel != null)
if (guild != null)
{
//By Id
ulong id;
if (MentionUtils.TryParseRole(input, out id) || ulong.TryParse(input, out id))
{
var channel = guildChannel.Guild.GetRole(id);
if (channel != null)
return Task.FromResult(TypeReaderResult.FromSuccess(channel));
}
var results = new Dictionary<ulong, TypeReaderValue>();
var roles = guild.Roles;
//By Name
var roles = guildChannel.Guild.Roles;
var filteredRoles = roles.Where(x => string.Equals(input, x.Name, StringComparison.OrdinalIgnoreCase)).ToArray();
if (filteredRoles.Length > 1)
return Task.FromResult(TypeReaderResult.FromError(CommandError.MultipleMatches, "Multiple roles found."));
else if (filteredRoles.Length == 1)
return Task.FromResult(TypeReaderResult.FromSuccess(filteredRoles[0]));
//By Mention (1.0)
if (MentionUtils.TryParseRole(input, out id))
AddResult(results, guild.GetRole(id) as T, 1.00f);
//By Id (0.9)
if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out id))
AddResult(results, guild.GetRole(id) as T, 0.90f);
//By Name (0.7-0.8)
foreach (var role in roles.Where(x => string.Equals(input, x.Name, StringComparison.OrdinalIgnoreCase)))
AddResult(results, role as T, role.Name == input ? 0.80f : 0.70f);
if (results.Count > 0)
return Task.FromResult(TypeReaderResult.FromSuccess(results));
}
return Task.FromResult(TypeReaderResult.FromError(CommandError.ObjectNotFound, "Role not found."));
}
private void AddResult(Dictionary<ulong, TypeReaderValue> results, T role, float score)
{
if (role != null && !results.ContainsKey(role.Id))
results.Add(role.Id, new TypeReaderValue(role, score));
}
}
}

View File

@@ -16,8 +16,7 @@ namespace Discord.Commands
T value;
if (_tryParse(input, out value))
return Task.FromResult(TypeReaderResult.FromSuccess(value));
else
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, $"Failed to parse {typeof(T).Name}"));
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, $"Failed to parse {typeof(T).Name}"));
}
}
}

View File

@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
@@ -9,54 +11,78 @@ namespace Discord.Commands
{
public override async Task<TypeReaderResult> Read(IMessage context, string input)
{
IUser result = null;
//By Id
var results = new Dictionary<ulong, TypeReaderValue>();
var guild = (context.Channel as IGuildChannel)?.Guild;
IReadOnlyCollection<IUser> channelUsers = await context.Channel.GetUsersAsync().ConfigureAwait(false);
IReadOnlyCollection<IGuildUser> guildUsers = null;
ulong id;
if (MentionUtils.TryParseUser(input, out id) || ulong.TryParse(input, out id))
if (guild != null)
guildUsers = await guild.GetUsersAsync().ConfigureAwait(false);
//By Mention (1.0)
if (MentionUtils.TryParseUser(input, out id))
{
var user = await context.Channel.GetUserAsync(id).ConfigureAwait(false);
if (user != null)
result = user;
if (guild != null)
AddResult(results, await guild.GetUserAsync(id).ConfigureAwait(false) as T, 1.00f);
else
AddResult(results, await context.Channel.GetUserAsync(id).ConfigureAwait(false) as T, 1.00f);
}
//By Username + Discriminator
if (result == null)
//By Id (0.9)
if (ulong.TryParse(input, NumberStyles.None, CultureInfo.InvariantCulture, out id))
{
int index = input.LastIndexOf('#');
if (index >= 0)
if (guild != null)
AddResult(results, await guild.GetUserAsync(id).ConfigureAwait(false) as T, 0.90f);
else
AddResult(results, await context.Channel.GetUserAsync(id).ConfigureAwait(false) as T, 0.90f);
}
//By Username + Discriminator (0.7-0.85)
int index = input.LastIndexOf('#');
if (index >= 0)
{
string username = input.Substring(0, index);
ushort discriminator;
if (ushort.TryParse(input.Substring(index + 1), out discriminator))
{
string username = input.Substring(0, index);
ushort discriminator;
if (ushort.TryParse(input.Substring(index + 1), out discriminator))
{
var users = await context.Channel.GetUsersAsync().ConfigureAwait(false);
result = users.Where(x =>
x.DiscriminatorValue == discriminator &&
string.Equals(username, x.Username, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
}
var channelUser = channelUsers.Where(x => x.DiscriminatorValue == discriminator &&
string.Equals(username, x.Username, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
AddResult(results, channelUser as T, channelUser.Username == username ? 0.85f : 0.75f);
var guildUser = channelUsers.Where(x => x.DiscriminatorValue == discriminator &&
string.Equals(username, x.Username, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
AddResult(results, guildUser as T, guildUser.Username == username ? 0.80f : 0.70f);
}
}
//By Username
if (result == null)
//By Username (0.5-0.6)
{
var users = await context.Channel.GetUsersAsync().ConfigureAwait(false);
var filteredUsers = users.Where(x => string.Equals(input, x.Username, StringComparison.OrdinalIgnoreCase)).ToArray();
if (filteredUsers.Length > 1)
return TypeReaderResult.FromError(CommandError.MultipleMatches, "Multiple users found.");
else if (filteredUsers.Length == 1)
result = filteredUsers[0];
foreach (var channelUser in channelUsers.Where(x => string.Equals(input, x.Username, StringComparison.OrdinalIgnoreCase)))
AddResult(results, channelUser as T, channelUser.Username == input ? 0.65f : 0.55f);
foreach (var guildUser in guildUsers.Where(x => string.Equals(input, x.Username, StringComparison.OrdinalIgnoreCase)))
AddResult(results, guildUser as T, guildUser.Username == input ? 0.60f : 0.50f);
}
if (result == null)
return TypeReaderResult.FromError(CommandError.ObjectNotFound, "User not found.");
//By Nickname (0.5-0.6)
{
foreach (var channelUser in channelUsers.Where(x => string.Equals(input, (x as IGuildUser).Nickname, StringComparison.OrdinalIgnoreCase)))
AddResult(results, channelUser as T, (channelUser as IGuildUser).Nickname == input ? 0.65f : 0.55f);
T castResult = result as T;
if (castResult == null)
return TypeReaderResult.FromError(CommandError.CastFailed, $"User is not a {typeof(T).Name}.");
else
return TypeReaderResult.FromSuccess(castResult);
foreach (var guildUser in guildUsers.Where(x => string.Equals(input, (x as IGuildUser).Nickname, StringComparison.OrdinalIgnoreCase)))
AddResult(results, guildUser as T, (guildUser as IGuildUser).Nickname == input ? 0.60f : 0.50f);
}
if (results.Count > 0)
return TypeReaderResult.FromSuccess(results.Values.ToArray());
return TypeReaderResult.FromError(CommandError.ObjectNotFound, "User not found.");
}
private void AddResult(Dictionary<ulong, TypeReaderValue> results, T user, float score)
{
if (user != null && !results.ContainsKey(user.Id))
results.Add(user.Id, new TypeReaderValue(user, score));
}
}
}