diff --git a/docpages/advanced_reference/coding_style_standards.md b/docpages/advanced_reference/coding_style_standards.md index 672b31c80e..25305d301b 100644 --- a/docpages/advanced_reference/coding_style_standards.md +++ b/docpages/advanced_reference/coding_style_standards.md @@ -10,16 +10,28 @@ Enums and their values should be `snake_case` as with class, function and method ## Curly Braces, Brackets etc +This covers your standard Curly Braces (commonly known as squiggly brackets), and Lists. -Open curly braces on the same line as the keyword, for example: +### Curly Braces +Curly Braces should be on the same line as the keyword, for example: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} -if (a == b) { - c(); +void foo() { + if (a == b) { + c(); + } + + while(true) { + // ... + } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Use a space after the comma in parameter lists, and after opening brackets and before closing brackets except when calling a function, e.g.: +This applies to functions, `while` statements, `if` statments, lambdas, nearly anything that uses curly braces with statements! + +### Lists + +Lists should have a space after the comma in parameter lists, and after opening brackets and before closing brackets except when calling a function, for example: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} std::vector clowns = { "pennywise", "bobo" }; diff --git a/docpages/example_programs/interactions_and_components/components.md b/docpages/example_programs/interactions_and_components/components.md index 407c492871..83a93bf0af 100644 --- a/docpages/example_programs/interactions_and_components/components.md +++ b/docpages/example_programs/interactions_and_components/components.md @@ -10,38 +10,53 @@ D++ as an on_button_click event. To make use of this, use code as in this exampl int main() { - dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); + dpp::cluster bot("token"); bot.on_log(dpp::utility::cout_logger()); - /* Message handler to look for a command called !button */ - bot.on_message_create([&bot](const dpp::message_create_t & event) { - if (event.msg.content == "!button") { - /* Create a message containing an action row, and a button within the action row. */ - bot.message_create( - dpp::message(event.msg.channel_id, "this text has buttons").add_component( - dpp::component().add_component( - dpp::component().set_label("Click me!"). - set_type(dpp::cot_button). - set_emoji(u8"😄"). - set_style(dpp::cos_danger). - set_id("myid") - ) + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) { + /* Check which command they ran */ + if (event.command.get_command_name == "button") { + + /* Create a message */ + dpp::message msg(event.command.channel_id, "this text has a button"); + + /* Add an action row, and then a button within the action row. */ + msg.add_component( + dpp::component().add_component( + dpp::component(). + set_label("Click me!"). + set_type(dpp::cot_button). + set_emoji(u8"😄"). + set_style(dpp::cos_danger). + set_id("myid") ) ); + + /* Reply to the user with our message. */ + event.reply(msg); } }); /* When a user clicks your button, the on_button_click event will fire, * containing the custom_id you defined in your button. */ - bot.on_button_click([&bot](const dpp::button_click_t & event) { + bot.on_button_click([&bot](const dpp::button_click_t& event) { /* Button clicks are still interactions, and must be replied to in some form to * prevent the "this interaction has failed" message from Discord to the user. */ event.reply("You clicked: " + event.custom_id); }); + bot.on_ready([&bot](const dpp::ready_t& event) { + if (dpp::run_once()) { + + /* Create and register a command when the bot is ready */ + bot.global_command_create(dpp::slashcommand("button", "Send a message with a button!", bot.me.id)); + } + }); + bot.start(dpp::st_wait); return 0; diff --git a/docpages/example_programs/interactions_and_components/components2.md b/docpages/example_programs/interactions_and_components/components2.md index 4ad17dd350..078d4adf8e 100644 --- a/docpages/example_programs/interactions_and_components/components2.md +++ b/docpages/example_programs/interactions_and_components/components2.md @@ -1,6 +1,6 @@ -\page components2 Advanced components +\page components2 Advanced button components -This example demonstrates receiving button clicks and sending response messages. +This example demonstrates adding multiple buttons, receiving button clicks and sending response messages. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} #include @@ -9,39 +9,58 @@ using json = nlohmann::json; int main() { - dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); // Privileged intent required to receive message content + dpp::cluster bot("token"); - bot.on_log(dpp::utility::cout_logger()); + bot.on_log(dpp::utility::cout_logger()); + + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) { + /* Check which command they ran */ + if (event.command.get_command_name == "math") { + + /* Create a message */ + dpp::message msg(event.command.channel_id, "What is 5+5?"); + + /* Add an action row, and then 3 buttons within the action row. */ + msg.add_component( + dpp::component().add_component( + dpp::component(). + set_label("9"). + set_style(dpp::cos_primary). + set_id("9") + ).add_component( + dpp::component(). + set_label("10"). + set_style(dpp::cos_primary). + set_id("10") + ).add_component( + dpp::component(). + set_label("11"). + set_style(dpp::cos_primary). + set_id("11") + ) + ); + + /* Reply to the user with our message. */ + event.reply(msg); + } + }); bot.on_button_click([&bot](const dpp::button_click_t & event) { if (event.custom_id == "10") { - event.reply(dpp::message("Correct").set_flags(dpp::m_ephemeral)); + event.reply(dpp::message("You got it right!").set_flags(dpp::m_ephemeral)); } else { - event.reply(dpp::message("Incorrect").set_flags(dpp::m_ephemeral)); + event.reply(dpp::message("Wrong! Try again.").set_flags(dpp::m_ephemeral)); } }); - bot.on_message_create([&bot](const dpp::message_create_t & event) { - if (event.msg.content == "!ping2") { - bot.message_create( - dpp::message(event.msg.channel_id, "What is 5+5?").add_component( - dpp::component().add_component( - dpp::component().set_label("9"). - set_style(dpp::cos_primary). - set_id("9") - ).add_component( - dpp::component().set_label("10"). - set_style(dpp::cos_primary). - set_id("10") - ).add_component( - dpp::component().set_label("11"). - set_style(dpp::cos_primary). - set_id("11") - ) - ) - ); - } - }); + bot.on_ready([&bot](const dpp::ready_t& event) { + if (dpp::run_once()) { + + /* Create and register a command when the bot is ready */ + bot.global_command_create(dpp::slashcommand("math", "A quick maths question!", bot.me.id)); + } + }); bot.start(dpp::st_wait); diff --git a/docpages/example_programs/interactions_and_components/components3.md b/docpages/example_programs/interactions_and_components/components3.md index df98eb3b1d..0691a2d848 100644 --- a/docpages/example_programs/interactions_and_components/components3.md +++ b/docpages/example_programs/interactions_and_components/components3.md @@ -1,6 +1,6 @@ \page components3 Using select menu components -This example demonstrates receiving select menu clicks and sending response messages. +This example demonstrates creating a select menu, receiving select menu clicks and sending a response message. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} #include @@ -9,27 +9,35 @@ using json = nlohmann::json; int main() { - dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); + dpp::cluster bot("token"); - bot.on_log(dpp::utility::cout_logger()); + bot.on_log(dpp::utility::cout_logger()); - /* Message handler to look for a command called !select */ - bot.on_message_create([&bot](const dpp::message_create_t & event) { - if (event.msg.content == "!select") { - /* Create a message containing an action row, and a select menu within the action row. */ - dpp::message m(event.msg.channel_id, "this text has a select menu"); - m.add_component( + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) { + /* Check which command they ran */ + if (event.command.get_command_name == "select") { + + /* Create a message */ + dpp::message msg(event.command.channel_id, "This text has a select menu!"); + + /* Add an action row, and a select menu within the action row. */ + msg.add_component( dpp::component().add_component( - dpp::component().set_type(dpp::cot_selectmenu). + dpp::component(). + set_type(dpp::cot_selectmenu). set_placeholder("Pick something"). add_select_option(dpp::select_option("label1","value1","description1").set_emoji(u8"😄")). add_select_option(dpp::select_option("label2","value2","description2").set_emoji(u8"🙂")). - set_id("myselid") + set_id("myselectid") ) ); - bot.message_create(m); + + /* Reply to the user with our message. */ + event.reply(msg); } }); + /* When a user clicks your select menu , the on_select_click event will fire, * containing the custom_id you defined in your select menu. */ @@ -40,6 +48,14 @@ int main() { event.reply("You clicked " + event.custom_id + " and chose: " + event.values[0]); }); + bot.on_ready([&bot](const dpp::ready_t& event) { + if (dpp::run_once()) { + + /* Create and register a command when the bot is ready */ + bot.global_command_create(dpp::slashcommand("select", "Select something at random!", bot.me.id)); + } + }); + bot.start(dpp::st_wait); return 0; diff --git a/docpages/example_programs/interactions_and_components/context_menus.md b/docpages/example_programs/interactions_and_components/context_menus.md index 08f206fa37..c48d518388 100644 --- a/docpages/example_programs/interactions_and_components/context_menus.md +++ b/docpages/example_programs/interactions_and_components/context_menus.md @@ -4,7 +4,9 @@ Context menus are application commands that appear on the context menu (right cl \image html context_menu_user_command.png -The following example shows how to create and handle **user context menus**. +\note This example sets the command as the type dpp::ctxm_user which can only be used by right clicking on a user. To make it appear on a message, you'll want to switch the type to dpp::ctxm_message. + +The following example shows how to create and handle **user context menus** for message context menus, read the notice above. ~~~~~~~~~~{.cpp} #include @@ -18,21 +20,21 @@ int main() bot.on_ready([&bot](const dpp::ready_t &event) { if (dpp::run_once()) { + + /* Create the command */ + dpp::slashcommand command("High Five", "Send a High Five!", bot.me.id); + + command.set_type(dpp::ctxm_user); + /* Register the command */ - bot.guild_command_create( - dpp::slashcommand() - .set_type(dpp::ctxm_user) - .set_name("High Five") - .set_application_id(bot.me.id), - 857692897221033129 // you need to put your guild-id in here - ); + bot.guild_command_create(command, guild_id); } }); /* Use the on_user_context_menu event to look for user context menu actions */ - bot.on_user_context_menu([&](const dpp::user_context_menu_t &event) { + bot.on_user_context_menu([&](const dpp::user_context_menu_t& event) { /* check if the context menu name is High Five */ - if (event.command.get_command_name() == "High Five") { + if (event.command.get_command_name() == "high five") { dpp::user user = event.get_user(); // the user who the command has been issued on dpp::user author = event.command.get_issuing_user(); // the user who clicked on the context menu event.reply(author.get_mention() + " slapped " + user.get_mention()); diff --git a/docpages/example_programs/interactions_and_components/modal_dialog_interactions.md b/docpages/example_programs/interactions_and_components/modal_dialog_interactions.md index d388a72c36..f9a99bcde6 100644 --- a/docpages/example_programs/interactions_and_components/modal_dialog_interactions.md +++ b/docpages/example_programs/interactions_and_components/modal_dialog_interactions.md @@ -12,20 +12,15 @@ int main(int argc, char const *argv[]) { dpp::cluster bot("token"); - bot.on_log(dpp::utility::cout_logger()); + bot.on_log(dpp::utility::cout_logger()); - bot.on_ready([&](const dpp::ready_t & event) { - if (dpp::run_once()) { - /* Create a slash command and register it as a global command */ - bot.global_command_create(dpp::slashcommand("dialog", "Make a modal dialog box", bot.me.id)); - } - }); - - bot.on_slashcommand([&bot](const dpp::slashcommand_t & event) { + bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) { /* Check for our /dialog command */ if (event.command.get_command_name() == "dialog") { + /* Instantiate an interaction_modal_response object */ dpp::interaction_modal_response modal("my_modal", "Please enter stuff"); + /* Add a text component */ modal.add_component( dpp::component(). @@ -37,6 +32,7 @@ int main(int argc, char const *argv[]) set_max_length(50). set_text_style(dpp::text_short) ); + /* Add another text component in the next row, as required by Discord */ modal.add_row(); modal.add_component( @@ -49,6 +45,7 @@ int main(int argc, char const *argv[]) set_max_length(2000). set_text_style(dpp::text_paragraph) ); + /* Trigger the dialog box. All dialog boxes are ephemeral */ event.dialog(modal); } @@ -56,17 +53,28 @@ int main(int argc, char const *argv[]) /* This event handles form submission for the modal dialog we create above */ bot.on_form_submit([&](const dpp::form_submit_t & event) { + /* For this simple example we know the first element of the first row ([0][0]) is value type string. * In the real world it may not be safe to make such assumptions! */ std::string v = std::get(event.components[0].components[0].value); + dpp::message m; m.set_content("You entered: " + v).set_flags(dpp::m_ephemeral); + /* Emit a reply. Form submission is still an interaction and must generate some form of reply! */ event.reply(m); }); + bot.on_ready([&](const dpp::ready_t & event) { + if (dpp::run_once()) { + /* Create a slash command and register it as a global command */ + bot.global_command_create(dpp::slashcommand("dialog", "Make a modal dialog box", bot.me.id)); + } + }); + /* Start bot */ + bot.start(dpp::st_wait); return 0; } diff --git a/docpages/example_programs/interactions_and_components/slashcommands.md b/docpages/example_programs/interactions_and_components/slashcommands.md index f849f236c7..9ccfdc78c6 100644 --- a/docpages/example_programs/interactions_and_components/slashcommands.md +++ b/docpages/example_programs/interactions_and_components/slashcommands.md @@ -2,7 +2,9 @@ Slash commands and interactions are a newer feature of Discord which allow bot's commands to be registered centrally within the system and for users to easily explore and get help with available commands through the client itself. -To add a slash command you should use the dpp::cluster::global_command_create method for global commands (available to all guilds) or dpp::cluster::guild_command_create to create a local command (available only to one guild). +To add a slash command you should use the dpp::cluster::global_command_create method for global commands (available to all guilds) or dpp::cluster::guild_command_create to create a local command (available only to one guild). If you want to add many commands, it is advised to use the dpp::cluster::global_bulk_command_create method for global commands or the dpp::cluster::guild_bulk_command_create method for local commands. + +\note dpp::cluster::global_bulk_command_create or dpp::cluster::guild_bulk_command_create will delete any previous commands that were registered. For example, if you call global_bulk_command_create twice with two different sets then the first set of commands will be created, then when the second set is called, the first set will be deleted, leaving only the second set. When a user issues these commands the reply will arrive via the `on_slashcommand` event which you can hook, and take action when you see your commands. It is possible to reply to an interaction by using either the dpp::interaction_create_t::reply method, or by manually instantiating an object of type dpp::interaction_response and attaching a dpp::message object to it. @@ -10,6 +12,8 @@ dpp::interaction_create_t::reply has two overloaded versions of the method, one \note You can also use the unified command handler, which lets you combine channel based message commands and slash commands under the same lambda with the same code like they were one and the same. Note that after August of 2022 Discord will be discouraging bots from using commands that are prefixed messages via means of a privileged message intent. It is advised that you exclusively use slash commands, or the unified handler with only a prefix of "/" going forward for any new bots you create and look to migrating existing bots to this setup. +This first example goes over creating a single command globally. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} #include @@ -21,10 +25,13 @@ int main() /* The event is fired when someone issues your commands */ bot.on_slashcommand([&bot](const dpp::slashcommand_t & event) { + /* Check which command they ran */ if (event.command.get_command_name() == "blep") { + /* Fetch a parameter value from the command parameters */ std::string animal = std::get(event.get_parameter("animal")); + /* Reply to the command. There is an overloaded version of this * call that accepts a dpp::message so you can send embeds. */ @@ -57,5 +64,149 @@ int main() } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -\note For demonstration purposes, and small bots, this code is OK, but in the real world once your bot gets big, it's not recommended to create slash commands in the `on_ready` event because it gets called often (discord forces reconnections and sometimes these do not resume). You could for example add a commandline parameter to your bot (`argc`, `argv`) so that if you want the bot to register commands it must be launched with a specific command line argument. +This second example goes over creating a single command but only for a guild, this means that the command can not be accessed anywhere else but the guild specified. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +#include + +int main() +{ + dpp::cluster bot("token"); + + bot.on_log(dpp::utility::cout_logger()); + + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot](const dpp::slashcommand_t & event) { + + /* Check which command they ran */ + if (event.command.get_command_name() == "blep") { + + /* Fetch a parameter value from the command parameters */ + std::string animal = std::get(event.get_parameter("animal")); + + /* Reply to the command. There is an overloaded version of this + * call that accepts a dpp::message so you can send embeds. + */ + event.reply(std::string("Blep! You chose") + animal); + } + }); + + bot.on_ready([&bot](const dpp::ready_t & event) { + if (dpp::run_once()) { + + /* Create a new global command on ready event */ + dpp::slashcommand newcommand("blep", "Send a random adorable animal photo", bot.me.id); + newcommand.add_option( + dpp::command_option(dpp::co_string, "animal", "The type of animal", true). + add_choice(dpp::command_option_choice("Dog", std::string("animal_dog"))). + add_choice(dpp::command_option_choice("Cat", std::string("animal_cat"))). + add_choice(dpp::command_option_choice("Penguin", std::string("animal_penguin") + ) + ) + ); + + /* Register the command */ + bot.guild_command_create(newcommand, 857692897221033129); /* Replace this with the guild id you want */ + } + }); + + bot.start(dpp::st_wait); + + return 0; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This third example goes over creating four commands globally, using the bulk create method. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +#include + +int main() +{ + dpp::cluster bot("token"); + + bot.on_log(dpp::utility::cout_logger()); + + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot](const dpp::slashcommand_t & event) { + + /* Check which command they ran */ + if (event.command.get_command_name() == "ping") { + event.reply("Pong!"); + } else if (event.command.get_command_name() == "pong") { + event.reply("Ping!"); + } else if (event.command.get_command_name() == "ding") { + event.reply("Dong!"); + } else if (event.command.get_command_name() == "dong") { + event.reply("Ding!"); + } + }); + + bot.on_ready([&bot](const dpp::ready_t & event) { + if (dpp::run_once()) { + + /* Create some commands */ + dpp::slashcommand pingcommand("ping", "Pong!", bot.me.id); + dpp::slashcommand pongcommand("pong", "Ping!", bot.me.id); + dpp::slashcommand dingcommand("ding", "Dong!", bot.me.id); + dpp::slashcommand dongcommand("dong", "Ding!", bot.me.id); + + /* Register our commands in a list using bulk */ + bot.global_bulk_command_create({ pingcommand, pongcommand, dingcommand, dongcommand }); + } + }); + + bot.start(dpp::st_wait); + + return 0; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This fourth example goes over creating four commands but only for a guild. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +#include + +int main() +{ + dpp::cluster bot("token"); + + bot.on_log(dpp::utility::cout_logger()); + + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot](const dpp::slashcommand_t & event) { + + /* Check which command they ran */ + if (event.command.get_command_name() == "ping") { + event.reply("Pong!"); + } else if (event.command.get_command_name() == "pong") { + event.reply("Ping!"); + } else if (event.command.get_command_name() == "ding") { + event.reply("Dong!"); + } else if (event.command.get_command_name() == "dong") { + event.reply("Ding!"); + } + }); + + bot.on_ready([&bot](const dpp::ready_t & event) { + if (dpp::run_once()) { + + /* Create some commands */ + dpp::slashcommand pingcommand("ping", "Pong!", bot.me.id); + dpp::slashcommand pongcommand("pong", "Ping!", bot.me.id); + dpp::slashcommand dingcommand("ding", "Dong!", bot.me.id); + dpp::slashcommand dongcommand("dong", "Ding!", bot.me.id); + + /* Register our commands in a list using bulk */ + bot.guild_bulk_command_create({ pingcommand, pongcommand, dingcommand, dongcommand }, 857692897221033129); + + } + }); + + bot.start(dpp::st_wait); + + return 0; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +\note For demonstration purposes, and small bots, this code is OK, but in the real world once your bot gets big, it's not recommended to create slash commands in the `on_ready` event even when it's inside `dpp::run_once` as, if you re-run your bot multiple times or start multiple clusters, you will quickly get rate-limited! You could, for example, add a commandline parameter to your bot (`argc`, `argv`) so that if you want the bot to register commands it must be launched with a specific command line argument. \ No newline at end of file diff --git a/docpages/example_programs/interactions_and_components/upload_parameter.md b/docpages/example_programs/interactions_and_components/upload_parameter.md index 8b8f2656b5..19deaa3a57 100644 --- a/docpages/example_programs/interactions_and_components/upload_parameter.md +++ b/docpages/example_programs/interactions_and_components/upload_parameter.md @@ -16,20 +16,30 @@ int main() bot.on_log(dpp::utility::cout_logger()); - bot.on_slashcommand([&bot](const dpp::slashcommand_t & event) { - dpp::command_interaction cmd_data = std::get(event.command.data); - if (cmd_data.name == "show") { + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) { + + /* Check which command they ran */ + if (event.command.get_command_name() == "show") { + + /* Get the file id from the parameter attachment. */ dpp::snowflake file_id = std::get(event.get_parameter("file")); + + /* Get the attachment that the user inputted from the file id. */ dpp::attachment att = event.command.get_resolved_attachment(file_id); + + /* Reply with the file as a URL. */ event.reply(att.url); } }); bot.on_ready([&bot](const dpp::ready_t & event) { - if (dpp::run_once()) { + + /* Create a new command. */ dpp::slashcommand newcommand("show", "Show an uploaded file", bot.me.id); + /* Add a parameter option. */ newcommand.add_option(dpp::command_option(dpp::co_attachment, "file", "Select an image")); bot.global_command_create(newcommand); @@ -40,4 +50,4 @@ int main() return 0; } -~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~ \ No newline at end of file diff --git a/docpages/example_programs/misc/cache_messages.md b/docpages/example_programs/misc/cache_messages.md index 77cfdbffa1..19dde4526a 100644 --- a/docpages/example_programs/misc/cache_messages.md +++ b/docpages/example_programs/misc/cache_messages.md @@ -14,44 +14,56 @@ exercise to the reader. For further reading please see the documentation of dpp: int main() { /* Create bot */ - dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); + dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); /* Because we're handling messages, we need to use the "i_message_content" intent! */ /* Create a cache to contain types of dpp::message */ dpp::cache message_cache; - bot.on_log(dpp::utility::cout_logger()); + bot.on_log(dpp::utility::cout_logger()); /* Message handler */ bot.on_message_create([&](const dpp::message_create_t &event) { - /* Make a permanent pointer using new, for each message to be cached */ dpp::message* m = new dpp::message(); + /* Store the message into the pointer by copying it */ *m = event.msg; + /* Store the new pointer to the cache using the store() method */ message_cache.store(m); + }); + + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) { + /* Check which command they ran */ + if (event.command.get_command_name == "get") { + + dpp::message* find_msg = message_cache.find(std::get(event.get_parameter("message_id"))); - /* Simple ghetto command handler. In the real world, use slashcommand or commandhandler here. */ - std::stringstream ss(event.msg.content); - std::string cmd; - dpp::snowflake msg_id; - ss >> cmd; - - /* Look for our command */ - if (cmd == "!get") { - ss >> msg_id; - /* Search our cache for a cached message */ - dpp::message* find_msg = message_cache.find(msg_id); - if (find_msg != nullptr) { - /* Found a cached message, echo it out */ - bot.message_create(dpp::message(event.msg.channel_id, "This message had the following content: " + find_msg->content)); - } else { - /* Nothing like that here. Have you checked under the carpet? */ - bot.message_create(dpp::message(event.msg.channel_id, "There is no message cached with this ID")); + /* If find_msg is null, tell the user and return. */ + if (!find_msg) { + event.reply("There is no message cached with this ID"); + return; } + + event.reply("This message had the following content: " + find_msg->content); } }); + bot.on_ready([&bot](const dpp::ready_t& event) { + if (dpp::run_once()) { + + /* Create a new command. */ + dpp::slashcommand newcommand("get", "Get the contents of a message that was cached via an id", bot.me.id); + + /* Add a parameter option. */ + newcommand.add_option(dpp::command_option(dpp::co_string, "message_id", "The ID of the message you want to find", true)); + + /* Register the command */ + bot.global_command_create(newcommand); + } + }); + /* Start bot */ bot.start(dpp::st_wait); diff --git a/docpages/example_programs/music_and_audio/join_voice.md b/docpages/example_programs/music_and_audio/join_voice.md index 65d069a40a..8a44f40f81 100644 --- a/docpages/example_programs/music_and_audio/join_voice.md +++ b/docpages/example_programs/music_and_audio/join_voice.md @@ -12,30 +12,28 @@ When a user issues a command you may want to join their voice channel, e.g. in a int main(int argc, char const *argv[]) { /* Setup the bot */ - dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); // Privileged intent required to receive message content + dpp::cluster bot("token"); - bot.on_log(dpp::utility::cout_logger()); + bot.on_log(dpp::utility::cout_logger()); - /* Use the on_message_create event to look for commands */ - bot.on_message_create([&bot, robot, robot_size](const dpp::message_create_t & event) { + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot, &fd](const dpp::slashcommand_t& event) { - std::stringstream ss(event.msg.content); - std::string command; + /* Check which command they ran */ + if (event.command.get_command_name() == "join") { - ss >> command; + /* Get the guild */ + dpp::guild* g = dpp::find_guild(event.command.guild_id); + auto current_vc = event.from->get_voice(event.command.guild_id); - /* Switch to or join the vc the user is on. Syntax: .join */ - if (command == ".join") { - dpp::guild * g = dpp::find_guild(event.msg.guild_id); - auto current_vc = event.from->get_voice(event.msg.guild_id); bool join_vc = true; - /* Check if we are currently on any vc */ - if (current_vc) { - /* Find the channel id that the user is currently on */ - auto users_vc = g->voice_members.find(event.msg.author.id); - /* See if we currently share a channel with the user */ + + if (!current_vc) { + auto users_vc = g->voice_members.find(event.command.get_issuing_user().id); + if (users_vc != g->voice_members.end() && current_vc->channel_id == users_vc->second.channel_id) { join_vc = false; + /* We are on this voice channel, at this point we can send any audio instantly to vc: * current_vc->send_audio_raw(...) @@ -44,31 +42,48 @@ int main(int argc, char const *argv[]) /* We are on a different voice channel. Leave it, then join the new one * by falling through to the join_vc branch below. */ - event.from->disconnect_voice(event.msg.guild_id); + event.from->disconnect_voice(event.channel.guild_id); + join_vc = true; } } + /* If we need to join a vc at all, join it here if join_vc == true */ - if (join_vc) { - if (!g->connect_member_voice(event.msg.author.id)) { - /* The user issuing the command is not on any voice channel, we can't do anything */ - bot.message_create(dpp::message(event.msg.channel_id, "You don't seem to be on a voice channel! :(")); - } else { - /* We are now connecting to a vc. Wait for on_voice_ready - * event, and then send the audio within that event: - * - * event.voice_client->send_audio_raw(...); - * - * NOTE: We can't instantly send audio, as we have to wait for - * the connection to the voice server to be established! - */ + if(join_vc) { + /* Attempt to connect to a voice channel, returns false if we fail to connect. */ + if (!g->connect_member_voice(event.command.get_issuing_user().id)) { + event.reply("You don't seem to be in a voice channel!"); + return; } + + /* We are now connecting to a vc. Wait for on_voice_ready + * event, and then send the audio within that event: + * + * event.voice_client->send_audio_raw(...); + * + * NOTE: We can't instantly send audio, as we have to wait for + * the connection to the voice server to be established! + */ + + /* Tell the user we joined their channel. */ + event.reply("Joined your channel!"); + } else { + event.reply("Don't need to join your channel as i'm already there with you!"); } } }); + bot.on_ready([&bot](const dpp::ready_t & event) { + if (dpp::run_once()) { + + /* Create a new command. */ + bot.global_command_create(dpp::slashcommand("join", "Joins your voice channel.", bot.me.id)); + } + }); + /* Start bot */ bot.start(dpp::st_wait); + return 0; } diff --git a/docpages/example_programs/music_and_audio/mp3.md b/docpages/example_programs/music_and_audio/mp3.md index 0c80cafe02..a6181a75d2 100644 --- a/docpages/example_programs/music_and_audio/mp3.md +++ b/docpages/example_programs/music_and_audio/mp3.md @@ -63,31 +63,54 @@ int main(int argc, char const *argv[]) mpg123_delete(mh); /* Setup the bot */ - dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); + dpp::cluster bot("token"); - bot.on_log(dpp::utility::cout_logger()); + bot.on_log(dpp::utility::cout_logger()); - /* Use the on_message_create event to look for commands */ - bot.on_message_create([&bot, &pcmdata](const dpp::message_create_t & event) { - std::stringstream ss(event.msg.content); - std::string command; - ss >> command; + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot, &pcmdata](const dpp::slashcommand_t& event) { - /* Tell the bot to join the discord voice channel the user is on. Syntax: .join */ - if (command == ".join") { - dpp::guild * g = dpp::find_guild(event.msg.guild_id); - if (!g->connect_member_voice(event.msg.author.id)) { - bot.message_create(dpp::message(event.msg.channel_id, "You don't seem to be on a voice channel! :(")); + /* Check which command they ran */ + if (event.command.get_command_name() == "join") { + + /* Get the guild */ + dpp::guild* g = dpp::find_guild(event.command.guild_id); + + /* Attempt to connect to a voice channel, returns false if we fail to connect. */ + if (!g->connect_member_voice(event.command.get_issuing_user().id)) { + event.reply("You don't seem to be in a voice channel!"); + return; + } + + /* Tell the user we joined their channel. */ + event.reply("Joined your channel!"); + } else if (event.command.get_command_name() == "mp3") { + + /* Get the voice channel the bot is in, in this current guild. */ + dpp::voiceconn* v = event.from->get_voice(event.channel.guild_id); + + /* If the voice channel was invalid, or there is an issue with it, then tell the user. */ + if (!v || !v->voiceclient || !v->voiceclient->is_ready()) { + event.reply("There was an issue with getting the voice channel. Make sure I'm in a voice channel!"); + return; } + + /* Stream the already decoded MP3 file. This passes the PCM data to the library to be encoded to OPUS */ + v->voiceclient->send_audio_raw((uint16_t*)pcmdata.data(), pcmdata.size()); + + event.reply("Played the mp3 file."); } + }); - /* Tell the bot to play the mp3 file. Syntax: .mp3 */ - if (command == ".mp3") { - dpp::voiceconn* v = event.from->get_voice(event.msg.guild_id); - if (v && v->voiceclient && v->voiceclient->is_ready()) { - /* Stream the already decoded MP3 file. This passes the PCM data to the library to be encoded to OPUS */ - v->voiceclient->send_audio_raw((uint16_t*)pcmdata.data(), pcmdata.size()); - } + bot.on_ready([&bot](const dpp::ready_t & event) { + if (dpp::run_once()) { + + /* Create a new command. */ + dpp::slashcommand joincommand("join", "Joins your voice channel.", bot.me.id); + + dpp::slashcommand mp3command("mp3", "Plays an mp3 file.", bot.me.id); + + bot.global_bulk_command_create({joincommand, mp3command}); } }); diff --git a/docpages/example_programs/music_and_audio/oggopus.md b/docpages/example_programs/music_and_audio/oggopus.md index fd1228d76b..50be5b28a4 100644 --- a/docpages/example_programs/music_and_audio/oggopus.md +++ b/docpages/example_programs/music_and_audio/oggopus.md @@ -21,144 +21,165 @@ int main(int argc, char const *argv[]) * You may use ffmpeg to encode songs to ogg opus: * ffmpeg -i /path/to/song -c:a libopus -ar 48000 -ac 2 -vn -b:a 96K /path/to/opus.ogg */ - dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); - bot.on_log(dpp::utility::cout_logger()); + dpp::cluster bot("token"); - /* Use the on_message_create event to look for commands */ - bot.on_message_create([&bot](const dpp::message_create_t & event) { - std::stringstream ss(event.msg.content); - std::string command; - ss >> command; + bot.on_log(dpp::utility::cout_logger()); - /* Tell the bot to join the discord voice channel the user is on. Syntax: .join */ - if (command == ".join") { - dpp::guild * g = dpp::find_guild(event.msg.guild_id); - if (!g->connect_member_voice(event.msg.author.id)) { - bot.message_create(dpp::message(event.msg.channel_id, "You don't seem to be on a voice channel! :(")); + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) { + + /* Check which command they ran */ + if (event.command.get_command_name() == "join") { + + /* Get the guild */ + dpp::guild* g = dpp::find_guild(event.command.guild_id); + + /* Attempt to connect to a voice channel, returns false if we fail to connect. */ + if (!g->connect_member_voice(event.command.get_issuing_user().id)) { + event.reply("You don't seem to be in a voice channel!"); + return; + } + + /* Tell the user we joined their channel. */ + event.reply("Joined your channel!"); + } else if (event.command.get_command_name() == "play") { + + /* Get the voice channel the bot is in, in this current guild. */ + dpp::voiceconn* v = event.from->get_voice(event.channel.guild_id); + + /* If the voice channel was invalid, or there is an issue with it, then tell the user. */ + if (!v || !v->voiceclient || !v->voiceclient->is_ready()) { + event.reply("There was an issue with getting the voice channel. Make sure I'm in a voice channel!"); + return; } - } - /* Tell the bot to play the sound file */ - if (command == ".play") { - dpp::voiceconn* v = event.from->get_voice(event.msg.guild_id); - if (v && v->voiceclient && v->voiceclient->is_ready()) { - ogg_sync_state oy; - ogg_stream_state os; - ogg_page og; - ogg_packet op; - OpusHead header; - char *buffer; + ogg_sync_state oy; + ogg_stream_state os; + ogg_page og; + ogg_packet op; + OpusHead header; + char *buffer; - FILE *fd; + FILE *fd; - fd = fopen("/path/to/opus.ogg", "rb"); + fd = fopen("/path/to/opus.ogg", "rb"); - fseek(fd, 0L, SEEK_END); - size_t sz = ftell(fd); - rewind(fd); + fseek(fd, 0L, SEEK_END); + size_t sz = ftell(fd); + rewind(fd); - ogg_sync_init(&oy); + ogg_sync_init(&oy); - int eos = 0; - int i; + int eos = 0; + int i; - buffer = ogg_sync_buffer(&oy, sz); - fread(buffer, 1, sz, fd); + buffer = ogg_sync_buffer(&oy, sz); + fread(buffer, 1, sz, fd); - ogg_sync_wrote(&oy, sz); + ogg_sync_wrote(&oy, sz); - /** - * We must first verify that the stream is indeed ogg opus - * by reading the header and parsing it - */ - if (ogg_sync_pageout(&oy, &og) != 1) - { - fprintf(stderr,"Does not appear to be ogg stream.\n"); - exit(1); - } + /** + * We must first verify that the stream is indeed ogg opus + * by reading the header and parsing it + */ + if (ogg_sync_pageout(&oy, &og) != 1) { + fprintf(stderr,"Does not appear to be ogg stream.\n"); + exit(1); + } - ogg_stream_init(&os, ogg_page_serialno(&og)); + ogg_stream_init(&os, ogg_page_serialno(&og)); - if (ogg_stream_pagein(&os,&og) < 0) { - fprintf(stderr,"Error reading initial page of ogg stream.\n"); - exit(1); - } + if (ogg_stream_pagein(&os,&og) < 0) { + fprintf(stderr,"Error reading initial page of ogg stream.\n"); + exit(1); + } - if (ogg_stream_packetout(&os,&op) != 1) - { - fprintf(stderr,"Error reading header packet of ogg stream.\n"); - exit(1); - } + if (ogg_stream_packetout(&os,&op) != 1) { + fprintf(stderr,"Error reading header packet of ogg stream.\n"); + exit(1); + } - /* We must ensure that the ogg stream actually contains opus data */ - if (!(op.bytes > 8 && !memcmp("OpusHead", op.packet, 8))) - { - fprintf(stderr,"Not an ogg opus stream.\n"); - exit(1); - } + /* We must ensure that the ogg stream actually contains opus data */ + if (!(op.bytes > 8 && !memcmp("OpusHead", op.packet, 8))) { + fprintf(stderr,"Not an ogg opus stream.\n"); + exit(1); + } - /* Parse the header to get stream info */ - int err = opus_head_parse(&header, op.packet, op.bytes); - if (err) - { - fprintf(stderr,"Not a ogg opus stream\n"); - exit(1); - } - /* Now we ensure the encoding is correct for Discord */ - if (header.channel_count != 2 && header.input_sample_rate != 48000) - { - fprintf(stderr,"Wrong encoding for Discord, must be 48000Hz sample rate with 2 channels.\n"); + /* Parse the header to get stream info */ + int err = opus_head_parse(&header, op.packet, op.bytes); + if (err) { + fprintf(stderr,"Not a ogg opus stream\n"); + exit(1); + } + + /* Now we ensure the encoding is correct for Discord */ + if (header.channel_count != 2 && header.input_sample_rate != 48000) { + fprintf(stderr,"Wrong encoding for Discord, must be 48000Hz sample rate with 2 channels.\n"); + exit(1); + } + + /* Now loop though all the pages and send the packets to the vc */ + while (ogg_sync_pageout(&oy, &og) == 1) { + ogg_stream_init(&os, ogg_page_serialno(&og)); + + if(ogg_stream_pagein(&os,&og)<0) { + fprintf(stderr,"Error reading page of Ogg bitstream data.\n"); exit(1); } - /* Now loop though all the pages and send the packets to the vc */ - while (ogg_sync_pageout(&oy, &og) == 1){ - ogg_stream_init(&os, ogg_page_serialno(&og)); + while (ogg_stream_packetout(&os,&op) != 0) { - if(ogg_stream_pagein(&os,&og)<0){ - fprintf(stderr,"Error reading page of Ogg bitstream data.\n"); - exit(1); - } - - while (ogg_stream_packetout(&os,&op) != 0) - { - /* Read remaining headers */ - if (op.bytes > 8 && !memcmp("OpusHead", op.packet, 8)) - { - int err = opus_head_parse(&header, op.packet, op.bytes); - if (err) - { - fprintf(stderr,"Not a ogg opus stream\n"); - exit(1); - } - if (header.channel_count != 2 && header.input_sample_rate != 48000) - { - fprintf(stderr,"Wrong encoding for Discord, must be 48000Hz sample rate with 2 channels.\n"); - exit(1); - } - continue; + /* Read remaining headers */ + if (op.bytes > 8 && !memcmp("OpusHead", op.packet, 8)) { + int err = opus_head_parse(&header, op.packet, op.bytes); + if (err) { + fprintf(stderr,"Not a ogg opus stream\n"); + exit(1); } - /* Skip the opus tags */ - if (op.bytes > 8 && !memcmp("OpusTags", op.packet, 8)) - continue; - /* Send the audio */ - int samples = opus_packet_get_samples_per_frame(op.packet, 48000); + if (header.channel_count != 2 && header.input_sample_rate != 48000) { + fprintf(stderr,"Wrong encoding for Discord, must be 48000Hz sample rate with 2 channels.\n"); + exit(1); + } - v->voiceclient->send_audio_opus(op.packet, op.bytes, samples / 48); + continue; } - } - /* Cleanup */ - ogg_stream_clear(&os); - ogg_sync_clear(&oy); + /* Skip the opus tags */ + if (op.bytes > 8 && !memcmp("OpusTags", op.packet, 8)) + continue; + + /* Send the audio */ + int samples = opus_packet_get_samples_per_frame(op.packet, 48000); + + v->voiceclient->send_audio_opus(op.packet, op.bytes, samples / 48); + } } + + /* Cleanup */ + ogg_stream_clear(&os); + ogg_sync_clear(&oy); + + event.reply("Finished playing the audio file!"); + } + }); + + bot.on_ready([&bot](const dpp::ready_t & event) { + if (dpp::run_once()) { + + /* Create a new command. */ + dpp::slashcommand joincommand("join", "Joins your voice channel.", bot.me.id); + + dpp::slashcommand playcommand("play", "Plays an ogg file.", bot.me.id); + + bot.global_bulk_command_create({joincommand, playcommand}); } }); /* Start bot */ bot.start(dpp::st_wait); + return 0; } ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -191,78 +212,108 @@ int main(int argc, char const *argv[]) * You may use ffmpeg to encode songs to ogg opus: * ffmpeg -i /path/to/song -c:a libopus -ar 48000 -ac 2 -vn -b:a 96K /path/to/opus.ogg */ - dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); - bot.on_log(dpp::utility::cout_logger()); + /* Setup the bot */ + dpp::cluster bot("token"); + + bot.on_log(dpp::utility::cout_logger()); + + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) { + + /* Check which command they ran */ + if (event.command.get_command_name() == "join") { - /* Use the on_message_create event to look for commands */ - bot.on_message_create([&bot](const dpp::message_create_t & event) { - std::stringstream ss(event.msg.content); - std::string command; - ss >> command; + /* Get the guild */ + dpp::guild* g = dpp::find_guild(event.command.guild_id); - /* Tell the bot to join the discord voice channel the user is on. Syntax: .join */ - if (command == ".join") { - dpp::guild * g = dpp::find_guild(event.msg.guild_id); - if (!g->connect_member_voice(event.msg.author.id)) { - bot.message_create(dpp::message(event.msg.channel_id, "You don't seem to be on a voice channel! :(")); + /* Attempt to connect to a voice channel, returns false if we fail to connect. */ + if (!g->connect_member_voice(event.command.get_issuing_user().id)) { + event.reply("You don't seem to be in a voice channel!"); + return; + } + + /* Tell the user we joined their channel. */ + event.reply("Joined your channel!"); + } else if (event.command.get_command_name() == "play") { + + /* Get the voice channel the bot is in, in this current guild. */ + dpp::voiceconn* v = event.from->get_voice(event.channel.guild_id); + + /* If the voice channel was invalid, or there is an issue with it, then tell the user. */ + if (!v || !v->voiceclient || !v->voiceclient->is_ready()) { + event.reply("There was an issue with getting the voice channel. Make sure I'm in a voice channel!"); + return; } - } - /* Tell the bot to play the sound file */ - if (command == ".play") { - dpp::voiceconn* v = event.from->get_voice(event.msg.guild_id); - if (v && v->voiceclient && v->voiceclient->is_ready()) { - // load the audio file with oggz - OGGZ *track_og = oggz_open("/path/to/opus.ogg", OGGZ_READ); - - if (track_og) { - // set read callback, this callback will be called on packets with the serialno, - // -1 means every packet will be handled with this callback - oggz_set_read_callback( - track_og, -1, - [](OGGZ *oggz, oggz_packet *packet, long serialno, - void *user_data) { - dpp::voiceconn *voiceconn = (dpp::voiceconn *)user_data; - - // send the audio - voiceconn->voiceclient->send_audio_opus(packet->op.packet, - packet->op.bytes); - - // make sure to always return 0 here, read more on oggz documentation - return 0; - }, - // this will be the value of void *user_data - (void *)v); - - // read loop - while (v && v->voiceclient && !v->voiceclient->terminating) { - // you can tweak this to whatever. Here I use BUFSIZ, defined in - // stdio.h as 8192 - static const constexpr long CHUNK_READ = BUFSIZ * 2; - - const long read_bytes = oggz_read(track_og, CHUNK_READ); - - // break on eof - if (!read_bytes) - break; - } - } else { - fprintf(stderr, "Error opening file\n"); - } + // load the audio file with oggz + OGGZ *track_og = oggz_open("/path/to/opus.ogg", OGGZ_READ); - // don't forget to free the memory - oggz_close(track_og); + /* If there was an issue reading the file, tell the user and stop */ + if (!track_og) { + fprintf(stderr, "Error opening file\n"); + event.reply("There was an issue opening the file!"); + return; } + + // set read callback, this callback will be called on packets with the serialno, + // -1 means every packet will be handled with this callback + oggz_set_read_callback( + track_og, -1, + [](OGGZ *oggz, oggz_packet *packet, long serialno, + void *user_data) { + dpp::voiceconn *voiceconn = (dpp::voiceconn *)user_data; + + // send the audio + voiceconn->voiceclient->send_audio_opus(packet->op.packet, + packet->op.bytes); + + // make sure to always return 0 here, read more on oggz documentation + return 0; + }, + // this will be the value of void *user_data + (void *)v + ); + + // read loop + while (v && v->voiceclient && !v->voiceclient->terminating) { + // you can tweak this to whatever. Here I use BUFSIZ, defined in + // stdio.h as 8192 + static const constexpr long CHUNK_READ = BUFSIZ * 2; + + const long read_bytes = oggz_read(track_og, CHUNK_READ); + + // break on eof + if (!read_bytes) + break; + } + + // don't forget to free the memory + oggz_close(track_og); + + event.reply("Finished playing the audio file!"); + } + }); + + bot.on_ready([&bot](const dpp::ready_t & event) { + if (dpp::run_once()) { + + /* Create a new command. */ + dpp::slashcommand joincommand("join", "Joins your voice channel.", bot.me.id); + + dpp::slashcommand playcommand("play", "Plays an ogg file.", bot.me.id); + + bot.global_bulk_command_create({joincommand, playcommand}); } }); /* Start bot */ bot.start(dpp::st_wait); + return 0; } ~~~~~~~~~~~~~~~~~~~~~~~~~ You can compile this example using the following command - c++ /path/to/source.cc -ldpp -loggz + c++ /path/to/source.cc -ldpp -loggz \ No newline at end of file diff --git a/docpages/example_programs/music_and_audio/record_user.md b/docpages/example_programs/music_and_audio/record_user.md index bf37e15136..f80f53f38e 100644 --- a/docpages/example_programs/music_and_audio/record_user.md +++ b/docpages/example_programs/music_and_audio/record_user.md @@ -20,36 +20,37 @@ int main(int argc, char const *argv[]) /* Replace with the user's id you wish to record */ dpp::snowflake user_id = 407877550216314882; - dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); + /* Setup the bot */ + dpp::cluster bot("token"); FILE *fd; fd = fopen("./me.pcm", "wb"); - bot.on_log(dpp::utility::cout_logger()); + bot.on_log(dpp::utility::cout_logger()); - /* Use the on_message_create event to look for commands */ - bot.on_message_create([&bot, &fd](const dpp::message_create_t & event) { + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot, &fd](const dpp::slashcommand_t& event) { - std::stringstream ss(event.msg.content); - std::string command; + /* Check which command they ran */ + if (event.command.get_command_name() == "record") { - ss >> command; + /* Get the guild */ + dpp::guild* g = dpp::find_guild(event.command.guild_id); - /* Tell the bot to record */ - if (command == ".record") { - dpp::guild * g = dpp::find_guild(event.msg.guild_id); - if (!g->connect_member_voice(event.msg.author.id)) { - bot.message_create(dpp::message( - event.msg.channel_id, - "You don't seem to be on a voice channel! :(" - )); + /* Attempt to connect to a voice channel, returns false if we fail to connect. */ + if (!g->connect_member_voice(event.command.get_issuing_user().id)) { + event.reply("You don't seem to be in a voice channel!"); + return; } - } + + /* Tell the user we joined their channel. */ + event.reply("Joined your channel, now recording!"); + } else if (event.command.get_command_name() == "stop") { - /* Tell the bot to stop recording */ - if (command == ".stop") { - event.from->disconnect_voice(event.msg.guild_id); + event.from->disconnect_voice(event.command.guild_id); fclose(fd); + + event.reply("Stopped recording."); } }); @@ -59,8 +60,21 @@ int main(int argc, char const *argv[]) } }); + bot.on_ready([&bot](const dpp::ready_t & event) { + if (dpp::run_once()) { + + /* Create a new command. */ + dpp::slashcommand recordcommand("record", "Joins your voice channel and records you.", bot.me.id); + + dpp::slashcommand stopcommand("stop", "Stops recording you.", bot.me.id); + + bot.global_bulk_command_create({recordcommand, stopcommand}); + } + }); + /* Start bot */ bot.start(dpp::st_wait); + return 0; } ~~~~~~~~~~ diff --git a/docpages/example_programs/music_and_audio/soundboard.md b/docpages/example_programs/music_and_audio/soundboard.md index 624af1530b..88d6940b6e 100644 --- a/docpages/example_programs/music_and_audio/soundboard.md +++ b/docpages/example_programs/music_and_audio/soundboard.md @@ -32,37 +32,60 @@ int main(int argc, char const *argv[]) } /* Setup the bot */ - dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); // Privileged intent required to receive message content + dpp::cluster bot("token"); - bot.on_log(dpp::utility::cout_logger()); + bot.on_log(dpp::utility::cout_logger()); - /* Use the on_message_create event to look for commands */ - bot.on_message_create([&bot, robot, robot_size](const dpp::message_create_t & event) { + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot, robot, robot_size](const dpp::slashcommand_t& event) { - std::stringstream ss(event.msg.content); - std::string command; + /* Check which command they ran */ + if (event.command.get_command_name() == "join") { - ss >> command; + /* Get the guild */ + dpp::guild* g = dpp::find_guild(event.command.guild_id); - /* Tell the bot to join the discord voice channel the user is on. Syntax: .join */ - if (command == ".join") { - dpp::guild * g = dpp::find_guild(event.msg.guild_id); - if (!g->connect_member_voice(event.msg.author.id)) { - bot.message_create(dpp::message(event.msg.channel_id, "You don't seem to be on a voice channel! :(")); + /* Attempt to connect to a voice channel, returns false if we fail to connect. */ + if (!g->connect_member_voice(event.command.get_issuing_user().id)) { + event.reply("You don't seem to be in a voice channel!"); + return; } - } + + /* Tell the user we joined their channel. */ + event.reply("Joined your channel!"); + } else if (event.command.get_command_name() == "robot") { + + /* Get the voice channel the bot is in, in this current guild. */ + dpp::voiceconn* v = event.from->get_voice(event.channel.guild_id); - /* Tell the bot to play the sound file 'Robot.pcm'. Syntax: .robot */ - if (command == ".robot") { - dpp::voiceconn* v = event.from->get_voice(event.msg.guild_id); - if (v && v->voiceclient && v->voiceclient->is_ready()) { - v->voiceclient->send_audio_raw((uint16_t*)robot, robot_size); + /* If the voice channel was invalid, or there is an issue with it, then tell the user. */ + if (!v || !v->voiceclient || !v->voiceclient->is_ready()) { + event.reply("There was an issue with getting the voice channel. Make sure I'm in a voice channel!"); + return; } + + /* Tell the bot to play the sound file 'Robot.pcm' in the current voice channel. */ + v->voiceclient->send_audio_raw((uint16_t*)robot, robot_size); + + event.reply("Played robot."); + } + }); + + bot.on_ready([&bot](const dpp::ready_t & event) { + if (dpp::run_once()) { + + /* Create a new command. */ + dpp::slashcommand joincommand("join", "Joins your voice channel.", bot.me.id); + + dpp::slashcommand robotcommand("robot", "Plays a robot noise in your voice channel.", bot.me.id); + + bot.global_bulk_command_create({joincommand, robotcommand}); } }); /* Start bot */ bot.start(dpp::st_wait); + return 0; } -~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~ \ No newline at end of file diff --git a/docpages/example_programs/the_basics/attachments.md b/docpages/example_programs/the_basics/attachments.md index 31ca63d754..a8ed5ba4d2 100644 --- a/docpages/example_programs/the_basics/attachments.md +++ b/docpages/example_programs/the_basics/attachments.md @@ -8,31 +8,39 @@ D++ has this helper function to read a file: `dpp::utility::read_file`. An example program: -@note Because these examples utilizes message content, they require the message content privileged intent. - ~~~~~~~~~~{.cpp} #include int main() { - dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); + dpp::cluster bot("token"); bot.on_log(dpp::utility::cout_logger()); + + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) { + /* Check which command they ran */ + if (event.command.get_command_name == "file") { - /* Message handler to look for a command called !file */ - bot.on_message_create([&bot](const dpp::message_create_t &event) { - if (event.msg.content == "!file") { - // create a message - dpp::message msg(event.msg.channel_id, "Hey there, i've got a new file!"); + dpp::message msg(event.msg.channel_id, "Hey there, I've got a new file!"); - // attach the file to the message + /* attach the file to the message */ msg.add_file("foobar.txt", dpp::utility::read_file("path_to_your_file.txt")); - // send the message - bot.message_create(msg); + /* Reply to the user with the message, with our file attached. */ + event.reply(msg); + } + }); + + bot.on_ready([&bot](const dpp::ready_t& event) { + if (dpp::run_once()) { + + /* Create and register a command when the bot is ready */ + bot.global_command_create(dpp::slashcommand("file", "Send a message with a file attached!", bot.me.id)); } }); bot.start(dpp::st_wait); + return 0; } ~~~~~~~~~~ @@ -47,31 +55,42 @@ The following example program shows how to request a file and attach it to a mes #include int main() { - dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); + dpp::cluster bot("token"); bot.on_log(dpp::utility::cout_logger()); - /* Message handler to look for a command called !file */ - bot.on_message_create([&bot](const dpp::message_create_t &event) { - if (event.msg.content == "!file") { - // request an image - bot.request("https://dpp.dev/DPP-Logo.png", dpp::m_get, [&bot, channel_id = event.msg.channel_id](const dpp::http_request_completion_t & httpRequestCompletion) { + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) { + /* Check which command they ran */ + if (event.command.get_command_name == "file") { - // create a message - dpp::message msg(channel_id, "This is my new attachment:"); + /* Request the image from the URL specified and capture the event in a lambda. */ + bot.request("https://dpp.dev/DPP-Logo.png", dpp::m_get, [event](const dpp::http_request_completion_t & httpRequestCompletion) { - // attach the image on success + /* Create a message */ + dpp::message msg(event.command.channel_id, "This is my new attachment:"); + + /* Attach the image to the message, only on success (Code 200). */ if (httpRequestCompletion.status == 200) { msg.add_file("logo.png", httpRequestCompletion.body); } - // send the message - bot.message_create(msg); + /* Send the message, with our attachment. */ + event.reply(msg); }); + } + }); + + bot.on_ready([&bot](const dpp::ready_t& event) { + if (dpp::run_once()) { + + /* Create and register a command when the bot is ready */ + bot.global_command_create(dpp::slashcommand("file", "Send a message with an image attached from the internet!", bot.me.id)); } }); bot.start(dpp::st_wait); + return 0; } ~~~~~~~~~~ @@ -84,29 +103,42 @@ Upload the image in the same message as the embed and then reference it in the e #include int main() { - dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); + dpp::cluster bot("token"); bot.on_log(dpp::utility::cout_logger()); - /* Message handler to look for a command called !file */ - bot.on_message_create([&bot](const dpp::message_create_t &event) { - if (event.msg.content == "!file") { - // create a message + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) { + /* Check which command they ran */ + if (event.command.get_command_name == "file") { + + /* Create a message. */ dpp::message msg(event.msg.channel_id, ""); - // attach the image to the message + /* Attach the image to the message we just created. */ msg.add_file("image.jpg", dpp::utility::read_file("path_to_your_image.jpg")); + /* Create an embed. */ dpp::embed embed; - embed.set_image("attachment://image.jpg"); // reference to the attached file + embed.set_image("attachment://image.jpg"); /* Set the image of the embed to the attached image. */ + + /* Add the embed to the message. */ msg.add_embed(embed); - // send the message - bot.message_create(msg); + event.reply(msg); + } + }); + + bot.on_ready([&bot](const dpp::ready_t& event) { + if (dpp::run_once()) { + + /* Create and register a command when the bot is ready */ + bot.global_command_create(dpp::slashcommand("file", "Send a local image along with an embed with the image!", bot.me.id)); } }); bot.start(dpp::st_wait); + return 0; } ~~~~~~~~~~ diff --git a/docpages/example_programs/the_basics/embeds.md b/docpages/example_programs/the_basics/embeds.md index 837a5199f5..051a83f408 100644 --- a/docpages/example_programs/the_basics/embeds.md +++ b/docpages/example_programs/the_basics/embeds.md @@ -1,8 +1,6 @@ \page embed-message Sending Embeds -You might have seen these special messages, often sent by bots. In this section, we will show how to create an embed. - -@note Because this example utilizes message content, it requires the message content privileged intent. +If you've been in a server and used a bot or even seen a message from a bot, you might have seen a special messages, often sent by these bots. These are called embeds! In this section, we will show how to create an embed and reply to a user, using our newly created embed! ~~~~~~~~~~{.cpp} #include @@ -11,11 +9,12 @@ int main() { /* Setup the bot */ dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); - /* Message handler to look for a command called !embed */ - bot.on_message_create([&bot](const dpp::message_create_t & event) { - if (event.msg.content == "!embed") { + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) { + /* Check which command they ran */ + if (event.command.get_command_name == "embed") { - /* create the embed */ + /* Create an embed */ dpp::embed embed = dpp::embed(). set_color(dpp::colors::sti_blue). set_title("Some name"). @@ -41,8 +40,19 @@ int main() { set_footer(dpp::embed_footer().set_text("Some footer text here").set_icon("https://dpp.dev/DPP-Logo.png")). set_timestamp(time(0)); - /* reply with the created embed */ - bot.message_create(dpp::message(event.msg.channel_id, embed).set_reference(event.msg.id)); + /* Create a message with the content as our new embed. */ + dpp::message msg(event.command.channel_id, embed); + + /* Reply to the user with the message, containing our embed. */ + event.reply(msg); + } + }); + + bot.on_ready([&bot](const dpp::ready_t& event) { + if (dpp::run_once()) { + + /* Create and register a command when the bot is ready */ + bot.global_command_create(dpp::slashcommand("embed", "Send a test embed!", bot.me.id)); } }); diff --git a/docpages/images/button.png b/docpages/images/button.png index ad1a40d98c..632ebb2025 100644 Binary files a/docpages/images/button.png and b/docpages/images/button.png differ diff --git a/docpages/images/button_2.png b/docpages/images/button_2.png index 3947201153..f495a8f8f3 100644 Binary files a/docpages/images/button_2.png and b/docpages/images/button_2.png differ diff --git a/docpages/images/context_menu_user_command.png b/docpages/images/context_menu_user_command.png index 31b0d9334b..0f67dcc2bd 100644 Binary files a/docpages/images/context_menu_user_command.png and b/docpages/images/context_menu_user_command.png differ diff --git a/docpages/images/context_menu_user_command_showcase.png b/docpages/images/context_menu_user_command_showcase.png index 9d2127599e..977a6c6ff1 100644 Binary files a/docpages/images/context_menu_user_command_showcase.png and b/docpages/images/context_menu_user_command_showcase.png differ diff --git a/docpages/images/embed.png b/docpages/images/embed.png index a8a6e33434..7bec190edd 100644 Binary files a/docpages/images/embed.png and b/docpages/images/embed.png differ