Interaction Service Complex Parameters (#2155)
* Interaction Service Complex Parameters * add complex parameters * add complex parameters * fix build errors * add argument parsing * add nested complex parameter checks * add inline docs * add preferred constructor declaration * fix autocompletehandlers for complex parameters * make GetConstructor private * use flattened params in ToProps method * make DiscordType of SlashParameter nullable * add docs to Flattened parameters collection and move the GetComplexParameterCtor method * add inline docs to SlashCommandParameterBuilder.ComplexParameterFields * add check for validating required/optinal parameter order * implement change requests * return internal ParseResult as ExecuteResult Co-Authored-By: Cenk Ergen <57065323+Cenngo@users.noreply.github.com> * fix merge errors Co-authored-by: Cenk Ergen <57065323+Cenngo@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
|
||||
namespace Discord.Interactions
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers a parameter as a complex parameter.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
|
||||
public class ComplexParameterAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the parameter array of the constructor method that should be prioritized.
|
||||
/// </summary>
|
||||
public Type[] PrioritizedCtorSignature { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Registers a slash command parameter as a complex parameter.
|
||||
/// </summary>
|
||||
public ComplexParameterAttribute() { }
|
||||
|
||||
/// <summary>
|
||||
/// Registers a slash command parameter as a complex parameter with a specified constructor signature.
|
||||
/// </summary>
|
||||
/// <param name="types">Type array of the preferred constructor parameters.</param>
|
||||
public ComplexParameterAttribute(Type[] types)
|
||||
{
|
||||
PrioritizedCtorSignature = types;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Discord.Interactions
|
||||
{
|
||||
/// <summary>
|
||||
/// Tag a type constructor as the preferred Complex command constructor.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = true)]
|
||||
public class ComplexParameterCtorAttribute : Attribute { }
|
||||
}
|
||||
@@ -397,7 +397,6 @@ namespace Discord.Interactions.Builders
|
||||
builder.Description = paramInfo.Name;
|
||||
builder.IsRequired = !paramInfo.IsOptional;
|
||||
builder.DefaultValue = paramInfo.DefaultValue;
|
||||
builder.SetParameterType(paramType, services);
|
||||
|
||||
foreach (var attribute in attributes)
|
||||
{
|
||||
@@ -435,12 +434,32 @@ namespace Discord.Interactions.Builders
|
||||
case MinValueAttribute minValue:
|
||||
builder.MinValue = minValue.Value;
|
||||
break;
|
||||
case ComplexParameterAttribute complexParameter:
|
||||
{
|
||||
builder.IsComplexParameter = true;
|
||||
ConstructorInfo ctor = GetComplexParameterConstructor(paramInfo.ParameterType.GetTypeInfo(), complexParameter);
|
||||
|
||||
foreach (var parameter in ctor.GetParameters())
|
||||
{
|
||||
if (parameter.IsDefined(typeof(ComplexParameterAttribute)))
|
||||
throw new InvalidOperationException("You cannot create nested complex parameters.");
|
||||
|
||||
builder.AddComplexParameterField(fieldBuilder => BuildSlashParameter(fieldBuilder, parameter, services));
|
||||
}
|
||||
|
||||
var initializer = builder.Command.Module.InteractionService._useCompiledLambda ?
|
||||
ReflectionUtils<object>.CreateLambdaConstructorInvoker(paramInfo.ParameterType.GetTypeInfo()) : ctor.Invoke;
|
||||
builder.ComplexParameterInitializer = args => initializer(args);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
builder.AddAttributes(attribute);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
builder.SetParameterType(paramType, services);
|
||||
|
||||
// Replace pascal casings with '-'
|
||||
builder.Name = Regex.Replace(builder.Name, "(?<=[a-z])(?=[A-Z])", "-").ToLower();
|
||||
}
|
||||
@@ -608,5 +627,41 @@ namespace Discord.Interactions.Builders
|
||||
propertyInfo.SetMethod?.IsStatic == false &&
|
||||
propertyInfo.IsDefined(typeof(ModalInputAttribute));
|
||||
}
|
||||
|
||||
private static ConstructorInfo GetComplexParameterConstructor(TypeInfo typeInfo, ComplexParameterAttribute complexParameter)
|
||||
{
|
||||
var ctors = typeInfo.GetConstructors();
|
||||
|
||||
if (ctors.Length == 0)
|
||||
throw new InvalidOperationException($"No constructor found for \"{typeInfo.FullName}\".");
|
||||
|
||||
if (complexParameter.PrioritizedCtorSignature is not null)
|
||||
{
|
||||
var ctor = typeInfo.GetConstructor(complexParameter.PrioritizedCtorSignature);
|
||||
|
||||
if (ctor is null)
|
||||
throw new InvalidOperationException($"No constructor was found with the signature: {string.Join(",", complexParameter.PrioritizedCtorSignature.Select(x => x.Name))}");
|
||||
|
||||
return ctor;
|
||||
}
|
||||
|
||||
var prioritizedCtors = ctors.Where(x => x.IsDefined(typeof(ComplexParameterCtorAttribute), true));
|
||||
|
||||
switch (prioritizedCtors.Count())
|
||||
{
|
||||
case > 1:
|
||||
throw new InvalidOperationException($"{nameof(ComplexParameterCtorAttribute)} can only be used once in a type.");
|
||||
case 1:
|
||||
return prioritizedCtors.First();
|
||||
}
|
||||
|
||||
switch (ctors.Length)
|
||||
{
|
||||
case > 1:
|
||||
throw new InvalidOperationException($"Multiple constructors found for \"{typeInfo.FullName}\".");
|
||||
default:
|
||||
return ctors.First();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Discord.Interactions.Builders
|
||||
{
|
||||
@@ -10,6 +11,7 @@ namespace Discord.Interactions.Builders
|
||||
{
|
||||
private readonly List<ParameterChoice> _choices = new();
|
||||
private readonly List<ChannelType> _channelTypes = new();
|
||||
private readonly List<SlashCommandParameterBuilder> _complexParameterFields = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the description of this parameter.
|
||||
@@ -36,6 +38,11 @@ namespace Discord.Interactions.Builders
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<ChannelType> ChannelTypes => _channelTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the constructor parameters of this parameter, if <see cref="IsComplexParameter"/> is <see langword="true"/>.
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<SlashCommandParameterBuilder> ComplexParameterFields => _complexParameterFields;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether this parameter should be configured for Autocomplete Interactions.
|
||||
/// </summary>
|
||||
@@ -46,6 +53,16 @@ namespace Discord.Interactions.Builders
|
||||
/// </summary>
|
||||
public TypeConverter TypeConverter { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether this type should be treated as a complex parameter.
|
||||
/// </summary>
|
||||
public bool IsComplexParameter { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the initializer delegate for this parameter, if <see cref="IsComplexParameter"/> is <see langword="true"/>.
|
||||
/// </summary>
|
||||
public ComplexParameterInitializer ComplexParameterInitializer { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="IAutocompleteHandler"/> of this parameter.
|
||||
/// </summary>
|
||||
@@ -60,7 +77,14 @@ namespace Discord.Interactions.Builders
|
||||
/// <param name="command">Parent command of this parameter.</param>
|
||||
/// <param name="name">Name of this command.</param>
|
||||
/// <param name="type">Type of this parameter.</param>
|
||||
public SlashCommandParameterBuilder(ICommandBuilder command, string name, Type type) : base(command, name, type) { }
|
||||
public SlashCommandParameterBuilder(ICommandBuilder command, string name, Type type, ComplexParameterInitializer complexParameterInitializer = null)
|
||||
: base(command, name, type)
|
||||
{
|
||||
ComplexParameterInitializer = complexParameterInitializer;
|
||||
|
||||
if (complexParameterInitializer is not null)
|
||||
IsComplexParameter = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets <see cref="Description"/>.
|
||||
@@ -168,7 +192,47 @@ namespace Discord.Interactions.Builders
|
||||
public SlashCommandParameterBuilder SetParameterType(Type type, IServiceProvider services = null)
|
||||
{
|
||||
base.SetParameterType(type);
|
||||
TypeConverter = Command.Module.InteractionService.GetTypeConverter(ParameterType, services);
|
||||
|
||||
if(!IsComplexParameter)
|
||||
TypeConverter = Command.Module.InteractionService.GetTypeConverter(ParameterType, services);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a parameter builders to <see cref="ComplexParameterFields"/>.
|
||||
/// </summary>
|
||||
/// <param name="configure"><see cref="SlashCommandParameterBuilder"/> factory.</param>
|
||||
/// <returns>
|
||||
/// The builder instance.
|
||||
/// </returns>
|
||||
/// <exception cref="InvalidOperationException">Thrown if the added field has a <see cref="ComplexParameterAttribute"/>.</exception>
|
||||
public SlashCommandParameterBuilder AddComplexParameterField(Action<SlashCommandParameterBuilder> configure)
|
||||
{
|
||||
SlashCommandParameterBuilder builder = new(Command);
|
||||
configure(builder);
|
||||
|
||||
if(builder.IsComplexParameter)
|
||||
throw new InvalidOperationException("You cannot create nested complex parameters.");
|
||||
|
||||
_complexParameterFields.Add(builder);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds parameter builders to <see cref="ComplexParameterFields"/>.
|
||||
/// </summary>
|
||||
/// <param name="fields">New parameter builders to be added to <see cref="ComplexParameterFields"/>.</param>
|
||||
/// <returns>
|
||||
/// The builder instance.
|
||||
/// </returns>
|
||||
/// <exception cref="InvalidOperationException">Thrown if the added field has a <see cref="ComplexParameterAttribute"/>.</exception>
|
||||
public SlashCommandParameterBuilder AddComplexParameterFields(params SlashCommandParameterBuilder[] fields)
|
||||
{
|
||||
if(fields.Any(x => x.IsComplexParameter))
|
||||
throw new InvalidOperationException("You cannot create nested complex parameters.");
|
||||
|
||||
_complexParameterFields.AddRange(fields);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ namespace Discord.Interactions
|
||||
private readonly ExecuteCallback _action;
|
||||
private readonly ILookup<string, PreconditionAttribute> _groupedPreconditions;
|
||||
|
||||
internal IReadOnlyDictionary<string, TParameter> _parameterDictionary { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ModuleInfo Module { get; }
|
||||
|
||||
@@ -79,6 +81,7 @@ namespace Discord.Interactions
|
||||
|
||||
_action = builder.Callback;
|
||||
_groupedPreconditions = builder.Preconditions.ToLookup(x => x.Group, x => x, StringComparer.Ordinal);
|
||||
_parameterDictionary = Parameters?.ToDictionary(x => x.Name, x => x).ToImmutableDictionary();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace Discord.Interactions
|
||||
/// </summary>
|
||||
public class SlashCommandInfo : CommandInfo<SlashCommandParameterInfo>, IApplicationCommandInfo
|
||||
{
|
||||
internal IReadOnlyDictionary<string, SlashCommandParameterInfo> _flattenedParameterDictionary { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the command description that will be displayed on Discord.
|
||||
/// </summary>
|
||||
@@ -30,11 +32,23 @@ namespace Discord.Interactions
|
||||
/// <inheritdoc/>
|
||||
public override bool SupportsWildCards => false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the flattened collection of command parameters and complex parameter fields.
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<SlashCommandParameterInfo> FlattenedParameters { get; }
|
||||
|
||||
internal SlashCommandInfo (Builders.SlashCommandBuilder builder, ModuleInfo module, InteractionService commandService) : base(builder, module, commandService)
|
||||
{
|
||||
Description = builder.Description;
|
||||
DefaultPermission = builder.DefaultPermission;
|
||||
Parameters = builder.Parameters.Select(x => x.Build(this)).ToImmutableArray();
|
||||
FlattenedParameters = FlattenParameters(Parameters).ToImmutableArray();
|
||||
|
||||
for (var i = 0; i < FlattenedParameters.Count - 1; i++)
|
||||
if (!FlattenedParameters.ElementAt(i).IsRequired && FlattenedParameters.ElementAt(i + 1).IsRequired)
|
||||
throw new InvalidOperationException("Optional parameters must appear after all required parameters, ComplexParameters with optional parameters must be located at the end.");
|
||||
|
||||
_flattenedParameterDictionary = FlattenedParameters?.ToDictionary(x => x.Name, x => x).ToImmutableDictionary();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -56,45 +70,81 @@ namespace Discord.Interactions
|
||||
{
|
||||
try
|
||||
{
|
||||
if (paramList?.Count() < argList?.Count())
|
||||
return ExecuteResult.FromError(InteractionCommandError.BadArgs ,"Command was invoked with too many parameters");
|
||||
|
||||
var args = new object[paramList.Count()];
|
||||
|
||||
for (var i = 0; i < paramList.Count(); i++)
|
||||
{
|
||||
var parameter = paramList.ElementAt(i);
|
||||
|
||||
var arg = argList?.Find(x => string.Equals(x.Name, parameter.Name, StringComparison.OrdinalIgnoreCase));
|
||||
var result = await ParseArgument(parameter, context, argList, services).ConfigureAwait(false);
|
||||
|
||||
if (arg == default)
|
||||
if(!result.IsSuccess)
|
||||
{
|
||||
if (parameter.IsRequired)
|
||||
return ExecuteResult.FromError(InteractionCommandError.BadArgs, "Command was invoked with too few parameters");
|
||||
else
|
||||
args[i] = parameter.DefaultValue;
|
||||
var execResult = ExecuteResult.FromError(result);
|
||||
await InvokeModuleEvent(context, execResult).ConfigureAwait(false);
|
||||
return execResult;
|
||||
}
|
||||
|
||||
if (result is ParseResult parseResult)
|
||||
args[i] = parseResult.Value;
|
||||
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;
|
||||
}
|
||||
return ExecuteResult.FromError(InteractionCommandError.BadArgs, "Command parameter parsing failed for an unknown reason.");
|
||||
}
|
||||
|
||||
return await RunAsync(context, args, services).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ExecuteResult.FromError(ex);
|
||||
var result = ExecuteResult.FromError(ex);
|
||||
await InvokeModuleEvent(context, result).ConfigureAwait(false);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
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 ParseResult parseResult)
|
||||
ctorArgs[i] = parseResult.Value;
|
||||
else
|
||||
return ExecuteResult.FromError(InteractionCommandError.BadArgs, "Complex command parsing failed for an unknown reason.");
|
||||
}
|
||||
|
||||
return ParseResult.FromSuccess(parameterInfo._complexParameterInitializer(ctorArgs));
|
||||
}
|
||||
else
|
||||
{
|
||||
var arg = argList?.Find(x => string.Equals(x.Name, parameterInfo.Name, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (arg == default)
|
||||
{
|
||||
if (parameterInfo.IsRequired)
|
||||
return ExecuteResult.FromError(InteractionCommandError.BadArgs, "Command was invoked with too few parameters");
|
||||
else
|
||||
return ParseResult.FromSuccess(parameterInfo.DefaultValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
var typeConverter = parameterInfo.TypeConverter;
|
||||
|
||||
var readResult = await typeConverter.ReadAsync(context, arg, services).ConfigureAwait(false);
|
||||
|
||||
if (!readResult.IsSuccess)
|
||||
return readResult;
|
||||
|
||||
return ParseResult.FromSuccess(readResult.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,5 +158,15 @@ namespace Discord.Interactions
|
||||
else
|
||||
return $"Slash Command: \"{base.ToString()}\" for {context.User} in {context.Channel}";
|
||||
}
|
||||
|
||||
private static IEnumerable<SlashCommandParameterInfo> FlattenParameters(IEnumerable<SlashCommandParameterInfo> parameters)
|
||||
{
|
||||
foreach (var parameter in parameters)
|
||||
if (!parameter.IsComplexParameter)
|
||||
yield return parameter;
|
||||
else
|
||||
foreach(var complexParameterField in parameter.ComplexParameterFields)
|
||||
yield return complexParameterField;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
namespace Discord.Interactions
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a cached argument constructor delegate.
|
||||
/// </summary>
|
||||
/// <param name="args">Method arguments array.</param>
|
||||
/// <returns>
|
||||
/// Returns the constructed object.
|
||||
/// </returns>
|
||||
public delegate object ComplexParameterInitializer(object[] args);
|
||||
|
||||
/// <summary>
|
||||
/// Represents the parameter info class for <see cref="SlashCommandInfo"/> commands.
|
||||
/// </summary>
|
||||
public class SlashCommandParameterInfo : CommandParameterInfo
|
||||
{
|
||||
internal readonly ComplexParameterInitializer _complexParameterInitializer;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public new SlashCommandInfo Command => base.Command as SlashCommandInfo;
|
||||
|
||||
@@ -43,9 +55,14 @@ namespace Discord.Interactions
|
||||
public bool IsAutocomplete { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Discord option type this parameter represents.
|
||||
/// Gets whether this type should be treated as a complex parameter.
|
||||
/// </summary>
|
||||
public ApplicationCommandOptionType DiscordOptionType => TypeConverter.GetDiscordType();
|
||||
public bool IsComplexParameter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Discord option type this parameter represents. If the parameter is not a complex parameter.
|
||||
/// </summary>
|
||||
public ApplicationCommandOptionType? DiscordOptionType => TypeConverter?.GetDiscordType();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parameter choices of this Slash Application Command parameter.
|
||||
@@ -57,6 +74,11 @@ namespace Discord.Interactions
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<ChannelType> ChannelTypes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the constructor parameters of this parameter, if <see cref="IsComplexParameter"/> is <see langword="true"/>.
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<SlashCommandParameterInfo> ComplexParameterFields { get; }
|
||||
|
||||
internal SlashCommandParameterInfo(Builders.SlashCommandParameterBuilder builder, SlashCommandInfo command) : base(builder, command)
|
||||
{
|
||||
TypeConverter = builder.TypeConverter;
|
||||
@@ -64,9 +86,13 @@ namespace Discord.Interactions
|
||||
Description = builder.Description;
|
||||
MaxValue = builder.MaxValue;
|
||||
MinValue = builder.MinValue;
|
||||
IsComplexParameter = builder.IsComplexParameter;
|
||||
IsAutocomplete = builder.Autocomplete;
|
||||
Choices = builder.Choices.ToImmutableArray();
|
||||
ChannelTypes = builder.ChannelTypes.ToImmutableArray();
|
||||
ComplexParameterFields = builder.ComplexParameterFields?.Select(x => x.Build(command)).ToImmutableArray();
|
||||
|
||||
_complexParameterInitializer = builder.ComplexParameterInitializer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -747,9 +747,7 @@ namespace Discord.Interactions
|
||||
|
||||
if(autocompleteHandlerResult.IsSuccess)
|
||||
{
|
||||
var parameter = autocompleteHandlerResult.Command.Parameters.FirstOrDefault(x => string.Equals(x.Name, interaction.Data.Current.Name, StringComparison.Ordinal));
|
||||
|
||||
if(parameter?.AutocompleteHandler is not null)
|
||||
if (autocompleteHandlerResult.Command._flattenedParameterDictionary.TryGetValue(interaction.Data.Current.Name, out var parameter) && parameter?.AutocompleteHandler is not null)
|
||||
return await parameter.AutocompleteHandler.ExecuteAsync(context, interaction, parameter, services).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
36
src/Discord.Net.Interactions/Results/ParseResult.cs
Normal file
36
src/Discord.Net.Interactions/Results/ParseResult.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
|
||||
namespace Discord.Interactions
|
||||
{
|
||||
internal struct ParseResult : IResult
|
||||
{
|
||||
public object Value { get; }
|
||||
|
||||
public InteractionCommandError? Error { get; }
|
||||
|
||||
public string ErrorReason { get; }
|
||||
|
||||
public bool IsSuccess => !Error.HasValue;
|
||||
|
||||
private ParseResult(object value, InteractionCommandError? error, string reason)
|
||||
{
|
||||
Value = value;
|
||||
Error = error;
|
||||
ErrorReason = reason;
|
||||
}
|
||||
|
||||
public static ParseResult FromSuccess(object value) =>
|
||||
new ParseResult(value, null, null);
|
||||
|
||||
public static ParseResult FromError(Exception exception) =>
|
||||
new ParseResult(null, InteractionCommandError.Exception, exception.Message);
|
||||
|
||||
public static ParseResult FromError(InteractionCommandError error, string reason) =>
|
||||
new ParseResult(null, error, reason);
|
||||
|
||||
public static ParseResult FromError(IResult result) =>
|
||||
new ParseResult(null, result.Error, result.ErrorReason);
|
||||
|
||||
public override string ToString() => IsSuccess ? "Success" : $"{Error}: {ErrorReason}";
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ namespace Discord.Interactions
|
||||
{
|
||||
Name = parameterInfo.Name,
|
||||
Description = parameterInfo.Description,
|
||||
Type = parameterInfo.DiscordOptionType,
|
||||
Type = parameterInfo.DiscordOptionType.Value,
|
||||
IsRequired = parameterInfo.IsRequired,
|
||||
Choices = parameterInfo.Choices?.Select(x => new ApplicationCommandOptionChoiceProperties
|
||||
{
|
||||
@@ -46,7 +46,7 @@ namespace Discord.Interactions
|
||||
if (commandInfo.Parameters.Count > SlashCommandBuilder.MaxOptionsCount)
|
||||
throw new InvalidOperationException($"Slash Commands cannot have more than {SlashCommandBuilder.MaxOptionsCount} command parameters");
|
||||
|
||||
props.Options = commandInfo.Parameters.Select(x => x.ToApplicationCommandOptionProps())?.ToList() ?? Optional<List<ApplicationCommandOptionProperties>>.Unspecified;
|
||||
props.Options = commandInfo.FlattenedParameters.Select(x => x.ToApplicationCommandOptionProps())?.ToList() ?? Optional<List<ApplicationCommandOptionProperties>>.Unspecified;
|
||||
|
||||
return props;
|
||||
}
|
||||
@@ -58,7 +58,7 @@ namespace Discord.Interactions
|
||||
Description = commandInfo.Description,
|
||||
Type = ApplicationCommandOptionType.SubCommand,
|
||||
IsRequired = false,
|
||||
Options = commandInfo.Parameters?.Select(x => x.ToApplicationCommandOptionProps())?.ToList()
|
||||
Options = commandInfo.FlattenedParameters?.Select(x => x.ToApplicationCommandOptionProps())?.ToList()
|
||||
};
|
||||
|
||||
public static ApplicationCommandProperties ToApplicationCommandProps(this ContextCommandInfo commandInfo)
|
||||
|
||||
Reference in New Issue
Block a user