You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

DiscordClient.cs 7.0 kB

Implemented SubCommands and SubCommandGroups properly. Details: To implement them I had to get creative. First thing i did was manually register a command that uses sub commands and sub command groups. Two things I noticed immediately: 1) I can create a subcommand on a "root" command - where no SubCommandGroup is used 2) The current implementation of the Interactions doesn't know what type of value an option is. Good thing is that there is only 1 option when querying subcommands and subcommand groups, so I can find out what the "path" of the subcommand is. TOP/root/rng TOP/root/usr/zero TOP/root/usr/johnny (i misspelled it in the source files, woops) [See SlashCommandsExample/DiscordClient.cs] Next I wanted to make command groups (I'll use this term as to mean a slash command with subcommands and regular slash command groups) to be implemented in code in a sort of hierarchical manner - so I made them classes with attributes. Unfortunately to make this work I had to make them re-inherit the same things as the base module - UGLY but I see no other option to do this other than making them inherit from another class that remembers the instance of the upper class and implements the same methods aka a whole mess that I decided I won't want to partake in. [See SlashCommandsExample/Modules/DevModule.cs] Next-up is to search for these sub-groups. I decided that the most intuitive way of implementing these was to make SlashModuleInfo have children and parent of the same type -- from which arose different problems, but we'll get to that. So I gave them some children and a parent and a reference to the CommandGroup attribute they have on themselves. The boolean isCommandGroup is unused, but could be useful in the future... maybe. Also I've added a path variable to internally store structure. I wanted (after the whole reflections business) for commands to be easly accessed and deal WITH NO REFLECTION because those are slow, so I changed the final string - SlashCommandInfo dictionary to containt paths instead of command infos, something like what I exemplefied above. In any case, I edited the service helper (the search for modules method) to ignore command groups and only store top level commands. After that I made a command to instantiate command groups, and the command creation and registration were changed as to be recursive - because recurion is the simpest way to do this and it's efficient enough for what we want - we only run this once anyway. The biggest change was with command building - commands no longer build themselves, but now we command each module to build itself. There are 3 cases: Top-Level commands Top-Level subcommands (or level 1 command group) subcommands within slash command groups The code is uncommented, untidy and I'll fix that in a future commit. One last thing to note is that SlashCommands can have 0 options! - fixed that bug. Also SlashCommandBuilder.WithName() for some reason was implemented wrongly - I pressume a copy-paste error, Also I implemented 0 types of enforcing rules - I'm going to leave this to other people to do.
5 years ago
Implemented SubCommands and SubCommandGroups properly. Details: To implement them I had to get creative. First thing i did was manually register a command that uses sub commands and sub command groups. Two things I noticed immediately: 1) I can create a subcommand on a "root" command - where no SubCommandGroup is used 2) The current implementation of the Interactions doesn't know what type of value an option is. Good thing is that there is only 1 option when querying subcommands and subcommand groups, so I can find out what the "path" of the subcommand is. TOP/root/rng TOP/root/usr/zero TOP/root/usr/johnny (i misspelled it in the source files, woops) [See SlashCommandsExample/DiscordClient.cs] Next I wanted to make command groups (I'll use this term as to mean a slash command with subcommands and regular slash command groups) to be implemented in code in a sort of hierarchical manner - so I made them classes with attributes. Unfortunately to make this work I had to make them re-inherit the same things as the base module - UGLY but I see no other option to do this other than making them inherit from another class that remembers the instance of the upper class and implements the same methods aka a whole mess that I decided I won't want to partake in. [See SlashCommandsExample/Modules/DevModule.cs] Next-up is to search for these sub-groups. I decided that the most intuitive way of implementing these was to make SlashModuleInfo have children and parent of the same type -- from which arose different problems, but we'll get to that. So I gave them some children and a parent and a reference to the CommandGroup attribute they have on themselves. The boolean isCommandGroup is unused, but could be useful in the future... maybe. Also I've added a path variable to internally store structure. I wanted (after the whole reflections business) for commands to be easly accessed and deal WITH NO REFLECTION because those are slow, so I changed the final string - SlashCommandInfo dictionary to containt paths instead of command infos, something like what I exemplefied above. In any case, I edited the service helper (the search for modules method) to ignore command groups and only store top level commands. After that I made a command to instantiate command groups, and the command creation and registration were changed as to be recursive - because recurion is the simpest way to do this and it's efficient enough for what we want - we only run this once anyway. The biggest change was with command building - commands no longer build themselves, but now we command each module to build itself. There are 3 cases: Top-Level commands Top-Level subcommands (or level 1 command group) subcommands within slash command groups The code is uncommented, untidy and I'll fix that in a future commit. One last thing to note is that SlashCommands can have 0 options! - fixed that bug. Also SlashCommandBuilder.WithName() for some reason was implemented wrongly - I pressume a copy-paste error, Also I implemented 0 types of enforcing rules - I'm going to leave this to other people to do.
5 years ago
Implemented SubCommands and SubCommandGroups properly. Details: To implement them I had to get creative. First thing i did was manually register a command that uses sub commands and sub command groups. Two things I noticed immediately: 1) I can create a subcommand on a "root" command - where no SubCommandGroup is used 2) The current implementation of the Interactions doesn't know what type of value an option is. Good thing is that there is only 1 option when querying subcommands and subcommand groups, so I can find out what the "path" of the subcommand is. TOP/root/rng TOP/root/usr/zero TOP/root/usr/johnny (i misspelled it in the source files, woops) [See SlashCommandsExample/DiscordClient.cs] Next I wanted to make command groups (I'll use this term as to mean a slash command with subcommands and regular slash command groups) to be implemented in code in a sort of hierarchical manner - so I made them classes with attributes. Unfortunately to make this work I had to make them re-inherit the same things as the base module - UGLY but I see no other option to do this other than making them inherit from another class that remembers the instance of the upper class and implements the same methods aka a whole mess that I decided I won't want to partake in. [See SlashCommandsExample/Modules/DevModule.cs] Next-up is to search for these sub-groups. I decided that the most intuitive way of implementing these was to make SlashModuleInfo have children and parent of the same type -- from which arose different problems, but we'll get to that. So I gave them some children and a parent and a reference to the CommandGroup attribute they have on themselves. The boolean isCommandGroup is unused, but could be useful in the future... maybe. Also I've added a path variable to internally store structure. I wanted (after the whole reflections business) for commands to be easly accessed and deal WITH NO REFLECTION because those are slow, so I changed the final string - SlashCommandInfo dictionary to containt paths instead of command infos, something like what I exemplefied above. In any case, I edited the service helper (the search for modules method) to ignore command groups and only store top level commands. After that I made a command to instantiate command groups, and the command creation and registration were changed as to be recursive - because recurion is the simpest way to do this and it's efficient enough for what we want - we only run this once anyway. The biggest change was with command building - commands no longer build themselves, but now we command each module to build itself. There are 3 cases: Top-Level commands Top-Level subcommands (or level 1 command group) subcommands within slash command groups The code is uncommented, untidy and I'll fix that in a future commit. One last thing to note is that SlashCommands can have 0 options! - fixed that bug. Also SlashCommandBuilder.WithName() for some reason was implemented wrongly - I pressume a copy-paste error, Also I implemented 0 types of enforcing rules - I'm going to leave this to other people to do.
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. using Discord;
  2. using Discord.Commands;
  3. using Discord.SlashCommands;
  4. using Discord.WebSocket;
  5. using Microsoft.Extensions.DependencyInjection;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Reflection;
  9. using System.Threading.Tasks;
  10. namespace SlashCommandsExample
  11. {
  12. class DiscordClient
  13. {
  14. public static DiscordSocketClient socketClient { get; set; } = new DiscordSocketClient();
  15. public static SlashCommandService _commands { get; set; }
  16. public static IServiceProvider _services { get; set; }
  17. private string botToken = "<YOUR TOKEN HERE>";
  18. public DiscordClient()
  19. {
  20. _commands = new SlashCommandService();
  21. _services = new ServiceCollection()
  22. .AddSingleton(socketClient)
  23. .AddSingleton(_commands)
  24. .BuildServiceProvider();
  25. socketClient.Log += SocketClient_Log;
  26. _commands.Log += SocketClient_Log;
  27. socketClient.InteractionCreated += InteractionHandler;
  28. socketClient.Ready += RegisterCommand;
  29. // This is for dev purposes.
  30. // To avoid the situation in which you accidentally push your bot token to upstream, you can use
  31. // EnviromentVariables to store your key.
  32. botToken = Environment.GetEnvironmentVariable("DiscordSlashCommandsBotToken", EnvironmentVariableTarget.User);
  33. // Uncomment the next line of code to set the environment variable.
  34. // ------------------------------------------------------------------
  35. // | WARNING! |
  36. // | |
  37. // | MAKE SURE TO DELETE YOUR TOKEN AFTER YOU HAVE SET THE VARIABLE |
  38. // | |
  39. // ------------------------------------------------------------------
  40. //Environment.SetEnvironmentVariable("DiscordSlashCommandsBotToken",
  41. // "[YOUR TOKEN GOES HERE DELETE & COMMENT AFTER USE]",
  42. // EnvironmentVariableTarget.User);
  43. }
  44. public async Task RegisterCommand()
  45. {
  46. // Use this to manually register a command for testing.
  47. return;
  48. await socketClient.Rest.CreateGuildCommand(new SlashCommandCreationProperties()
  49. {
  50. Name = "root",
  51. Description = "Root Command",
  52. Options = new List<ApplicationCommandOptionProperties>()
  53. {
  54. new ApplicationCommandOptionProperties()
  55. {
  56. Name = "usr",
  57. Description = "User Folder",
  58. Type = ApplicationCommandOptionType.SubCommandGroup,
  59. Options = new List<ApplicationCommandOptionProperties>()
  60. {
  61. // This doesn't work. This is good!
  62. //new ApplicationCommandOptionProperties()
  63. //{
  64. // Name = "strstr",
  65. // Description = "Some random string I guess.",
  66. // Type = ApplicationCommandOptionType.String,
  67. //},
  68. new ApplicationCommandOptionProperties()
  69. {
  70. Name = "zero",
  71. Description = "Zero's Home Folder - COMMAND",
  72. Type = ApplicationCommandOptionType.SubCommand,
  73. Options = new List<ApplicationCommandOptionProperties>()
  74. {
  75. new ApplicationCommandOptionProperties()
  76. {
  77. Name = "file",
  78. Description = "the file you want accessed.",
  79. Type = ApplicationCommandOptionType.String
  80. }
  81. }
  82. },
  83. new ApplicationCommandOptionProperties()
  84. {
  85. Name = "johhny",
  86. Description = "Johnny Test's Home Folder - COMMAND",
  87. Type = ApplicationCommandOptionType.SubCommand,
  88. Options = new List<ApplicationCommandOptionProperties>()
  89. {
  90. new ApplicationCommandOptionProperties()
  91. {
  92. Name = "file",
  93. Description = "the file you want accessed.",
  94. Type = ApplicationCommandOptionType.String
  95. }
  96. }
  97. }
  98. }
  99. },
  100. new ApplicationCommandOptionProperties()
  101. {
  102. Name = "random",
  103. Description = "Random things",
  104. Type = ApplicationCommandOptionType.SubCommand
  105. }
  106. }
  107. }, 386658607338618891) ;
  108. }
  109. public async Task RunAsync()
  110. {
  111. await socketClient.LoginAsync(TokenType.Bot, botToken);
  112. await socketClient.StartAsync();
  113. await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _services);
  114. await _commands.RegisterCommandsAsync(socketClient, new List<ulong>()
  115. {
  116. 386658607338618891
  117. },
  118. new CommandRegistrationOptions(OldCommandOptions.DELETE_UNUSED,ExistingCommandOptions.OVERWRITE));
  119. // If you would like to register your commands manually use:
  120. //-----------------------------------------//
  121. //
  122. // await _commands.BuildCommands();
  123. //
  124. //-----------------------------------------//
  125. // Though I wouldn't highly recommend it unless you want to do something very specific with them
  126. // such as only registering some commands on only some guilds, or editing them manually.
  127. await Task.Delay(-1);
  128. }
  129. private async Task InteractionHandler(SocketInteraction arg)
  130. {
  131. if(arg.Type == InteractionType.ApplicationCommand)
  132. {
  133. await _commands.ExecuteAsync(arg);
  134. }
  135. }
  136. private Task SocketClient_Log(LogMessage arg)
  137. {
  138. Console.WriteLine("[Discord] " + arg.ToString());
  139. return Task.CompletedTask;
  140. }
  141. }
  142. }