diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index be83b955f..6fbf0a9bd 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -506,82 +506,26 @@ namespace Discord.Commands services = services ?? EmptyServiceProvider.Instance; var searchResult = Search(input); - if (!searchResult.IsSuccess) - { - await _commandExecutedEvent.InvokeAsync(Optional.Create(), context, searchResult).ConfigureAwait(false); - return searchResult; - } - var commands = searchResult.Commands; - var preconditionResults = new Dictionary(); - - foreach (var match in commands) - { - preconditionResults[match] = await match.Command.CheckPreconditionsAsync(context, services).ConfigureAwait(false); - } - - var successfulPreconditions = preconditionResults - .Where(x => x.Value.IsSuccess) - .ToArray(); + //Since ValidateAndGetBestMatch is deterministic on the return type, we can use pattern matching on the type for infering the code flow. + var (validationResult, commandMatch) = await ValidateAndGetBestMatch(searchResult, context, services, multiMatchHandling); - if (successfulPreconditions.Length == 0) + if(validationResult is SearchResult) { - //All preconditions failed, return the one from the highest priority command - var bestCandidate = preconditionResults - .OrderByDescending(x => x.Key.Command.Priority) - .FirstOrDefault(x => !x.Value.IsSuccess); - - await _commandExecutedEvent.InvokeAsync(bestCandidate.Key.Command, context, bestCandidate.Value).ConfigureAwait(false); - return bestCandidate.Value; + await _commandExecutedEvent.InvokeAsync(Optional.Create(), context, searchResult).ConfigureAwait(false); } - - //If we get this far, at least one precondition was successful. - - var parseResultsDict = new Dictionary(); - foreach (var pair in successfulPreconditions) + else if(validationResult is not ParseResult parseResult) { - var parseResult = await pair.Key.ParseAsync(context, searchResult, pair.Value, services).ConfigureAwait(false); - - if (parseResult.Error == CommandError.MultipleMatches) - { - IReadOnlyList 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; - } - } - - parseResultsDict[pair.Key] = parseResult; + await _commandExecutedEvent.InvokeAsync(commandMatch.Value.Command,context,validationResult).ConfigureAwait(false); } - - //Order the parse results by their score so that we choose the most likely result to execute - var parseResults = parseResultsDict - .OrderByDescending(x => CalculateScore(x.Key, x.Value)); - - var successfulParses = parseResults - .Where(x => x.Value.IsSuccess) - .ToArray(); - - if (successfulParses.Length == 0) + else { - //All parses failed, return the one from the highest priority command, using score as a tie breaker - var bestMatch = parseResults - .FirstOrDefault(x => !x.Value.IsSuccess); - - await _commandExecutedEvent.InvokeAsync(bestMatch.Key.Command, context, bestMatch.Value).ConfigureAwait(false); - return bestMatch.Value; + var result = await commandMatch.Value.Command.ExecuteAsync(context, parseResult, services).ConfigureAwait(false); + if (!result.IsSuccess && !(result is RuntimeResult || result is ExecuteResult)) // succesful results raise the event in CommandInfo#ExecuteInternalAsync (have to raise it there b/c deffered execution) + await _commandExecutedEvent.InvokeAsync(commandMatch.Value.Command, context, result); + return result; } - - //If we get this far, at least one parse was successful. Execute the most likely overload. - var chosenOverload = successfulParses[0]; - var result = await chosenOverload.Key.ExecuteAsync(context, chosenOverload.Value, services).ConfigureAwait(false); - if (!result.IsSuccess && !(result is RuntimeResult || result is ExecuteResult)) // succesful results raise the event in CommandInfo#ExecuteInternalAsync (have to raise it there b/c deffered execution) - await _commandExecutedEvent.InvokeAsync(chosenOverload.Key.Command, context, result); - return result; + return validationResult; } // Calculates the 'score' of a command given a parse result