| @@ -257,8 +257,10 @@ namespace Discord.Interactions.Builders | |||||
| var parameters = methodInfo.GetParameters(); | var parameters = methodInfo.GetParameters(); | ||||
| var wildCardCount = Regex.Matches(Regex.Escape(builder.Name), Regex.Escape(commandService._wildCardExp)).Count; | |||||
| foreach (var parameter in parameters) | foreach (var parameter in parameters) | ||||
| builder.AddParameter(x => BuildParameter(x, parameter)); | |||||
| builder.AddParameter(x => BuildComponentParameter(x, parameter, parameter.Position >= wildCardCount)); | |||||
| builder.Callback = CreateCallback(createInstance, methodInfo, commandService); | builder.Callback = CreateCallback(createInstance, methodInfo, commandService); | ||||
| } | } | ||||
| @@ -442,10 +444,11 @@ namespace Discord.Interactions.Builders | |||||
| builder.Name = Regex.Replace(builder.Name, "(?<=[a-z])(?=[A-Z])", "-").ToLower(); | builder.Name = Regex.Replace(builder.Name, "(?<=[a-z])(?=[A-Z])", "-").ToLower(); | ||||
| } | } | ||||
| private static void BuildComponentParameter(ComponentCommandParameterBuilder builder, ParameterInfo paramInfo) | |||||
| private static void BuildComponentParameter(ComponentCommandParameterBuilder builder, ParameterInfo paramInfo, bool isComponentParam) | |||||
| { | { | ||||
| BuildParameter(builder, paramInfo); | |||||
| builder.SetAsRouteSegment(!isComponentParam); | |||||
| BuildParameter(builder, paramInfo); | |||||
| } | } | ||||
| private static void BuildParameter<TInfo, TBuilder> (ParameterBuilder<TInfo, TBuilder> builder, ParameterInfo paramInfo) | private static void BuildParameter<TInfo, TBuilder> (ParameterBuilder<TInfo, TBuilder> builder, ParameterInfo paramInfo) | ||||
| @@ -5,6 +5,8 @@ namespace Discord.Interactions.Builders | |||||
| public class ComponentCommandParameterBuilder : ParameterBuilder<ComponentCommandParameterInfo, ComponentCommandParameterBuilder> | public class ComponentCommandParameterBuilder : ParameterBuilder<ComponentCommandParameterInfo, ComponentCommandParameterBuilder> | ||||
| { | { | ||||
| public ComponentTypeConverter TypeConverter { get; private set; } | public ComponentTypeConverter TypeConverter { get; private set; } | ||||
| public TypeReader TypeReader { get; private set; } | |||||
| public bool IsRouteSegmentParameter { get; private set; } | |||||
| protected override ComponentCommandParameterBuilder Instance => this; | protected override ComponentCommandParameterBuilder Instance => this; | ||||
| public ComponentCommandParameterBuilder(ICommandBuilder command) : base(command) { } | public ComponentCommandParameterBuilder(ICommandBuilder command) : base(command) { } | ||||
| @@ -25,7 +27,18 @@ namespace Discord.Interactions.Builders | |||||
| public ComponentCommandParameterBuilder SetParameterType(Type type, IServiceProvider services = null) | public ComponentCommandParameterBuilder SetParameterType(Type type, IServiceProvider services = null) | ||||
| { | { | ||||
| base.SetParameterType(type); | base.SetParameterType(type); | ||||
| TypeConverter = Command.Module.InteractionService.GetComponentTypeConverter(ParameterType, services); | |||||
| if (IsRouteSegmentParameter) | |||||
| TypeReader = Command.Module.InteractionService.GetTypeReader(type); | |||||
| else | |||||
| TypeConverter = Command.Module.InteractionService.GetComponentTypeConverter(ParameterType, services); | |||||
| return this; | |||||
| } | |||||
| public ComponentCommandParameterBuilder SetAsRouteSegment(bool isRouteSegment) | |||||
| { | |||||
| IsRouteSegmentParameter = isRouteSegment; | |||||
| return this; | return this; | ||||
| } | } | ||||
| @@ -62,19 +62,47 @@ namespace Discord.Interactions | |||||
| { | { | ||||
| var parameter = Parameters.ElementAt(i); | var parameter = Parameters.ElementAt(i); | ||||
| if (i <= captureCount) | |||||
| args[i] = wildcardCaptures.ElementAt(i); | |||||
| if (i < captureCount) | |||||
| { | |||||
| if(parameter.IsRouteSegmentParameter) | |||||
| { | |||||
| var readResult = await parameter.TypeReader.ReadAsync(context, wildcardCaptures.ElementAt(i), services).ConfigureAwait(false); | |||||
| if(!readResult.IsSuccess) | |||||
| { | |||||
| await InvokeModuleEvent(context, readResult).ConfigureAwait(false); | |||||
| return readResult; | |||||
| } | |||||
| args[i] = readResult.Value; | |||||
| } | |||||
| else | |||||
| { | |||||
| var result = ExecuteResult.FromError(InteractionCommandError.BadArgs, $"Expected Wild Card Capture, got component value"); | |||||
| await InvokeModuleEvent(context, result).ConfigureAwait(false); | |||||
| return result; | |||||
| } | |||||
| } | |||||
| else | else | ||||
| { | { | ||||
| var readResult = await parameter.TypeConverter.ReadAsync(context, data, services).ConfigureAwait(false); | |||||
| if(!parameter.IsRouteSegmentParameter) | |||||
| { | |||||
| var readResult = await parameter.TypeConverter.ReadAsync(context, data, services).ConfigureAwait(false); | |||||
| if (!readResult.IsSuccess) | |||||
| { | |||||
| await InvokeModuleEvent(context, readResult).ConfigureAwait(false); | |||||
| return readResult; | |||||
| } | |||||
| if(!readResult.IsSuccess) | |||||
| args[i] = readResult.Value; | |||||
| } | |||||
| else | |||||
| { | { | ||||
| await InvokeModuleEvent(context, readResult).ConfigureAwait(false); | |||||
| return readResult; | |||||
| var result = ExecuteResult.FromError(InteractionCommandError.BadArgs, $"Expected component value, got Wild Card capture."); | |||||
| await InvokeModuleEvent(context, result).ConfigureAwait(false); | |||||
| return result; | |||||
| } | } | ||||
| args[i] = readResult.Value; | |||||
| } | } | ||||
| } | } | ||||
| @@ -94,7 +122,7 @@ namespace Discord.Interactions | |||||
| { | { | ||||
| var parameter = paramList.ElementAt(i); | var parameter = paramList.ElementAt(i); | ||||
| if (argList?.ElementAt(i) == null) | |||||
| if (argList?.ElementAt(i) is null) | |||||
| { | { | ||||
| if (!parameter.IsRequired) | if (!parameter.IsRequired) | ||||
| result[i] = parameter.DefaultValue; | result[i] = parameter.DefaultValue; | ||||
| @@ -13,10 +13,14 @@ namespace Discord.Interactions | |||||
| /// <see cref="CommandParameterInfo.ParameterType"/>. | /// <see cref="CommandParameterInfo.ParameterType"/>. | ||||
| /// </summary> | /// </summary> | ||||
| public ComponentTypeConverter TypeConverter { get; } | public ComponentTypeConverter TypeConverter { get; } | ||||
| public TypeReader TypeReader { get; } | |||||
| public bool IsRouteSegmentParameter { get; } | |||||
| internal ComponentCommandParameterInfo(ComponentCommandParameterBuilder builder, ICommandInfo command) : base(builder, command) | internal ComponentCommandParameterInfo(ComponentCommandParameterBuilder builder, ICommandInfo command) : base(builder, command) | ||||
| { | { | ||||
| TypeConverter = builder.TypeConverter; | TypeConverter = builder.TypeConverter; | ||||
| TypeReader = builder.TypeReader; | |||||
| IsRouteSegmentParameter = builder.IsRouteSegmentParameter; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -199,8 +199,7 @@ namespace Discord.Interactions | |||||
| _compTypeConverterMap = new TypeMap<ComponentTypeConverter, IComponentInteractionData>(this, new Dictionary<Type, ComponentTypeConverter>(), | _compTypeConverterMap = new TypeMap<ComponentTypeConverter, IComponentInteractionData>(this, new Dictionary<Type, ComponentTypeConverter>(), | ||||
| new Dictionary<Type, Type> | new Dictionary<Type, Type> | ||||
| { | { | ||||
| [typeof(Array)] = typeof(DefaultArrayComponentConverter<>), | |||||
| [typeof(string)] = typeof(DefaultValueConverter<>) | |||||
| [typeof(Array)] = typeof(DefaultArrayComponentConverter<>) | |||||
| }); | }); | ||||
| _typeReaderMap = new TypeMap<TypeReader, string>(this, new Dictionary<Type, TypeReader>(), | _typeReaderMap = new TypeMap<TypeReader, string>(this, new Dictionary<Type, TypeReader>(), | ||||
| @@ -31,7 +31,7 @@ namespace Discord.Interactions | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets or sets the string expression that will be treated as a wild card. | /// Gets or sets the string expression that will be treated as a wild card. | ||||
| /// </summary> | /// </summary> | ||||
| public string WildCardExpression { get; set; } | |||||
| public string WildCardExpression { get; set; } = "*"; | |||||
| /// <summary> | /// <summary> | ||||
| /// Gets or sets the option to use compiled lambda expressions to create module instances and execute commands. This method improves performance at the cost of memory. | /// Gets or sets the option to use compiled lambda expressions to create module instances and execute commands. This method improves performance at the cost of memory. | ||||
| @@ -36,7 +36,12 @@ namespace Discord.Interactions | |||||
| results.Add(result); | results.Add(result); | ||||
| } | } | ||||
| return TypeConverterResult.FromSuccess(results.Select(x => x.Value).ToArray()); | |||||
| var destination = Array.CreateInstance(_underlyingType, results.Count); | |||||
| for (var i = 0; i < results.Count; i++) | |||||
| destination.SetValue(results[i].Value, i); | |||||
| return TypeConverterResult.FromSuccess(destination); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,17 +0,0 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| namespace Discord.Interactions.TypeConverters | |||||
| { | |||||
| internal sealed class DefaultValueComponentConverter<T> : ComponentTypeConverter<T> | |||||
| where T : class, IConvertible | |||||
| { | |||||
| public override Task<TypeConverterResult> ReadAsync(IInteractionContext context, IComponentInteractionData option, IServiceProvider services) | |||||
| { | |||||
| return Task.FromResult(TypeConverterResult.FromSuccess(Convert.ChangeType(option.Values, TypeCode.Object))); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -4,7 +4,7 @@ using System.Threading.Tasks; | |||||
| namespace Discord.Interactions | namespace Discord.Interactions | ||||
| { | { | ||||
| internal sealed class DefaultValueReader<T> : TypeReader<T> | internal sealed class DefaultValueReader<T> : TypeReader<T> | ||||
| where T : class, IConvertible | |||||
| where T : IConvertible | |||||
| { | { | ||||
| public override Task<TypeConverterResult> ReadAsync(IInteractionContext context, string option, IServiceProvider services) | public override Task<TypeConverterResult> ReadAsync(IInteractionContext context, string option, IServiceProvider services) | ||||
| { | { | ||||