From 6ba456a1d681562c07f62881b831f6c39dcfc5cd Mon Sep 17 00:00:00 2001 From: Cosma George Date: Tue, 16 Feb 2021 17:36:18 +0200 Subject: [PATCH] Implemented [Choice( [] , [] )] and [Required] Attributes. Details: There is nothing really to be said, it's simple and self-explanatory. The only thing I would want to implement is to add support for bool? and int? param types because, as of now, you don't know if the user passed False or just didn't pass anything. In any case, I personally don't suspect it's going to be hard to do. After I implement this I will create a PR on the original Discord.Net Repo. --- SlashCommandsExample/Modules/DevModule.cs | 20 ++++++++- .../SlashCommands/Attributes/Choice.cs | 41 +++++++++++++++++++ .../SlashCommands/Attributes/Required.cs | 16 ++++++++ .../SlashCommandServiceHelper.cs | 28 ++++++++++++- 4 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 src/Discord.Net.Commands/SlashCommands/Attributes/Choice.cs create mode 100644 src/Discord.Net.Commands/SlashCommands/Attributes/Required.cs diff --git a/SlashCommandsExample/Modules/DevModule.cs b/SlashCommandsExample/Modules/DevModule.cs index 4ff82e0de..d2079573f 100644 --- a/SlashCommandsExample/Modules/DevModule.cs +++ b/SlashCommandsExample/Modules/DevModule.cs @@ -21,7 +21,10 @@ namespace SlashCommandsExample.Modules } [SlashCommand("echo", "I'll repeate everything you said to me, word for word.")] - public async Task EchoAsync([Description("The message you want repetead")]string message) + public async Task EchoAsync( + [Description("The message you want repetead")] + [Required] + string message) { await Reply($"{Interaction.Member?.Nickname ?? Interaction.Member?.Username} told me to say this: \r\n{message}"); } @@ -40,6 +43,21 @@ namespace SlashCommandsExample.Modules } + [SlashCommand("stats","Get the stats from Game(tm) for players or teams.")] + public async Task GetStatsAsync( + [Required] + [Choice("XBOX","xbox")] + [Choice("PlayStation","ps")] + [Choice("PC","pc")] + string platform, + [Choice("Player",1)] + [Choice("Team",2)] + int searchType + ) + { + await Reply($"Well I got this: {platform}, {searchType}"); + } + [CommandGroup("root")] //[Global] public class DevModule_Root : SlashCommandModule diff --git a/src/Discord.Net.Commands/SlashCommands/Attributes/Choice.cs b/src/Discord.Net.Commands/SlashCommands/Attributes/Choice.cs new file mode 100644 index 000000000..a71c16b23 --- /dev/null +++ b/src/Discord.Net.Commands/SlashCommands/Attributes/Choice.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.SlashCommands +{ + /// + /// Defines the parameter as a choice. + /// + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true)] + public class Choice : Attribute + { + /// + /// The internal value of this choice. + /// + public string choiceStringValue; + + /// + /// The internal value of this choice. + /// + public int? choiceIntValue = null; + + /// + /// The display value of this choice. + /// + public string choiceName; + + public Choice(string choiceName, string choiceValue) + { + this.choiceName = choiceName; + this.choiceStringValue = choiceValue; + } + public Choice(string choiceName, int choiceValue) + { + this.choiceName = choiceName; + this.choiceIntValue = choiceValue; + } + } +} diff --git a/src/Discord.Net.Commands/SlashCommands/Attributes/Required.cs b/src/Discord.Net.Commands/SlashCommands/Attributes/Required.cs new file mode 100644 index 000000000..4cbd5b2f8 --- /dev/null +++ b/src/Discord.Net.Commands/SlashCommands/Attributes/Required.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Discord.SlashCommands +{ + /// + /// An Attribute that gives the command parameter a description. + /// + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)] + public class Required : Attribute + { + } +} diff --git a/src/Discord.Net.Commands/SlashCommands/SlashCommandServiceHelper.cs b/src/Discord.Net.Commands/SlashCommands/SlashCommandServiceHelper.cs index a63455ff3..e49846193 100644 --- a/src/Discord.Net.Commands/SlashCommands/SlashCommandServiceHelper.cs +++ b/src/Discord.Net.Commands/SlashCommands/SlashCommandServiceHelper.cs @@ -257,7 +257,33 @@ namespace Discord.SlashCommands // And get the parameter type newParameter.Type = TypeFromMethodParameter(methodParameter); - // TODO: implement more attributes, such as [Required] + // [Required] Parameter + var requiredAttributes = methodParameter.GetCustomAttributes(typeof(Required)); + if (requiredAttributes.Count() == 1) + newParameter.Required = true; + else if (requiredAttributes.Count() > 1) + throw new Exception($"Too many Required attributes on a single parameter ({method.Name} -> {methodParameter.Name}). It can only contain one!"); + + // [Choice] Parameter + foreach (Choice choice in methodParameter.GetCustomAttributes(typeof(Choice))) + { + if (newParameter.Type == ApplicationCommandOptionType.String) + { + if(String.IsNullOrEmpty(choice.choiceStringValue)) + { + throw new Exception($"Parameter ({method.Name} -> {methodParameter.Name}) is of type string, but choice is of type int!"); + } + newParameter.AddChoice(choice.choiceName, choice.choiceStringValue); + } + if (newParameter.Type == ApplicationCommandOptionType.Integer) + { + if (choice.choiceIntValue == null) + { + throw new Exception($"Parameter ({method.Name} -> {methodParameter.Name}) is of type int, but choice is of type string!"); + } + newParameter.AddChoice(choice.choiceName, (int)choice.choiceIntValue); + } + } finalParameters.Add(newParameter); }