Browse Source

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>
tags/3.4.0
Quin Lynch GitHub 3 years ago
parent
commit
9ba64f62d1
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 315 additions and 33 deletions
  1. +30
    -0
      src/Discord.Net.Interactions/Attributes/ComplexParameterAttribute.cs
  2. +10
    -0
      src/Discord.Net.Interactions/Attributes/ComplexParameterCtorAttribute.cs
  3. +56
    -1
      src/Discord.Net.Interactions/Builders/ModuleClassBuilder.cs
  4. +66
    -2
      src/Discord.Net.Interactions/Builders/Parameters/SlashCommandParameterBuilder.cs
  5. +3
    -0
      src/Discord.Net.Interactions/Info/Commands/CommandInfo.cs
  6. +82
    -22
      src/Discord.Net.Interactions/Info/Commands/SlashCommandInfo.cs
  7. +28
    -2
      src/Discord.Net.Interactions/Info/Parameters/SlashCommandParameterInfo.cs
  8. +1
    -3
      src/Discord.Net.Interactions/InteractionService.cs
  9. +36
    -0
      src/Discord.Net.Interactions/Results/ParseResult.cs
  10. +3
    -3
      src/Discord.Net.Interactions/Utilities/ApplicationCommandRestUtil.cs

+ 30
- 0
src/Discord.Net.Interactions/Attributes/ComplexParameterAttribute.cs View File

@@ -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;
}
}
}

+ 10
- 0
src/Discord.Net.Interactions/Attributes/ComplexParameterCtorAttribute.cs View File

@@ -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 { }
}

+ 56
- 1
src/Discord.Net.Interactions/Builders/ModuleClassBuilder.cs View File

@@ -397,7 +397,6 @@ namespace Discord.Interactions.Builders
builder.Description = paramInfo.Name; builder.Description = paramInfo.Name;
builder.IsRequired = !paramInfo.IsOptional; builder.IsRequired = !paramInfo.IsOptional;
builder.DefaultValue = paramInfo.DefaultValue; builder.DefaultValue = paramInfo.DefaultValue;
builder.SetParameterType(paramType, services);


foreach (var attribute in attributes) foreach (var attribute in attributes)
{ {
@@ -435,12 +434,32 @@ namespace Discord.Interactions.Builders
case MinValueAttribute minValue: case MinValueAttribute minValue:
builder.MinValue = minValue.Value; builder.MinValue = minValue.Value;
break; 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: default:
builder.AddAttributes(attribute); builder.AddAttributes(attribute);
break; break;
} }
} }


builder.SetParameterType(paramType, services);

// Replace pascal casings with '-' // Replace pascal casings with '-'
builder.Name = Regex.Replace(builder.Name, "(?<=[a-z])(?=[A-Z])", "-").ToLower(); builder.Name = Regex.Replace(builder.Name, "(?<=[a-z])(?=[A-Z])", "-").ToLower();
} }
@@ -608,5 +627,41 @@ namespace Discord.Interactions.Builders
propertyInfo.SetMethod?.IsStatic == false && propertyInfo.SetMethod?.IsStatic == false &&
propertyInfo.IsDefined(typeof(ModalInputAttribute)); 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();
}
}
} }
} }

+ 66
- 2
src/Discord.Net.Interactions/Builders/Parameters/SlashCommandParameterBuilder.cs View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;


