diff --git a/src/Discord.Net.Interactions/Builders/ModuleClassBuilder.cs b/src/Discord.Net.Interactions/Builders/ModuleClassBuilder.cs index 94db3bb84..c163ec83d 100644 --- a/src/Discord.Net.Interactions/Builders/ModuleClassBuilder.cs +++ b/src/Discord.Net.Interactions/Builders/ModuleClassBuilder.cs @@ -257,8 +257,10 @@ namespace Discord.Interactions.Builders var parameters = methodInfo.GetParameters(); + var wildCardCount = Regex.Matches(Regex.Escape(builder.Name), Regex.Escape(commandService._wildCardExp)).Count; + 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); } @@ -442,10 +444,11 @@ namespace Discord.Interactions.Builders 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 (ParameterBuilder builder, ParameterInfo paramInfo) diff --git a/src/Discord.Net.Interactions/Builders/Parameters/ComponentCommandParameterBuilder.cs b/src/Discord.Net.Interactions/Builders/Parameters/ComponentCommandParameterBuilder.cs index 4a8770c9a..81f4d05c8 100644 --- a/src/Discord.Net.Interactions/Builders/Parameters/ComponentCommandParameterBuilder.cs +++ b/src/Discord.Net.Interactions/Builders/Parameters/ComponentCommandParameterBuilder.cs @@ -5,6 +5,8 @@ namespace Discord.Interactions.Builders public class ComponentCommandParameterBuilder : ParameterBuilder { public ComponentTypeConverter TypeConverter { get; private set; } + public TypeReader TypeReader { get; private set; } + public bool IsRouteSegmentParameter { get; private set; } protected override ComponentCommandParameterBuilder Instance => this; public ComponentCommandParameterBuilder(ICommandBuilder command) : base(command) { } @@ -25,7 +27,18 @@ namespace Discord.Interactions.Builders public ComponentCommandParameterBuilder SetParameterType(Type type, IServiceProvider services = null) { 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; } diff --git a/src/Discord.Net.Interactions/Info/Commands/ComponentCommandInfo.cs b/src/Discord.Net.Interactions/Info/Commands/ComponentCommandInfo.cs index fa2836b22..f66690ca0 100644 --- a/src/Discord.Net.Interactions/Info/Commands/ComponentCommandInfo.cs +++ b/src/Discord.Net.Interactions/Info/Commands/ComponentCommandInfo.cs @@ -62,19 +62,47 @@ namespace Discord.Interactions { 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 { - 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); - if (argList?.ElementAt(i) == null) + if (argList?.ElementAt(i) is null) { if (!parameter.IsRequired) result[i] = parameter.DefaultValue; diff --git a/src/Discord.Net.Interactions/Info/Parameters/ComponentCommandParameterInfo.cs b/src/Discord.Net.Interactions/Info/Parameters/ComponentCommandParameterInfo.cs index ec71617a3..d281f681a 100644 --- a/src/Discord.Net.Interactions/Info/Parameters/ComponentCommandParameterInfo.cs +++ b/src/Discord.Net.Interactions/Info/Parameters/ComponentCommandParameterInfo.cs @@ -13,10 +13,14 @@ namespace Discord.Interactions /// . /// public ComponentTypeConverter TypeConverter { get; } + public TypeReader TypeReader { get; } + public bool IsRouteSegmentParameter { get; } internal ComponentCommandParameterInfo(ComponentCommandParameterBuilder builder, ICommandInfo command) : base(builder, command) { TypeConverter = builder.TypeConverter; + TypeReader = builder.TypeReader; + IsRouteSegmentParameter = builder.IsRouteSegmentParameter; } } } diff --git a/src/Discord.Net.Interactions/InteractionService.cs b/src/Discord.Net.Interactions/InteractionService.cs index f3feafa96..536a82607 100644 --- a/src/Discord.Net.Interactions/InteractionService.cs +++ b/src/Discord.Net.Interactions/InteractionService.cs @@ -199,8 +199,7 @@ namespace Discord.Interactions _compTypeConverterMap = new TypeMap(this, new Dictionary(), new Dictionary { - [typeof(Array)] = typeof(DefaultArrayComponentConverter<>), - [typeof(string)] = typeof(DefaultValueConverter<>) + [typeof(Array)] = typeof(DefaultArrayComponentConverter<>) }); _typeReaderMap = new TypeMap(this, new Dictionary(), diff --git a/src/Discord.Net.Interactions/InteractionServiceConfig.cs b/src/Discord.Net.Interactions/InteractionServiceConfig.cs index 136cba24c..b6576a49f 100644 --- a/src/Discord.Net.Interactions/InteractionServiceConfig.cs +++ b/src/Discord.Net.Interactions/InteractionServiceConfig.cs @@ -31,7 +31,7 @@ namespace Discord.Interactions /// /// Gets or sets the string expression that will be treated as a wild card. /// - public string WildCardExpression { get; set; } + public string WildCardExpression { get; set; } = "*"; /// /// 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. diff --git a/src/Discord.Net.Interactions/TypeConverters/ComponentInteractions/DefaultArrayComponentConverter.cs b/src/Discord.Net.Interactions/TypeConverters/ComponentInteractions/DefaultArrayComponentConverter.cs index b17320bbe..043019013 100644 --- a/src/Discord.Net.Interactions/TypeConverters/ComponentInteractions/DefaultArrayComponentConverter.cs +++ b/src/Discord.Net.Interactions/TypeConverters/ComponentInteractions/DefaultArrayComponentConverter.cs @@ -36,7 +36,12 @@ namespace Discord.Interactions 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); } } } diff --git a/src/Discord.Net.Interactions/TypeConverters/ComponentInteractions/DefaultValueComponentConverter.cs b/src/Discord.Net.Interactions/TypeConverters/ComponentInteractions/DefaultValueComponentConverter.cs deleted file mode 100644 index 7ee45b2f9..000000000 --- a/src/Discord.Net.Interactions/TypeConverters/ComponentInteractions/DefaultValueComponentConverter.cs +++ /dev/null @@ -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 : ComponentTypeConverter - where T : class, IConvertible - { - public override Task ReadAsync(IInteractionContext context, IComponentInteractionData option, IServiceProvider services) - { - return Task.FromResult(TypeConverterResult.FromSuccess(Convert.ChangeType(option.Values, TypeCode.Object))); - } - } -} diff --git a/src/Discord.Net.Interactions/TypeReaders/DefaultValueReader.cs b/src/Discord.Net.Interactions/TypeReaders/DefaultValueReader.cs index 498b99e02..e833382a6 100644 --- a/src/Discord.Net.Interactions/TypeReaders/DefaultValueReader.cs +++ b/src/Discord.Net.Interactions/TypeReaders/DefaultValueReader.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; namespace Discord.Interactions { internal sealed class DefaultValueReader : TypeReader - where T : class, IConvertible + where T : IConvertible { public override Task ReadAsync(IInteractionContext context, string option, IServiceProvider services) {