Skip to content

Commit

Permalink
Creates ValidateAndGetBestMatch function
Browse files Browse the repository at this point in the history
This function will validate all commands from a SearchResult and return the result of said validation, along with the command matched, if a valid match was found.
  • Loading branch information
alikindsys committed Nov 27, 2020
1 parent 574b503 commit 7955a09
Showing 1 changed file with 77 additions and 0 deletions.
77 changes: 77 additions & 0 deletions src/Discord.Net.Commands/CommandService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,83 @@ float CalculateScore(CommandMatch match, ParseResult parseResult)
return match.Command.Priority + totalArgsScore * 0.99f;
}

/// <summary>
/// Validates and gets the best <see cref="CommandMatch"/> from a specified <see cref="SearchResult"/>
/// </summary>
/// <param name="matches">The SearchResult.</param>
/// <param name="context">The context of the command.</param>
/// <param name="provider">The service provider to be used on the command's dependency injection.</param>
/// <param name="multiMatchHandling">The handling mode when multiple command matches are found.</param>
/// <returns>A task that represents the asynchronous validation operation. The task result contains the result of the
/// command validation and the command matched, if a match was found.</returns>
public async Task<(IResult, Optional<CommandMatch>)> ValidateAndGetBestMatch(SearchResult matches, ICommandContext context, IServiceProvider provider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
{
if (!matches.IsSuccess)
return (matches, Optional.Create<CommandMatch>());

var commands = matches.Commands;
var preconditionResults = new Dictionary<CommandMatch, PreconditionResult>();

foreach (var command in commands)
{
preconditionResults[command] = await command.CheckPreconditionsAsync(context, provider);
}

var successfulPreconditions = preconditionResults
.Where(x => x.Value.IsSuccess)
.ToArray();

if (successfulPreconditions.Length == 0)
{
var bestCandidate = preconditionResults
.OrderByDescending(x => x.Key.Command.Priority)
.FirstOrDefault(x => !x.Value.IsSuccess);

return (bestCandidate.Value, bestCandidate.Key);
}

var parseResults = new Dictionary<CommandMatch, ParseResult>();

foreach (var pair in successfulPreconditions)
{
var parseResult = await pair.Key.ParseAsync(context, matches, pair.Value, provider).ConfigureAwait(false);

if (parseResult.Error == CommandError.MultipleMatches)
{
IReadOnlyList<TypeReaderValue> argList, paramList;
switch (multiMatchHandling)
{
case MultiMatchHandling.Best:
argList = parseResult.ArgValues.Select(x => x.Values.OrderByDescending(y => y.Score).First()).ToImmutableArray();
paramList = parseResult.ParamValues.Select(x => x.Values.OrderByDescending(y => y.Score).First()).ToImmutableArray();
parseResult = ParseResult.FromSuccess(argList, paramList);
break;
}
}

parseResults[pair.Key] = parseResult;
}

var weightedParseResults = parseResults
.OrderByDescending(x => CalculateScore(x.Key, x.Value));

var successfulParses = weightedParseResults
.Where(x => x.Value.IsSuccess)
.ToArray();

if(successfulParses.Length == 0)
{
var bestMatch = parseResults
.FirstOrDefault(x => !x.Value.IsSuccess);

return (bestMatch.Value, bestMatch.Key);
}

var chosenOverload = successfulParses[0];

return (chosenOverload.Value, chosenOverload.Key);
}

protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
Expand Down

0 comments on commit 7955a09

Please sign in to comment.