namespace Discord.Interactions.Builders namespace Discord.Interactions.Builders
{ {
@@ -10,6 +11,7 @@ namespace Discord.Interactions.Builders
{ {
private readonly List<ParameterChoice> _choices = new(); private readonly List<ParameterChoice> _choices = new();
private readonly List<ChannelType> _channelTypes = new(); private readonly List<ChannelType> _channelTypes = new();
private readonly List<SlashCommandParameterBuilder> _complexParameterFields = new();


/// <summary> /// <summary>
/// Gets or sets the description of this parameter. /// Gets or sets the description of this parameter.
@@ -36,6 +38,11 @@ namespace Discord.Interactions.Builders
/// </summary> /// </summary>
public IReadOnlyCollection<ChannelType> ChannelTypes => _channelTypes; 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> /// <summary>
/// Gets or sets whether this parameter should be configured for Autocomplete Interactions. /// Gets or sets whether this parameter should be configured for Autocomplete Interactions.
/// </summary> /// </summary>
@@ -46,6 +53,16 @@ namespace Discord.Interactions.Builders
/// </summary> /// </summary>
public TypeConverter TypeConverter { get; private set; } 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> /// <summary>
/// Gets or sets the <see cref="IAutocompleteHandler"/> of this parameter. /// Gets or sets the <see cref="IAutocompleteHandler"/> of this parameter.
/// </summary> /// </summary>
@@ -60,7 +77,14 @@ namespace Discord.Interactions.Builders
/// <param name="command">Parent command of this parameter.</param> /// <param name="command">Parent command of this parameter.</param>
/// <param name="name">Name of this command.</param> /// <param name="name">Name of this command.</param>
/// <param name="type">Type of this parameter.</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> /// <summary>
/// Sets <see cref="Description"/>. /// Sets <see cref="Description"/>.
@@ -168,7 +192,47 @@ namespace Discord.Interactions.Builders
public SlashCommandParameterBuilder SetParameterType(Type type, IServiceProvider services = null) public SlashCommandParameterBuilder SetParameterType(Type type, IServiceProvider services = null)
{ {
base.SetParameterType(type); 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; return this;
} }




+ 3
- 0
src/Discord.Net.Interactions/Info/Commands/CommandInfo.cs View File

@@ -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 { get; }

/// <inheritdoc/> /// <inheritdoc/>
public ModuleInfo Module { get; } public ModuleInfo Module { get; }


@@ -79,6 +81,7 @@ namespace Discord.Interactions


_action = builder.Callback; _action = builder.Callback;
_groupedPreconditions = builder.Preconditions.ToLookup(x => x.Group, x => x, StringComparer.Ordinal); _groupedPreconditions = builder.Preconditions.ToLookup(x => x.Group, x => x, StringComparer.Ordinal);
_parameterDictionary = Parameters?.ToDictionary(x => x.Name, x => x).ToImmutableDictionary();
} }


/// <inheritdoc/> /// <inheritdoc/>


+ 82
- 22
src/Discord.Net.Interactions/Info/Commands/SlashCommandInfo.cs View File

@@ -13,6 +13,8 @@ namespace Discord.Interactions
/// </summary> /// </summary>
public class SlashCommandInfo : CommandInfo<SlashCommandParameterInfo>, IApplicationCommandInfo public class SlashCommandInfo : CommandInfo<SlashCommandParameterInfo>, IApplicationCommandInfo
{ {
internal IReadOnlyDictionary<string, SlashCommandParameterInfo> _flattenedParameterDictionary { get; }

/// <summary> /// <summary>
/// Gets the command description that will be displayed on Discord. /// Gets the command description that will be displayed on Discord.
/// </summary> /// </summary>
@@ -30,11 +32,23 @@ namespace Discord.Interactions
/// <inheritdoc/> /// <inheritdoc/>
public override bool SupportsWildCards => false; 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) internal SlashCommandInfo (Builders.SlashCommandBuilder builder, ModuleInfo module, InteractionService commandService) : base(builder, module, commandService)
{ {
Description = builder.Description; Description = builder.Description;
DefaultPermission = builder.DefaultPermission; DefaultPermission = builder.DefaultPermission;
Parameters = builder.Parameters.Select(x => x.Build(this)).ToImmutableArray(); 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/> /// <inheritdoc/>
@@ -56,45 +70,81 @@ namespace Discord.Interactions
{ {
try try
{ {
if (paramList?.Count() < argList?.Count())
return ExecuteResult.FromError(InteractionCommandError.BadArgs ,"Command was invoked with too many parameters");

var args = new object[paramList.Count()]; var args = new object[paramList.Count()];


for (var i = 0; i < paramList.Count(); i++) for (var i = 0; i < paramList.Count(); i++)
{ {
var parameter = paramList.ElementAt(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 else
{
var typeConverter = parameter.TypeConverter;
return ExecuteResult.FromError(InteractionCommandError.BadArgs, "Command parameter parsing failed for an unknown reason.");
}


var readResult = await typeConverter.ReadAsync(context, arg, services).ConfigureAwait(false);
return await RunAsync(context, args, services).ConfigureAwait(false);
}
catch (Exception ex)
{
var result = ExecuteResult.FromError(ex);
await InvokeModuleEvent(context, result).ConfigureAwait(false);
return result;
}
}


if (!readResult.IsSuccess)
{
await InvokeModuleEvent(context, readResult).ConfigureAwait(false);
return readResult;
}
private async Task<IResult> ParseArgument(SlashCommandParameterInfo parameterInfo, IInteractionContext context, List<IApplicationCommandInteractionDataOption> argList,
IServiceProvider services)
{
if (parameterInfo.IsComplexParameter)
{
var ctorArgs = new object[parameterInfo.ComplexParameterFields.Count];


args[i] = readResult.Value;
}
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 await RunAsync(context, args, services).ConfigureAwait(false);
return ParseResult.FromSuccess(parameterInfo._complexParameterInitializer(ctorArgs));
} }
catch (Exception ex)
else
{ {
return ExecuteResult.FromError(ex);
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 else
return $"Slash Command: \"{base.ToString()}\" for {context.User} in {context.Channel}"; 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;
}
} }
} }

+ 28
- 2
src/Discord.Net.Interactions/Info/Parameters/SlashCommandParameterInfo.cs View File

@@ -1,13 +1,25 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq;


namespace Discord.Interactions 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> /// <summary>
/// Represents the parameter info class for <see cref="SlashCommandInfo"/> commands. /// Represents the parameter info class for <see cref="SlashCommandInfo"/> commands.
/// </summary> /// </summary>
public class SlashCommandParameterInfo : CommandParameterInfo public class SlashCommandParameterInfo : CommandParameterInfo
{ {
internal readonly ComplexParameterInitializer _complexParameterInitializer;

/// <inheritdoc/> /// <inheritdoc/>
public new SlashCommandInfo Command => base.Command as SlashCommandInfo; public new SlashCommandInfo Command => base.Command as SlashCommandInfo;


@@ -43,9 +55,14 @@ namespace Discord.Interactions
public bool IsAutocomplete { get; } public bool IsAutocomplete { get; }


/// <summary> /// <summary>
/// Gets the Discord option type this parameter represents.
/// Gets whether this type should be treated as a complex parameter.
/// </summary> /// </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> /// <summary>
/// Gets the parameter choices of this Slash Application Command parameter. /// Gets the parameter choices of this Slash Application Command parameter.
@@ -57,6 +74,11 @@ namespace Discord.Interactions
/// </summary> /// </summary>
public IReadOnlyCollection<ChannelType> ChannelTypes { get; } 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) internal SlashCommandParameterInfo(Builders.SlashCommandParameterBuilder builder, SlashCommandInfo command) : base(builder, command)
{ {
TypeConverter = builder.TypeConverter; TypeConverter = builder.TypeConverter;
@@ -64,9 +86,13 @@ namespace Discord.Interactions
Description = builder.Description; Description = builder.Description;
MaxValue = builder.MaxValue; MaxValue = builder.MaxValue;
MinValue = builder.MinValue; MinValue = builder.MinValue;
IsComplexParameter = builder.IsComplexParameter;
IsAutocomplete = builder.Autocomplete; IsAutocomplete = builder.Autocomplete;
Choices = builder.Choices.ToImmutableArray(); Choices = builder.Choices.ToImmutableArray();
ChannelTypes = builder.ChannelTypes.ToImmutableArray(); ChannelTypes = builder.ChannelTypes.ToImmutableArray();
ComplexParameterFields = builder.ComplexParameterFields?.Select(x => x.Build(command)).ToImmutableArray();

_complexParameterInitializer = builder.ComplexParameterInitializer;
} }
} }
} }

+ 1
- 3
src/Discord.Net.Interactions/InteractionService.cs View File

@@ -747,9 +747,7 @@ namespace Discord.Interactions


if(autocompleteHandlerResult.IsSuccess) 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); return await parameter.AutocompleteHandler.ExecuteAsync(context, interaction, parameter, services).ConfigureAwait(false);
} }
} }


