@@ -43,7 +43,7 @@ namespace Discord.Interactions.Builders | |||||
/// <returns> | /// <returns> | ||||
/// The builder instance. | /// The builder instance. | ||||
/// </returns> | /// </returns> | ||||
public ComponentCommandParameterBuilder SetParameterType(Type type, IServiceProvider services = null) | |||||
public ComponentCommandParameterBuilder SetParameterType(Type type, IServiceProvider services) | |||||
{ | { | ||||
base.SetParameterType(type); | base.SetParameterType(type); | ||||
@@ -41,14 +41,7 @@ namespace Discord.Interactions | |||||
if (context.Interaction is not IAutocompleteInteraction) | if (context.Interaction is not IAutocompleteInteraction) | ||||
return ExecuteResult.FromError(InteractionCommandError.ParseFailed, $"Provided {nameof(IInteractionContext)} doesn't belong to a Autocomplete Interaction"); | return ExecuteResult.FromError(InteractionCommandError.ParseFailed, $"Provided {nameof(IInteractionContext)} doesn't belong to a Autocomplete Interaction"); | ||||
try | |||||
{ | |||||
return await RunAsync(context, Array.Empty<object>(), services).ConfigureAwait(false); | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
return ExecuteResult.FromError(ex); | |||||
} | |||||
return await RunAsync(context, Array.Empty<object>(), services).ConfigureAwait(false); | |||||
} | } | ||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
@@ -31,6 +31,8 @@ namespace Discord.Interactions | |||||
private readonly ExecuteCallback _action; | private readonly ExecuteCallback _action; | ||||
private readonly ILookup<string, PreconditionAttribute> _groupedPreconditions; | private readonly ILookup<string, PreconditionAttribute> _groupedPreconditions; | ||||
internal IReadOnlyDictionary<string, TParameter> _parameterDictionary; | |||||
/// <inheritdoc/> | /// <inheritdoc/> | ||||
public ModuleInfo Module { get; } | public ModuleInfo Module { get; } | ||||
@@ -120,10 +122,7 @@ namespace Discord.Interactions | |||||
return moduleResult; | return moduleResult; | ||||
var commandResult = await CheckGroups(_groupedPreconditions, "Command").ConfigureAwait(false); | var commandResult = await CheckGroups(_groupedPreconditions, "Command").ConfigureAwait(false); | ||||
if (!commandResult.IsSuccess) | |||||
return commandResult; | |||||
return PreconditionResult.FromSuccess(); | |||||
return !commandResult.IsSuccess ? commandResult : PreconditionResult.FromSuccess(); | |||||
} | } | ||||
protected async Task<IResult> RunAsync(IInteractionContext context, object[] args, IServiceProvider services) | protected async Task<IResult> RunAsync(IInteractionContext context, object[] args, IServiceProvider services) | ||||
@@ -137,8 +136,8 @@ namespace Discord.Interactions | |||||
using var scope = services?.CreateScope(); | using var scope = services?.CreateScope(); | ||||
return await ExecuteInternalAsync(context, args, scope?.ServiceProvider ?? EmptyServiceProvider.Instance).ConfigureAwait(false); | return await ExecuteInternalAsync(context, args, scope?.ServiceProvider ?? EmptyServiceProvider.Instance).ConfigureAwait(false); | ||||
} | } | ||||
else | |||||
return await ExecuteInternalAsync(context, args, services).ConfigureAwait(false); | |||||
return await ExecuteInternalAsync(context, args, services).ConfigureAwait(false); | |||||
} | } | ||||
case RunMode.Async: | case RunMode.Async: | ||||
_ = Task.Run(async () => | _ = Task.Run(async () => | ||||
@@ -167,20 +166,14 @@ namespace Discord.Interactions | |||||
{ | { | ||||
var preconditionResult = await CheckPreconditionsAsync(context, services).ConfigureAwait(false); | var preconditionResult = await CheckPreconditionsAsync(context, services).ConfigureAwait(false); | ||||
if (!preconditionResult.IsSuccess) | if (!preconditionResult.IsSuccess) | ||||
{ | |||||
await InvokeModuleEvent(context, preconditionResult).ConfigureAwait(false); | |||||
return preconditionResult; | |||||
} | |||||
return await InvokeEventAndReturn(context, preconditionResult).ConfigureAwait(false); | |||||
var index = 0; | var index = 0; | ||||
foreach (var parameter in Parameters) | foreach (var parameter in Parameters) | ||||
{ | { | ||||
var result = await parameter.CheckPreconditionsAsync(context, args[index++], services).ConfigureAwait(false); | var result = await parameter.CheckPreconditionsAsync(context, args[index++], services).ConfigureAwait(false); | ||||
if (!result.IsSuccess) | if (!result.IsSuccess) | ||||
{ | |||||
await InvokeModuleEvent(context, result).ConfigureAwait(false); | |||||
return result; | |||||
} | |||||
return await InvokeEventAndReturn(context, result).ConfigureAwait(false); | |||||
} | } | ||||
var task = _action(context, args, services, this); | var task = _action(context, args, services, this); | ||||
@@ -189,20 +182,16 @@ namespace Discord.Interactions | |||||
{ | { | ||||
var result = await resultTask.ConfigureAwait(false); | var result = await resultTask.ConfigureAwait(false); | ||||
await InvokeModuleEvent(context, result).ConfigureAwait(false); | await InvokeModuleEvent(context, result).ConfigureAwait(false); | ||||
if (result is RuntimeResult || result is ExecuteResult) | |||||
if (result is RuntimeResult or ExecuteResult) | |||||
return result; | return result; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
await task.ConfigureAwait(false); | await task.ConfigureAwait(false); | ||||
var result = ExecuteResult.FromSuccess(); | |||||
await InvokeModuleEvent(context, result).ConfigureAwait(false); | |||||
return result; | |||||
return await InvokeEventAndReturn(context, ExecuteResult.FromSuccess()).ConfigureAwait(false); | |||||
} | } | ||||
var failResult = ExecuteResult.FromError(InteractionCommandError.Unsuccessful, "Command execution failed for an unknown reason"); | |||||
await InvokeModuleEvent(context, failResult).ConfigureAwait(false); | |||||
return failResult; | |||||
return await InvokeEventAndReturn(context, ExecuteResult.FromError(InteractionCommandError.Unsuccessful, "Command execution failed for an unknown reason")).ConfigureAwait(false); | |||||
} | } | ||||
catch (Exception ex) | catch (Exception ex) | ||||
{ | { | ||||
@@ -231,6 +220,12 @@ namespace Discord.Interactions | |||||
} | } | ||||
} | } | ||||
protected async ValueTask<IResult> InvokeEventAndReturn(IInteractionContext context, IResult result) | |||||
{ | |||||
await InvokeModuleEvent(context, result).ConfigureAwait(false); | |||||
return result; | |||||
} | |||||
private static bool CheckTopLevel(ModuleInfo parent) | private static bool CheckTopLevel(ModuleInfo parent) | ||||
{ | { | ||||
var currentParent = parent; | var currentParent = parent; | ||||
@@ -48,6 +48,11 @@ namespace Discord.Interactions | |||||
public async Task<IResult> ExecuteAsync(IInteractionContext context, IEnumerable<CommandParameterInfo> paramList, IEnumerable<string> wildcardCaptures, IComponentInteractionData data, | public async Task<IResult> ExecuteAsync(IInteractionContext context, IEnumerable<CommandParameterInfo> paramList, IEnumerable<string> wildcardCaptures, IComponentInteractionData data, | ||||
IServiceProvider services) | IServiceProvider services) | ||||
{ | { | ||||
var paramCount = paramList.Count(); | |||||
var captureCount = wildcardCaptures?.Count() ?? 0; | |||||
if (paramCount < captureCount + 1) | |||||
return await InvokeEventAndReturn(context, ExecuteResult.FromError(InteractionCommandError.BadArgs, "Command was invoked with too many parameters")).ConfigureAwait(false); | |||||
if (context.Interaction is not IComponentInteraction messageComponent) | if (context.Interaction is not IComponentInteraction messageComponent) | ||||
return ExecuteResult.FromError(InteractionCommandError.ParseFailed, $"Provided {nameof(IInteractionContext)} doesn't belong to a Component Command Interaction"); | return ExecuteResult.FromError(InteractionCommandError.ParseFailed, $"Provided {nameof(IInteractionContext)} doesn't belong to a Component Command Interaction"); | ||||
@@ -58,27 +63,16 @@ namespace Discord.Interactions | |||||
for (var i = 0; i < paramCount; i++) | for (var i = 0; i < paramCount; i++) | ||||
{ | { | ||||
var parameter = Parameters.ElementAt(i); | var parameter = Parameters.ElementAt(i); | ||||
bool isCapture = i < captureCount; | |||||
var isCapture = i < captureCount; | |||||
if (isCapture ^ parameter.IsRouteSegmentParameter) | if (isCapture ^ parameter.IsRouteSegmentParameter) | ||||
{ | |||||
var result = ExecuteResult.FromError(InteractionCommandError.BadArgs, $"Argument type and parameter type didn't match (Wild Card capture/Component value)"); | |||||
await InvokeModuleEvent(context, result).ConfigureAwait(false); | |||||
return result; | |||||
} | |||||
TypeConverterResult readResult; | |||||
return await InvokeEventAndReturn(context, ExecuteResult.FromError(InteractionCommandError.BadArgs, "Argument type and parameter type didn't match (Wild Card capture/Component value)")).ConfigureAwait(false); | |||||
if (isCapture) | |||||
readResult = await parameter.TypeReader.ReadAsync(context, wildcardCaptures.ElementAt(i), services).ConfigureAwait(false); | |||||
else | |||||
readResult = await parameter.TypeConverter.ReadAsync(context, data, services).ConfigureAwait(false); | |||||
var readResult = isCapture ? await parameter.TypeReader.ReadAsync(context, wildcardCaptures.ElementAt(i), services).ConfigureAwait(false) : | |||||
await parameter.TypeConverter.ReadAsync(context, data, services).ConfigureAwait(false); | |||||
if (!readResult.IsSuccess) | if (!readResult.IsSuccess) | ||||
{ | |||||
await InvokeModuleEvent(context, readResult).ConfigureAwait(false); | |||||
return readResult; | |||||
} | |||||
return await InvokeEventAndReturn(context, readResult).ConfigureAwait(false); | |||||
args[i] = readResult.Value; | args[i] = readResult.Value; | ||||
} | } | ||||
@@ -87,9 +81,7 @@ namespace Discord.Interactions | |||||
} | } | ||||
catch (Exception ex) | catch (Exception ex) | ||||
{ | { | ||||
var result = ExecuteResult.FromError(ex); | |||||
await InvokeModuleEvent(context, result).ConfigureAwait(false); | |||||
return result; | |||||
return await InvokeEventAndReturn(context, ExecuteResult.FromError(ex)).ConfigureAwait(false); | |||||
} | } | ||||
} | } | ||||
@@ -1,6 +1,7 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Collections.Immutable; | using System.Collections.Immutable; | ||||
using System.Diagnostics.Tracing; | |||||
using System.Linq; | using System.Linq; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
namespace Discord.Interactions | namespace Discord.Interactions | ||||
@@ -57,37 +58,28 @@ namespace Discord.Interactions | |||||
if(i < captureCount) | if(i < captureCount) | ||||
{ | { | ||||
var readResult = await parameter.TypeReader.ReadAsync(context, additionalArgs[i], services).ConfigureAwait(false); | var readResult = await parameter.TypeReader.ReadAsync(context, additionalArgs[i], services).ConfigureAwait(false); | ||||
if (!readResult.IsSuccess) | |||||
return await InvokeEventAndReturn(context, readResult).ConfigureAwait(false); | |||||
if(!readResult.IsSuccess) | |||||
{ | |||||
await InvokeModuleEvent(context, readResult).ConfigureAwait(false); | |||||
return readResult; | |||||
} | |||||
args[i] = readResult.Value; | args[i] = readResult.Value; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
var modalResult = await Modal.CreateModalAsync(context, services, Module.CommandService._exitOnMissingModalField).ConfigureAwait(false); | var modalResult = await Modal.CreateModalAsync(context, services, Module.CommandService._exitOnMissingModalField).ConfigureAwait(false); | ||||
if (!modalResult.IsSuccess) | if (!modalResult.IsSuccess) | ||||
{ | |||||
await InvokeModuleEvent(context, modalResult).ConfigureAwait(false); | |||||
return modalResult; | |||||
} | |||||
return await InvokeEventAndReturn(context, modalResult).ConfigureAwait(false); | |||||
if (modalResult is not ParseResult parseResult) | |||||
return await InvokeEventAndReturn(context, ExecuteResult.FromError(InteractionCommandError.BadArgs, "Command parameter parsing failed for an unknown reason.")); | |||||
if (modalResult is ParseResult parseResult) | |||||
args[i] = parseResult.Value; | |||||
else | |||||
return ExecuteResult.FromError(InteractionCommandError.BadArgs, "Command parameter parsing failed for an unknown reason."); | |||||
args[i] = parseResult.Value; | |||||
} | } | ||||
} | } | ||||
return await RunAsync(context, args.ToArray(), services); | |||||
return await RunAsync(context, args, services); | |||||
} | } | ||||
catch (Exception ex) | catch (Exception ex) | ||||
{ | { | ||||
var result = ExecuteResult.FromError(ex); | |||||
await InvokeModuleEvent(context, result).ConfigureAwait(false); | |||||
return result; | |||||
return await InvokeEventAndReturn(context, ExecuteResult.FromError(ex)).ConfigureAwait(false); | |||||
} | } | ||||
} | } | ||||
@@ -56,48 +56,67 @@ namespace Discord.Interactions | |||||
{ | { | ||||
try | try | ||||
{ | { | ||||
if (paramList?.Count() < argList?.Count()) | |||||
return ExecuteResult.FromError(InteractionCommandError.BadArgs ,"Command was invoked with too many parameters"); | |||||
var slashCommandParameterInfos = paramList.ToList(); | |||||
var args = new object[slashCommandParameterInfos.Count]; | |||||
var args = new object[paramList.Count()]; | |||||
for (var i = 0; i < paramList.Count(); i++) | |||||
for (var i = 0; i < slashCommandParameterInfos.Count; i++) | |||||
{ | { | ||||
var parameter = paramList.ElementAt(i); | |||||
var arg = argList?.Find(x => string.Equals(x.Name, parameter.Name, StringComparison.OrdinalIgnoreCase)); | |||||
if (arg == default) | |||||
{ | |||||
if (parameter.IsRequired) | |||||
return ExecuteResult.FromError(InteractionCommandError.BadArgs, "Command was invoked with too few parameters"); | |||||
else | |||||
args[i] = parameter.DefaultValue; | |||||
} | |||||
else | |||||
{ | |||||
var typeConverter = parameter.TypeConverter; | |||||
var readResult = await typeConverter.ReadAsync(context, arg, services).ConfigureAwait(false); | |||||
if (!readResult.IsSuccess) | |||||
{ | |||||
await InvokeModuleEvent(context, readResult).ConfigureAwait(false); | |||||
return readResult; | |||||
} | |||||
args[i] = readResult.Value; | |||||
} | |||||
} | |||||
var parameter = slashCommandParameterInfos[i]; | |||||
var result = await ParseArgument(parameter, context, argList, services).ConfigureAwait(false); | |||||
if (!result.IsSuccess) | |||||
return await InvokeEventAndReturn(context, result).ConfigureAwait(false); | |||||
if (result is not ParseResult parseResult) | |||||
return ExecuteResult.FromError(InteractionCommandError.BadArgs, "Command parameter parsing failed for an unknown reason."); | |||||
args[i] = parseResult.Value; | |||||
} | |||||
return await RunAsync(context, args, services).ConfigureAwait(false); | return await RunAsync(context, args, services).ConfigureAwait(false); | ||||
} | } | ||||
catch (Exception ex) | catch (Exception ex) | ||||
{ | { | ||||
return ExecuteResult.FromError(ex); | |||||
return await InvokeEventAndReturn(context, ExecuteResult.FromError(ex)).ConfigureAwait(false); | |||||
} | } | ||||
} | } | ||||
private async Task<IResult> ParseArgument(SlashCommandParameterInfo parameterInfo, IInteractionContext context, List<IApplicationCommandInteractionDataOption> argList, | |||||
IServiceProvider services) | |||||
{ | |||||
if (parameterInfo.IsComplexParameter) | |||||
{ | |||||
var ctorArgs = new object[parameterInfo.ComplexParameterFields.Count]; | |||||
for (var i = 0; i < ctorArgs.Length; i++) | |||||
{ | |||||
var result = await ParseArgument(parameterInfo.ComplexParameterFields.ElementAt(i), context, argList, services).ConfigureAwait(false); | |||||
if (!result.IsSuccess) | |||||
return result; | |||||
if (result is not ParseResult parseResult) | |||||
return ExecuteResult.FromError(InteractionCommandError.BadArgs, "Complex command parsing failed for an unknown reason."); | |||||
ctorArgs[i] = parseResult.Value; | |||||
} | |||||
return ParseResult.FromSuccess(parameterInfo._complexParameterInitializer(ctorArgs)); | |||||
} | |||||
var arg = argList?.Find(x => string.Equals(x.Name, parameterInfo.Name, StringComparison.OrdinalIgnoreCase)); | |||||
if (arg == default) | |||||
return parameterInfo.IsRequired ? ExecuteResult.FromError(InteractionCommandError.BadArgs, "Command was invoked with too few parameters") : | |||||
ParseResult.FromSuccess(parameterInfo.DefaultValue); | |||||
var typeConverter = parameterInfo.TypeConverter; | |||||
var readResult = await typeConverter.ReadAsync(context, arg, services).ConfigureAwait(false); | |||||
if (!readResult.IsSuccess) | |||||
return readResult; | |||||
return ParseResult.FromSuccess(readResult.Value); | |||||
} | |||||
protected override Task InvokeModuleEvent (IInteractionContext context, IResult result) | protected override Task InvokeModuleEvent (IInteractionContext context, IResult result) | ||||
=> CommandService._slashCommandExecutedEvent.InvokeAsync(this, context, result); | => CommandService._slashCommandExecutedEvent.InvokeAsync(this, context, result); | ||||
@@ -193,7 +193,7 @@ namespace Discord.Interactions | |||||
[typeof(IMentionable)] = typeof(DefaultMentionableConverter<>), | [typeof(IMentionable)] = typeof(DefaultMentionableConverter<>), | ||||
[typeof(IConvertible)] = typeof(DefaultValueConverter<>), | [typeof(IConvertible)] = typeof(DefaultValueConverter<>), | ||||
[typeof(Enum)] = typeof(EnumConverter<>), | [typeof(Enum)] = typeof(EnumConverter<>), | ||||
[typeof(Nullable<>)] = typeof(NullableConverter<>), | |||||
[typeof(Nullable<>)] = typeof(NullableConverter<>) | |||||
}); | }); | ||||
_compTypeConverterMap = new TypeMap<ComponentTypeConverter, IComponentInteractionData>(this, new ConcurrentDictionary<Type, ComponentTypeConverter>(), | _compTypeConverterMap = new TypeMap<ComponentTypeConverter, IComponentInteractionData>(this, new ConcurrentDictionary<Type, ComponentTypeConverter>(), | ||||
@@ -209,7 +209,7 @@ namespace Discord.Interactions | |||||
[typeof(IChannel)] = typeof(DefaultChannelReader<>), | [typeof(IChannel)] = typeof(DefaultChannelReader<>), | ||||
[typeof(IRole)] = typeof(DefaultRoleReader<>), | [typeof(IRole)] = typeof(DefaultRoleReader<>), | ||||
[typeof(IUser)] = typeof(DefaultUserReader<>), | [typeof(IUser)] = typeof(DefaultUserReader<>), | ||||
[typeof(IMessage)] = typeof(DefaultUserReader<>), | |||||
[typeof(IMessage)] = typeof(DefaultMessageReader<>), | |||||
[typeof(IConvertible)] = typeof(DefaultValueReader<>), | [typeof(IConvertible)] = typeof(DefaultValueReader<>), | ||||
[typeof(Enum)] = typeof(EnumReader<>) | [typeof(Enum)] = typeof(EnumReader<>) | ||||
}); | }); | ||||
@@ -311,7 +311,7 @@ namespace Discord.Interactions | |||||
public async Task<ModuleInfo> AddModuleAsync (Type type, IServiceProvider services) | public async Task<ModuleInfo> AddModuleAsync (Type type, IServiceProvider services) | ||||
{ | { | ||||
if (!typeof(IInteractionModuleBase).IsAssignableFrom(type)) | if (!typeof(IInteractionModuleBase).IsAssignableFrom(type)) | ||||
throw new ArgumentException("Type parameter must be a type of Slash Module", "T"); | |||||
throw new ArgumentException("Type parameter must be a type of Slash Module", nameof(type)); | |||||
services ??= EmptyServiceProvider.Instance; | services ??= EmptyServiceProvider.Instance; | ||||
@@ -344,7 +344,7 @@ namespace Discord.Interactions | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
/// Register Application Commands from <see cref="ContextCommands"/> and <see cref="SlashCommands"/> to a guild. | |||||
/// Register Application Commands from <see cref="ContextCommands"/> and <see cref="SlashCommands"/> to a guild. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="guildId">Id of the target guild.</param> | /// <param name="guildId">Id of the target guild.</param> | ||||
/// <param name="deleteMissing">If <see langword="false"/>, this operation will not delete the commands that are missing from <see cref="InteractionService"/>.</param> | /// <param name="deleteMissing">If <see langword="false"/>, this operation will not delete the commands that are missing from <see cref="InteractionService"/>.</param> | ||||
@@ -440,7 +440,7 @@ namespace Discord.Interactions | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
/// Register Application Commands from modules provided in <paramref name="modules"/> to a guild. | |||||
/// Register Application Commands from modules provided in <paramref name="modules"/> to a guild. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="guild">The target guild.</param> | /// <param name="guild">The target guild.</param> | ||||
/// <param name="modules">Modules to be registered to Discord.</param> | /// <param name="modules">Modules to be registered to Discord.</param> | ||||
@@ -467,7 +467,7 @@ namespace Discord.Interactions | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
/// Register Application Commands from modules provided in <paramref name="modules"/> as global commands. | |||||
/// Register Application Commands from modules provided in <paramref name="modules"/> as global commands. | |||||
/// </summary> | /// </summary> | ||||
/// <param name="modules">Modules to be registered to Discord.</param> | /// <param name="modules">Modules to be registered to Discord.</param> | ||||
/// <returns> | /// <returns> | ||||
@@ -695,7 +695,7 @@ namespace Discord.Interactions | |||||
public async Task<IResult> ExecuteCommandAsync (IInteractionContext context, IServiceProvider services) | public async Task<IResult> ExecuteCommandAsync (IInteractionContext context, IServiceProvider services) | ||||
{ | { | ||||
var interaction = context.Interaction; | var interaction = context.Interaction; | ||||
return interaction switch | return interaction switch | ||||
{ | { | ||||
ISlashCommandInteraction slashCommand => await ExecuteSlashCommandAsync(context, slashCommand, services).ConfigureAwait(false), | ISlashCommandInteraction slashCommand => await ExecuteSlashCommandAsync(context, slashCommand, services).ConfigureAwait(false), | ||||
@@ -865,7 +865,7 @@ namespace Discord.Interactions | |||||
/// Add a concrete type <see cref="TypeReader"/>. | /// Add a concrete type <see cref="TypeReader"/>. | ||||
/// </summary> | /// </summary> | ||||
/// <typeparam name="T">Primary target <see cref="Type"/> of the <see cref="TypeReader"/>.</typeparam> | /// <typeparam name="T">Primary target <see cref="Type"/> of the <see cref="TypeReader"/>.</typeparam> | ||||
/// <param name="converter">The <see cref="TypeReader"/> instance.</param> | |||||
/// <param name="reader">The <see cref="TypeReader"/> instance.</param> | |||||
public void AddTypeReader<T>(TypeReader reader) => | public void AddTypeReader<T>(TypeReader reader) => | ||||
AddTypeReader(typeof(T), reader); | AddTypeReader(typeof(T), reader); | ||||
@@ -873,7 +873,7 @@ namespace Discord.Interactions | |||||
/// Add a concrete type <see cref="TypeReader"/>. | /// Add a concrete type <see cref="TypeReader"/>. | ||||
/// </summary> | /// </summary> | ||||
/// <param name="type">Primary target <see cref="Type"/> of the <see cref="TypeReader"/>.</param> | /// <param name="type">Primary target <see cref="Type"/> of the <see cref="TypeReader"/>.</param> | ||||
/// <param name="converter">The <see cref="TypeReader"/> instance.</param> | |||||
/// <param name="reader">The <see cref="TypeReader"/> instance.</param> | |||||
public void AddTypeReader(Type type, TypeReader reader) => | public void AddTypeReader(Type type, TypeReader reader) => | ||||
_typeReaderMap.AddConcrete(type, reader); | _typeReaderMap.AddConcrete(type, reader); | ||||
@@ -1066,7 +1066,7 @@ namespace Discord.Interactions | |||||
public ModuleInfo GetModuleInfo<TModule> ( ) where TModule : class | public ModuleInfo GetModuleInfo<TModule> ( ) where TModule : class | ||||
{ | { | ||||
if (!typeof(IInteractionModuleBase).IsAssignableFrom(typeof(TModule))) | if (!typeof(IInteractionModuleBase).IsAssignableFrom(typeof(TModule))) | ||||
throw new ArgumentException("Type parameter must be a type of Slash Module", "TModule"); | |||||
throw new ArgumentException("Type parameter must be a type of Slash Module", nameof(TModule)); | |||||
var module = _typedModuleDefs[typeof(TModule)]; | var module = _typedModuleDefs[typeof(TModule)]; | ||||
@@ -25,8 +25,8 @@ namespace Discord.Interactions | |||||
if (_concretes.TryGetValue(type, out var specific)) | if (_concretes.TryGetValue(type, out var specific)) | ||||
return specific; | return specific; | ||||
else if (_generics.Any(x => x.Key.IsAssignableFrom(type) | |||||
|| (x.Key.IsGenericTypeDefinition && type.IsGenericType && x.Key.GetGenericTypeDefinition() == type.GetGenericTypeDefinition()))) | |||||
if (_generics.Any(x => x.Key.IsAssignableFrom(type) | |||||
|| x.Key.IsGenericTypeDefinition && type.IsGenericType && x.Key.GetGenericTypeDefinition() == type.GetGenericTypeDefinition())) | |||||
{ | { | ||||
services ??= EmptyServiceProvider.Instance; | services ??= EmptyServiceProvider.Instance; | ||||
@@ -36,10 +36,10 @@ namespace Discord.Interactions | |||||
return converter; | return converter; | ||||
} | } | ||||
else if (_concretes.Any(x => x.Value.CanConvertTo(type))) | |||||
if (_concretes.Any(x => x.Value.CanConvertTo(type))) | |||||
return _concretes.First(x => x.Value.CanConvertTo(type)).Value; | return _concretes.First(x => x.Value.CanConvertTo(type)).Value; | ||||
throw new ArgumentException($"No type {typeof(TConverter).Name} is defined for this {type.FullName}", "type"); | |||||
throw new ArgumentException($"No type {typeof(TConverter).Name} is defined for this {type.FullName}", nameof(type)); | |||||
} | } | ||||
public void AddConcrete<TTarget>(TConverter converter) => | public void AddConcrete<TTarget>(TConverter converter) => | ||||
@@ -63,7 +63,7 @@ namespace Discord.Interactions | |||||
var genericArguments = converterType.GetGenericArguments(); | var genericArguments = converterType.GetGenericArguments(); | ||||
if (genericArguments.Count() > 1) | |||||
if (genericArguments.Length > 1) | |||||
throw new InvalidOperationException($"Valid generic {converterType.FullName}s cannot have more than 1 generic type parameter"); | throw new InvalidOperationException($"Valid generic {converterType.FullName}s cannot have more than 1 generic type parameter"); | ||||
var constraints = genericArguments.SelectMany(x => x.GetGenericParameterConstraints()); | var constraints = genericArguments.SelectMany(x => x.GetGenericParameterConstraints()); | ||||
@@ -15,10 +15,8 @@ namespace Discord.Interactions | |||||
var result = await GetEntity(snowflake, context).ConfigureAwait(false); | var result = await GetEntity(snowflake, context).ConfigureAwait(false); | ||||
if (result is not null) | |||||
return TypeConverterResult.FromSuccess(result); | |||||
else | |||||
return TypeConverterResult.FromError(InteractionCommandError.ConvertFailed, $"{option} must be a valid {typeof(T).Name} snowflake to be parsed."); | |||||
return result is not null ? | |||||
TypeConverterResult.FromSuccess(result) : TypeConverterResult.FromError(InteractionCommandError.ConvertFailed, $"{option} must be a valid {typeof(T).Name} snowflake to be parsed."); | |||||
} | } | ||||
public override Task<string> SerializeAsync(object obj) => Task.FromResult((obj as ISnowflakeEntity)?.Id.ToString()); | public override Task<string> SerializeAsync(object obj) => Task.FromResult((obj as ISnowflakeEntity)?.Id.ToString()); | ||||
@@ -8,10 +8,8 @@ namespace Discord.Interactions | |||||
{ | { | ||||
public override Task<TypeConverterResult> ReadAsync(IInteractionContext context, string option, IServiceProvider services) | public override Task<TypeConverterResult> ReadAsync(IInteractionContext context, string option, IServiceProvider services) | ||||
{ | { | ||||
if (Enum.TryParse<T>(option, out var result)) | |||||
return Task.FromResult(TypeConverterResult.FromSuccess(result)); | |||||
else | |||||
return Task.FromResult(TypeConverterResult.FromError(InteractionCommandError.ConvertFailed, $"Value {option} cannot be converted to {nameof(T)}")); | |||||
return Task.FromResult(Enum.TryParse<T>(option, out var result) ? | |||||
TypeConverterResult.FromSuccess(result) : TypeConverterResult.FromError(InteractionCommandError.ConvertFailed, $"Value {option} cannot be converted to {nameof(T)}")); | |||||
} | } | ||||
public override Task<string> SerializeAsync(object obj) | public override Task<string> SerializeAsync(object obj) | ||||
@@ -20,8 +20,8 @@ namespace Discord.Interactions | |||||
/// <summary> | /// <summary> | ||||
/// Will be used to read the incoming payload before executing the method body. | /// Will be used to read the incoming payload before executing the method body. | ||||
/// </summary> | /// </summary> | ||||
/// <param name="context">Command exexution context.</param> | |||||
/// <param name="option">Recieved option payload.</param> | |||||
/// <param name="context">Command execution context.</param> | |||||
/// <param name="option">Received option payload.</param> | |||||
/// <param name="services">Service provider that will be used to initialize the command module.</param> | /// <param name="services">Service provider that will be used to initialize the command module.</param> | ||||
/// <returns>The result of the read process.</returns> | /// <returns>The result of the read process.</returns> | ||||
public abstract Task<TypeConverterResult> ReadAsync(IInteractionContext context, string option, IServiceProvider services); | public abstract Task<TypeConverterResult> ReadAsync(IInteractionContext context, string option, IServiceProvider services); | ||||
@@ -31,7 +31,7 @@ namespace Discord.Interactions | |||||
/// </summary> | /// </summary> | ||||
/// <param name="obj">Object to be serialized.</param> | /// <param name="obj">Object to be serialized.</param> | ||||
/// <returns> | /// <returns> | ||||
/// A task represting the conversion process. The result of the task contains the conversion result. | |||||
/// A task representing the conversion process. The result of the task contains the conversion result. | |||||
/// </returns> | /// </returns> | ||||
public virtual Task<string> SerializeAsync(object obj) => Task.FromResult(obj.ToString()); | public virtual Task<string> SerializeAsync(object obj) => Task.FromResult(obj.ToString()); | ||||
} | } | ||||
@@ -7,7 +7,7 @@ namespace Discord.Interactions | |||||
{ | { | ||||
internal static class ModalUtils | internal static class ModalUtils | ||||
{ | { | ||||
private static ConcurrentDictionary<Type, ModalInfo> _modalInfos = new(); | |||||
private static readonly ConcurrentDictionary<Type, ModalInfo> _modalInfos = new(); | |||||
public static IReadOnlyCollection<ModalInfo> Modals => _modalInfos.Values.ToReadOnlyCollection(); | public static IReadOnlyCollection<ModalInfo> Modals => _modalInfos.Values.ToReadOnlyCollection(); | ||||