+ 36
- 0
src/Discord.Net.Interactions/Results/ParseResult.cs View 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}";
}
}

+ 3
- 3
src/Discord.Net.Interactions/Utilities/ApplicationCommandRestUtil.cs View File

@@ -13,7 +13,7 @@ namespace Discord.Interactions
{ {
Name = parameterInfo.Name, Name = parameterInfo.Name,
Description = parameterInfo.Description, Description = parameterInfo.Description,
Type = parameterInfo.DiscordOptionType,
Type = parameterInfo.DiscordOptionType.Value,
IsRequired = parameterInfo.IsRequired, IsRequired = parameterInfo.IsRequired,
Choices = parameterInfo.Choices?.Select(x => new ApplicationCommandOptionChoiceProperties Choices = parameterInfo.Choices?.Select(x => new ApplicationCommandOptionChoiceProperties
{ {
@@ -46,7 +46,7 @@ namespace Discord.Interactions
if (commandInfo.Parameters.Count > SlashCommandBuilder.MaxOptionsCount) if (commandInfo.Parameters.Count > SlashCommandBuilder.MaxOptionsCount)
throw new InvalidOperationException($"Slash Commands cannot have more than {SlashCommandBuilder.MaxOptionsCount} command parameters"); 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; return props;
} }
@@ -58,7 +58,7 @@ namespace Discord.Interactions
Description = commandInfo.Description, Description = commandInfo.Description,
Type = ApplicationCommandOptionType.SubCommand, Type = ApplicationCommandOptionType.SubCommand,
IsRequired = false, 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) public static ApplicationCommandProperties ToApplicationCommandProps(this ContextCommandInfo commandInfo)


Loading…
Cancel
Save