diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 7a82012fad..384144f12e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,5 +1,5 @@ --- -name: Bug report +name: Bug Report about: Create a report to help us improve title: '' labels: bug @@ -7,27 +7,27 @@ assignees: braindigitalis --- -**Git commit reference** +**Git Commit Reference** The git commit reference of the version you are using, obtainable via `git show -s --format="%H"` -**Describe the bug** +**Describe the Bug** A clear and concise description of what the bug is. **To Reproduce** -Steps to reproduce the behavior: +Steps to reproduce the behaviour: 1. Issue the method call 'X' 2. Retrieve returned value 'Y' 3. Returned value not in the range 'A..B' -**Expected behavior** +**Expected Behaviour** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. -**System Details:** +**System Details** - OS: [e.g. Debian Bullseye] - Discord Client used for testing [mobile, desktop, web] -**Additional context** -Add any other context about the problem here. +**Additional Context** +Add any other context about the problem here. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7d61..94963de5b2 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,5 +1,5 @@ --- -name: Feature request +name: Feature Request about: Suggest an idea for this project title: '' labels: '' @@ -8,7 +8,7 @@ assignees: '' --- **Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] +A clear and concise description of what the problem is. E.g. I'm always frustrated when […] **Describe the solution you'd like** A clear and concise description of what you want to happen. @@ -17,4 +17,4 @@ A clear and concise description of what you want to happen. A clear and concise description of any alternative solutions or features you've considered. **Additional context** -Add any other context or screenshots about the feature request here. +Add any other context or screenshots about the feature request here. \ No newline at end of file diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 995c7f4135..1849e70d05 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,8 +1,9 @@ + + - [ ] My pull request is made against the `dev` branch. - [ ] I have ensured that the changed library can be built on your target system. I did not introduce any platform-specific code. -- [ ] I have ensured that all methods and functions are **fully documented** using doxygen style comments. -- [ ] I tested my commits, by adding a test case to the unit tests if needed +- [ ] I have ensured that all methods and functions are **fully documented** using Doxygen style comments. +- [ ] I tested my commits, by adding a test case to the unit tests if needed. - [ ] I have ensured that I did not break any existing API calls. -- [ ] My code follows the [coding style guide](https://dpp.dev/coding-standards.html) (if you are not sure, match the code style of existing files including indent style etc). -- [ ] I have not built my pull request using AI, a static analysis tool or similar without any human oversight. Where I have generated this pull request using a tool, I have justified why this is needed. - +- [ ] My code follows the [coding style guide](https://dpp.dev/coding-standards.html) (if you are not sure, match the code style of existing files including indent style etc.). +- [ ] I have not built my pull request using AI, a static analysis tool, or similar without any human oversight. Where I have generated this pull request using a tool, I have justified why this is needed. \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 7cdf508e2c..fe1d64cc36 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,4 +1,3 @@ - # Contributor Covenant Code of Conduct ## Our Pledge @@ -60,8 +59,9 @@ representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement in the -[Discord][discord] server. +reported to the community leaders responsible for enforcement at +[the official Discord server](https://discord.gg/dpp) or sent via DM to `@brain` +for discreet treatment. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the @@ -126,9 +126,8 @@ For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations]. -[discord]: https://discord.gg/dpp [homepage]: https://www.contributor-covenant.org [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html [Mozilla CoC]: https://github.com/mozilla/diversity [FAQ]: https://www.contributor-covenant.org/faq -[translations]: https://www.contributor-covenant.org/translations +[translations]: https://www.contributor-covenant.org/translations \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e0dc64c4d8..a67069c09b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,14 +5,10 @@ When contributing to this repository, please do not feel intimidated! We welcome ## Pull Request Process 1. Pull requests should be made against the `dev` branch. -2. Ensure that the changed library can be built on your target system. Do not introduce any platform- - specific code. +2. Ensure that the changed library can be built on your target system. Do not introduce any platform specific code. 3. Ensure that all methods and functions you add are **fully documented** using doxygen style comments. -4. Test your commit! Make a simple single-file test bot to demonstrate the change, include this with the PR - as an attached file on a comment, so we can test and see how it works. +4. Test your commit! Make a simple single-file test bot to demonstrate the change, include this with the PR as an attached file on a comment, so we can test and see how it works. 5. Ensure that you do not break any existing API calls without discussing on Discord first! -6. Be sure to follow the coding style guide (if you are not sure, match the code style of existing files - including indent style etc). -7. Your PR must pass the CI actions before being allowed to be merged. Our PR actions check that the - build will compile on various platforms before release and makes precompiled versions of the library. -8. Automated changes e.g. via grammarly or a static analysis tool will not usually be accepted into the code without proper thought out justification (by a human being, not an AI or an App) as to why the changes are required. Generally a PR should do more than fix a single spelling error for example as this just takes precious time for something which could be resolved a direct commit to the dev branch. +6. Be sure to follow the coding style guide (if you are not sure, match the code style of existing files including indent style etc.). +7. Your PR must pass the CI actions before being allowed to be merged. Our PR actions check that the build will compile on various platforms before release and make precompiled versions of the library. +8. Automated changes e.g. via Grammarly or a static analysis tool will not usually be accepted into the code without proper thought out justification (by a human being, not an AI or an App) as to why the changes are required. Generally a PR should do more than fix a single spelling error for example as this just takes precious time for something which could have been resolved by a direct commit to the dev branch. \ No newline at end of file diff --git a/LICENSE b/LICENSE index e970b50366..815107d1f8 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2021 Craig Edwards and D++ Contributors + Copyright 2021-2023 Craig Edwards and D++ Contributors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -198,4 +198,4 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and - limitations under the License. + limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md index 9c4d765560..343f2464bb 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,9 @@
- D++ is a lightweight and efficient library for **Discord** written in **modern C++**, covering as much of the API specification as possible with an **incredibly small memory footprint** even when caching large amounts of data. -### Library features: +### Library Features * Support for Discord API v10 * Really small memory footprint @@ -29,7 +28,7 @@ D++ is a lightweight and efficient library for **Discord** written in **modern C * [Voice support](https://dpp.dev/soundboard.html) (sending **and** receiving audio) * The entire Discord API is available for use in the library * Stable [Windows support](https://dpp.dev/buildwindows.html) -* Ready-made compiled packages for Windows, Raspberry Pi (ARM64/ARM7/ARMv6), Debian x86/x64 and RPM based distributions +* Ready-made compiled packages for Windows, Raspberry Pi (ARM64/ARM7/ARMv6), Debian x86/x64, and RPM based distributions * Highly scalable for large amounts of guilds and users Want to help? Drop me a line or send a PR. @@ -46,28 +45,29 @@ The documentation is constantly evolving and improving, generated from the code This is a simple ping-pong example using slash commands. -```c++ +```cpp #include #include - + int main() { - dpp::cluster bot(std::getenv("BOT_TOKEN")); - - bot.on_slashcommand([](auto event) { - if (event.command.get_command_name() == "ping") { - event.reply("Pong!"); - } - }); - - bot.on_ready([&bot](auto event) { - if (dpp::run_once()) { - bot.global_command_create( - dpp::slashcommand("ping", "Ping pong!", bot.me.id) - ); - } - }); - - bot.start(dpp::st_wait); + dpp::cluster bot(std::getenv("BOT_TOKEN")); + + bot.on_slashcommand([](auto event) { + if (event.command.get_command_name() == "ping") { + event.reply("Pong!"); + } + }); + + bot.on_ready([&bot](auto event) { + if (dpp::run_once()) { + bot.global_command_create( + dpp::slashcommand("ping", "Ping pong!", bot.me.id) + ); + } + }); + + bot.start(dpp::st_wait); + return 0; } ``` @@ -76,18 +76,23 @@ You can find more examples in our [example page](https://dpp.dev/md_docpages_03_ ## 💻 Supported Systems ### Linux + The library runs ideally on **Linux**. -### Mac OS X and FreeBSD -The library is well-functional and stable on **Mac OS X** and **FreeBSD** too. +### macOS and FreeBSD + +The library is well-functional and stable on **macOS** and **FreeBSD** too. ### Raspberry Pi + For running your bot on a **Raspberry Pi**, we offer a prebuilt .deb package for ARM64, ARM6, and ARM7 so that you do not have to wait for it to compile. ### Windows + **Windows** is well-supported with ready-made compiled DLL and LIB files, please check out our [Windows Bot Template repository](https://github.com/brainboxdotcc/windows-bot-template). The Windows Bot repository can be cloned and integrated immediately into any Visual Studio 2019 and 2022 project in a matter of minutes. ### Other OS + The library should work fine on other operating systems as well, and if you run a D++ bot on something not listed here, please let us know! ## 🔰 Getting Started @@ -106,15 +111,13 @@ For frequently asked questions and their answers, please visit our [FAQ page](ht ## 🤝 Contributing -Contributions, issues and feature requests are welcome. After cloning and setting up project locally, you can just submit -a PR to this repo and it will be deployed once it's accepted. +Contributions, issues and feature requests are welcome. After cloning and setting up a project locally, you can just submit a PR to this repo and it will be deployed once it's accepted. Please read the [D++ Code Style Guide](https://dpp.dev/coding-standards.html) for more information on how we format pull requests. ## 💬 Get in touch -If you have various suggestions, questions or want to discuss things with our community, [Join our discord server](https://discord.gg/dpp)! -Make a humorous reference to brains in your nickname to get access to a secret brain cult channel! :) +If you have various suggestions, questions or want to discuss things with our community, [Join our discord server](https://discord.gg/dpp)! Make a humorous reference to brains in your nickname to get access to a secret brain cult channel! :) [![Discord](https://img.shields.io/discord/825407338755653642?style=flat)](https://discord.gg/dpp) @@ -125,26 +128,30 @@ We love people's support in growing and improving. Be sure to leave a ⭐️ if ## 📂 Dependencies ### Build requirements -* [cmake](https://cmake.org/) (version 3.13+) + +* [CMake](https://cmake.org/) (version 3.13+) * A supported C++ compiler from the list below ### Supported compilers + * [g++](https://gcc.gnu.org) (version 8 or higher) -* [clang](https://clang.llvm.org/) +* [Clang](https://clang.llvm.org/) * AppleClang (12.0 or higher) -* Microsoft Visual Studio 2019 or 2022 (16.x/17.x) -* [mingw-w64](https://www.mingw-w64.org/) (gcc version 8 or higher) +* [Microsoft Visual Studio 2019 or 2022](https://visualstudio.microsoft.com/downloads/) (16.x/17.x) Other compilers may work (either newer versions of those listed above, or different compilers entirely) but have not been tested by us. ### External Dependencies (You must install these) + * [OpenSSL](https://openssl.org/) (whichever `-dev` package comes with your OS) * [zlib](https://zlib.net) (whichever `-dev` package comes with your OS) #### Optional Dependencies + For voice support you require both of: * [LibOpus](https://www.opus-codec.org) * [libsodium](https://github.com/jedisct1/libsodium) ### Included Dependencies (Packaged with the library) -* [nlohmann::json](https://github.com/nlohmann/json) + +* [nlohmann::json](https://github.com/nlohmann/json) \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md index 1092e625e3..7b917c5e42 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -10,5 +10,4 @@ ## Reporting a Vulnerability -To report a vulnerability please contact the development team confidentially on Discord by contacting `@brain` via a DM on https://discord.gg/dpp - We will discuss via a group chat if necessary and action -the fix. Vulnerabilties are actioned and fixed within a 30 day window. Once the fix has been put into a release version, the vulnerability will be disclosed to the public. +To report a vulnerability please contact the development team confidentially on Discord by contacting `@brain` via a DM on https://discord.gg/dpp - We will discuss via a group chat if necessary and action the fix. Vulnerabilities are actioned and fixed within a 30 day window. Once the fix has been put into a release version, the vulnerability will be disclosed to the public. \ No newline at end of file diff --git a/docpages/01_frequently_asked_questions.md b/docpages/01_frequently_asked_questions.md index 7920108327..366ed1aea7 100644 --- a/docpages/01_frequently_asked_questions.md +++ b/docpages/01_frequently_asked_questions.md @@ -3,87 +3,113 @@ [TOC] ## Is this library in production use? -This library powers the bot [TriviaBot](https://triviabot.co.uk) which has over **151,000 servers**, and [Sporks](https://sporks.gg) which has over **3,500 severs**. The library's use in these bots shows that the library is production ready for bots of all sizes. + +This library powers the bot [TriviaBot](https://triviabot.co.uk) which has over **199,000 servers**, and [Sporks](https://sporks.gg) which has over **3,500 severs**. The library's use in these bots shows that the library is production ready for bots of all sizes. ## How much RAM does this library use? -In production on TriviaBot, the bot takes approximately 2gb of ram to run 18 separate processes (this is approximately **140mb** per process) on a production bot with 36 million users and 151,000 guilds. Each process takes under 1% CPU. This is less than a quarter of the memory of a similar C++ Discord library, **Aegis.cpp** (version 2). + +In production on TriviaBot, the bot takes approximately 2 GB of RAM to run 18 separate processes (this is approximately **140 MB** per process) on a production bot with 36 million users and 151,000 guilds. Each process takes under 1% CPU. This is less than a quarter of the memory of a similar C++ Discord library, **Aegis.cpp** (version 2). For a very small bot, you can get the memory usage as low as **6 megabytes** on a Raspberry Pi. ## How do I use this library in Windows? -The easiest way is to use our [template project](https://github.com/brainboxdotcc/windows-bot-template). If you are unable to do this, download the precompiled latest release from our GitHub releases, and take the dlls, `.lib` file, and header files (`bin`, `lib` and `include` directories), placing them in a easily accessible place on your computer. Go into Visual Studio project settings in a new project, and point the project directories (notably the library directories and and include directories) at the correct locations. Add the `include` folder you extracted to your include directories, and add `dpp.lib` to your library directories. Ensure the project is set to C++17 standard in the settings. You should then be able to compile example programs within that project. When you run the program you have compiled you must ensure that all the dll files from the `bin` directory exist in the same directory as your executable. + +The easiest way is to use our [template project](https://github.com/brainboxdotcc/windows-bot-template). If you are unable to do this, download the precompiled latest release from our GitHub releases, and take the dlls, `.lib` file, and header files (`bin`, `lib` and `include` directories), placing them in a easily accessible place on your computer. Go into Visual Studio project settings in a new project, and point the project directories (notably the library directories and and include directories) at the correct locations. Add the `include` folder you extracted to your include directories, and add `dpp.lib` to your library directories. Ensure the project is set to C++17 standard or later in the settings. You should then be able to compile example programs within that project. When you run the program you have compiled you must ensure that all the dll files from the `bin` directory exist in the same directory as your executable. ## Does this library support Visual Studio 2022? -Yes! The master branch comes with pre-built binaries for Visual Studio 2022 and our Windows bot template has a [vs2022 branch](https://github.com/brainboxdotcc/windows-bot-template/tree/vs2022) which you can clone to get Visual Studio 2022 specific code. For the time being we support both Visual Studio 2019 and 2022. At some point in the future only 2022 may be supported as 2019 becomes outdated. + +Yes! The master branch comes with pre-built binaries for Visual Studio 2022 and our Windows bot template has a [VS2022 branch](https://github.com/brainboxdotcc/windows-bot-template/tree/vs2022) which you can clone to get Visual Studio 2022 specific code. For the time being we support both Visual Studio 2019 and 2022. At some point in the future only 2022 may be supported as 2019 becomes outdated. ## How much of the library is completed? + All REST calls (outbound commands) are completed including all currently available interactions, and all Discord events are available. The library also has voice support. ## How do I chat with the developers or get help? + The best place to do this is on the [Discord server](https://discord.gg/dpp). You most likely won't get an answer immediately (we have lives, and need to sleep sometimes), but we will be willing to help! ## How can I contribute to development? -Just star and fork a copy of the repository, and submit a Pull Request! We won't bite! Authors of accepted pull requests get a special role on our [Discord server](https://discord.gg/dpp). -## Whats the best way to learn C++? +Just star and fork a copy of the repository, and submit a Pull Request! We won't bite! Significant contributors get a special role on our [Discord server](https://discord.gg/dpp). + +## What's the best way to learn C++? + A simple search can find some learning tools, however not all are good. Here is a list of some (good) learning resources: -* [CodeAcademy](https://www.codecademy.com/learn/c-plus-plus) +* [Codecademy](https://www.codecademy.com/learn/c-plus-plus) * [Learn CPP](https://www.learncpp.com/) * [Learn CPP (Very Basic)](https://www.learn-cpp.org/) -If you don't understand something then feel free to ask in the [Discord server](https://discord.gg/dpp) ...*we don't bite!* +If you don't understand something then feel free to ask in the [Discord server](https://discord.gg/dpp)… *we don't bite!* ## Do I need to be an expert in C++ to use this library? + NO! Definitely not! We have tried to keep things as simple as possible. We only use language features where they make sense, not just because they exist. Take a look at the example program (`test.cpp` and you'll see just how simple it is to get up and running quickly). We use a small subset of C++17 and C++14 features. -## Why is D++ also called DPP +## Why is D++ also called DPP? + DPP is short for *D Plus Plus* (D++), a play on the Discord and C++ names. You'll see the library referred to as `dpp` within source code as `d++` is not a valid symbol so we couldn't exactly use that as our namespace name. ## Is D++ a single header library? + No, D++ is a classically designed library which installs itself to your library directory/system directory as a shared object or dll. You must link to its `.lib` file and include its header files to make use of it. We have no plans for a single-header build. ## Does this library support slash commands/interactions? + Yes! This library supports slash commands and interactions. For more information please see \ref slashcommands "Using Slash Commands and Interactions". ## Does this library support buttons/drop down menus (message components)? -Yes! This library supports button message components, e.g. interactive buttons on the bottom of messages. For more information please see our \ref components "Using component interactions" and \ref components2 "Using component interactions (advanced)" examples. + +Yes! This library supports button message components, e.g. interactive buttons on the bottom of messages. For more information please see our \ref components "Using Component Interactions" and \ref components2 "Using Component Interactions (Advanced)" examples. ## Is the library asynchronous? -All functions within D++ are multi-threaded. You should still avoid doing long operations within event handlers or within callbacks, to prevent starvation of the threads managing each shard. Various blocking operations such as running files and making HTTP requests are offered as library functions (for example dpp::utility::exec) + +All functions within D++ are multi-threaded. You should still avoid doing long operations within event handlers or within callbacks, to prevent starvation of the threads managing each shard. Various blocking operations such as running files and making HTTP requests are offered as library functions (for example dpp::utility::exec). ## Does this library support voice? + Yes! This library supports voice and will automatically enable voice if your system has the libopus and libsodium libraries. When running `cmake` the script will identify if these libraries are found. See the example programs for information on how to send audio. ## Does this library support sharding? + Yes! D++ supports sharding and also clustering (grouping of shards into one process) to ensure it is scalable for small and large bots alike. ## How do I contribute to the documentation and website? -The documentation and website are built using Doxygen. To contribute to site pages, submit a Pull Request to the main repository. The site pages can be found within the `docpages` directory. Details of classes, variables, namespaces etc are auto generated from Doxygen comments within the library source code in the `include` and `src` folders. + +The documentation and website are built using Doxygen. To contribute to site pages, submit a Pull Request to the main repository. The site pages can be found within the `docpages` directory. Details of classes, variables, namespaces etc. are auto generated from Doxygen comments within the library source code in the `include` and `src` folders. ## What version of the Discord API does this library support? + D++ only supports Discord API v10, the latest version. D++ major version numbers match the supported Discord API version. ## Does this Discord library support the threads feature? -Yes! D++ supports Discord threads. You can create, edit and delete threads and also attach events watching for messages within threads. + +Yes! D++ supports Discord threads. You can create, edit, and delete threads and also attach events watching for messages within threads. ## Does D++ require C++20 support? + No, at the current time we do not use any C++20 features. Some C++17 features are used, which are available in all recent compilers. -## When I start my bot i get an error: "error while loading shared libraries: libdpp.so: cannot open shared object file: No such file or directory" -To fix this issue, run `ldconfig`: `sudo ldconfig` as root. Log out if your SSH session and log back in, and the bot should be able to find the library. +## When I start my bot I get an error: "error while loading shared libraries: libdpp.so: cannot open shared object file: No such file or directory". + +To fix this issue, run `ldconfig`: `sudo ldconfig` as root. Log out of your SSH session and log back in, and the bot should be able to find the library. + +## When compiling with voice support, I get an error: "No rule to make target 'sodium_LIBRARY_DEBUG-NOTFOUND', needed by 'libdpp.so'. Stop.". -## When compiling with voice support, i get an error: "No rule to make target 'sodium_LIBRARY_DEBUG-NOTFOUND', needed by 'libdpp.so'. Stop." The libsodium package requires pkg-config, but does not check for it when installed. Install it as root, e.g. `sudo apt install pkg-config`. Rerun cmake, and rebuild the library. -## When I try to instantiate a dpp::cluster in windows, a std::bad_alloc exception is thrown -If this happens, ensure you are using the correct precompiled build of the library. Our precompiled binaries are built in two forms, **release mode** and **debug mode** for Visual Studio 2019/2022. These two versions of the library are not cross-compatible due to differences in the debug and release libstdc++. You should not need to build your own copy, but please see the section about \ref buildwindows for more information on how to build your own copy, if needed. +## When I try to instantiate a dpp::cluster on Windows, a std::bad_alloc exception is thrown. + +If this happens, ensure you are using the correct precompiled build of the library. Our precompiled binaries are built in two forms, **release mode** and **debug mode** for Visual Studio 2019/2022. These two versions of the library are not cross-compatible due to differences in the debug and release STL (Microsoft standard library implementation). You should not need to build your own copy, but please see the section about \ref buildwindows for more information on how to build your own copy, if needed. ## Does this library build/run on Raspberry Pi? -Yes! This project will build and run on Raspberry Pi and is very much suited to this kind of system. It may take some time (read: hours) to compile the project on your Raspberry Pi unless you build it using a cross compiler. We offer pre-built `.deb` files for arm6, arm7 and arm64, you should use these where possible to avoid having to compile it by hand, or you can use a cross-compiler to build it on your PC then transfer the compiled binaries across. -## There are so many versions! Which deb file do i need for my Raspberry Pi? +Yes! This project will build and run on Raspberry Pi and is very much suited to this kind of system. It may take some time (read: hours) to compile the project on your Raspberry Pi unless you build it using a cross compiler. We offer pre-built `.deb` files for ARM6, ARM7 and ARM64, you should use these where possible to avoid having to compile it by hand, or you can use a cross-compiler to build it on your PC then transfer the compiled binaries across. + +## There are so many versions! Which deb file do I need for my Raspberry Pi? + Depending on which Raspberry Pi version you have, you will need to download a different release binary: + @@ -97,13 +123,17 @@ Depending on which Raspberry Pi version you have, you will need to download a di
Raspberry Pi Model
## Are other ARM devices supported? -Yes! We have confirmed that the D++ deb file will successfully install and operate on various forms of cellphone or non-pi ARM devices. If you get it working on any other devices please let us know and we can build a compatibility chart. + +Yes! We have confirmed that the D++ deb file will successfully install and operate on various forms of cellphone or non-Pi ARM devices. If you get it working on any other devices please let us know and we can build a compatibility chart. ## Can I run a D++ bot in Replit? + Yes! You can indeed run your bot in a replit.com container. [You can find a ready to go demo repl here](https://replit.com/@braindigitalis/dpp-demo-bot). We also have a \ref building-a-cpp-discord-bot-in-repl "guide showing how to do this". ## Why do the "get" functions like "messages_get" return void rather than what I'm after? + All the functions that obtain data directly from Discord (as opposed to the cache) perform HTTPS requests and may have to wait, either for the request itself or for their turn in a queue to respect rate limits. As such, it does not make sense that they should return a value, as this would mean they block execution of your event. Instead, each has a lambda, a function handler which receives the result of the request, which you can then read from within that function to get the data you are interested in. Note that this result will arrive on a different thread to the one which made the request. If you instead want the function to return a value, use the methods ending with `_sync` that will block until they have a response. Note that these forms of call will throw an exception on failure. -## Can i use a user token with this library (as opposed to a bot token)? -No. This feature is not supported as it is against the Discord Terms Of Service, and therefore we have no plans to ever support it. You should not automate any user token. Some libraries used to support this but it is a legacy feature of those libraries (where still available) dating back to before Discord offered an official public API. Please be aware that if Discord ever catch you automating a user token (or making a user client that uses a bot token) they can and do ban people for this. +## Can I use a user token with this library (as opposed to a bot token)? + +No. This feature is not supported as it is against the Discord Terms of Service, and therefore we have no plans to ever support it. You should not automate any user token. Some libraries used to support this but it is a legacy feature of those libraries (where still available) dating back to before Discord offered an official public API. Please be aware that if Discord ever catches you automating a user token (or making a user client that uses a bot token) they can and do ban people for this. \ No newline at end of file diff --git a/docpages/02_disdppgloss.md b/docpages/02_disdppgloss.md index 773ee12a3c..23565ff927 100644 --- a/docpages/02_disdppgloss.md +++ b/docpages/02_disdppgloss.md @@ -1,51 +1,51 @@ \page glossary-of-common-discord-terms A Glossary of Common Discord Terms -This is a list of terms that you should know if you want to use D++ (or any other discord library). These terms are not D++ specific, and are commonly used throughout most of the Discord developer community. This list, with a few exceptions, ***is discord specific***, that is to say that this is not a explanation of commonly used C++ terms, it is for people who are not familiar with the terminology of the discord API and libraries themselves. +This is a list of terms that you should know if you want to use D++ (or any other Discord library). These terms are not D++ specific, and are commonly used throughout most of the Discord developer community. This list, with a few exceptions, ***is Discord specific***, that is to say that this is not an explanation of commonly used C++ terms, it is for people who are not familiar with the terminology of the Discord API and libraries themselves. -#### Glossary +## Glossary -Listed in alphabetical order, with terms in bold, here are the basics on... +Listed in alphabetical order, with terms in bold, here are the basics on… -1. **Action row**: A collection of up to five **components** which is attached to a message. +* **Action row**: A collection of up to five **components** which is attached to a message. -2. **Audit log**: A log of **events** that have happened in a **guild**. +* **Audit log**: A log of **events** that have happened in a **guild**. -3. **Auto mod**: Discord's low-code solution to moderation. However, it is very limited in scope. +* **Auto mod**: Discord's low-code solution to moderation. However, it is very limited in scope. -4. **Badge**: A decoration on someone's profile showing certain things about them, such as if they have nitro, if they are a discord developer, etc. +* **Badge**: A decoration on someone's profile showing certain things about them, such as if they have Nitro, if they are a Discord developer, etc. -5. **Bot token**: A secret string of characters that is used as a "login" to your bot. If you lose it or it gets leaked you will have to get a new one from the discord developer portal, so be sure to keep it in a place that is both secure and where you won't forget it. +* **Bot token**: A secret string of characters that is used as a "login" to your bot. If you lose it or it gets leaked you will have to get a new one from the Discord developer portal, so be sure to keep it in a place that is both secure and where you won't forget it. -6. **Button**: A **component** on a message that can be styled that sends an **event** when clicked on by a user. +* **Button**: A **component** on a message that can be styled that sends an **event** when clicked on by a user. -7. **Cache**: A type of storage efficient for things like messages. +* **Cache**: A type of storage efficient for things like messages. -8. **Callback**: While not strictly related to discord, it is used a LOT in D++. A callback is when a function is passed to another function, sort of like how you might give someone a telephone number (you give them the means to do some sort of interaction rather than asking them how to interact), which is used to handle responses to **events**. +* **Callback**: While not strictly related to Discord, it is used a LOT in D++. A callback is when a function is passed to another function, sort of like how you might give someone a telephone number (you give them the means to do some sort of interaction rather than asking them how to interact), which is used to handle responses to **events**. -9. **Cluster**: A singular bot application, which is composed of one or more **shards**, a **cluster** is the center of bot development. +* **Cluster**: A singular bot application, which is composed of one or more **shards**, a **cluster** is the centre of bot development. -10. **\(Slash\) command**: The primary way a user interacts with a bot. It is a command sent to the bot with **parameters** (which may be optional) and is initiated by staring a message with `/`. +* **Component**: A component is anything that can appear in a bot's message besides text, such as **buttons** and **select menus**. -11. **Component**: A component is anything that can appear in a bot's message besides text, such as **buttons** and **select menus**. +* **Drop down/Select menu**: A **component** of a message that upon being clicked drops down and allows the user to select an option. -12. **Drop down/Select menu**: A **component** of a message that upon being clicked drops down and allows the user to select an option. +* **Embeds**: A widget attached to a message which can contain multiple fields of texts, an image, and much more information. -13. **Embeds**: A widget attached to a message which can contain multiple fields of texts, an image, and much more information. +* **Ephemeral**: A message only visible to the user being replied to. -14. **Ephemeral**: A message only visible to the user being replied to. +* **Event**: Something that a Discord bot can respond to, such as a message being sent, a **button** being clicked, or an option being selected, among others. -15. **Event**: Something that a Discord bot can respond to, such as a message being sent, a **button** being clicked, or an option being selected, among others. +* **Guild**: What the Discord API (and most libraries for it) call a server. -16. **Guild**: What the Discord API (and most libraries for it) call a server. +* **Intents**: The right for a bot to receive certain data from the Discord API. -17. **Intents**: The right for a bot to receive certain data from the Discord API. +* **Interaction**: An object that contains information about whenever a user interacts with an application, such as sending a message or clicking a button. It is the main part of an **event** that will be accessed in an application. -18. **Interaction**: A object that contains information about whenever a user interacts with a application, such as sending a message or clicking a button. It is the main part of an **event** that will be accessed in an application. +* **Modal**: A pop up form that contains text that can be sent by a bot. -19. **Modal**: A pop up form that contains text that can be sent by a bot. +* **[Shards](\ref clusters-shards-guilds)**: A shard manages part of the workload of your Discord application. -20. **[Shards](\ref clusters-shards-guilds)**: A shard manages part of the workload of your Discord application +* **Slash command**: The primary way a user interacts with a bot. It is a command sent to the bot with **parameters** (which may be optional) and is initiated by beginning a message with `/`. -21. **Snowflake**: An unsigned 64 bit integer (it can represent anything from 0 to 2^64-1) that is used by discord to identify basically everything, including but not limited to, **guilds**, users, messages, and much more. +* **Snowflake**: An unsigned 64 bit integer (it can represent anything from 0 to 2^64-1) that is used by Discord to identify basically everything, including but not limited to, **guilds**, users, messages, and much more. -22. **Subcommands**: A command which is derived from a different command, such as a bot that allows a person to get statistics for discord might have a `stats guild` command and a `stats global` command, both of which are **subcommands** of `stats`. +* **Subcommands**: A command which is derived from a different command, such as a bot that allows a person to get statistics for Discord might have a `stats guild` command and a `stats global` command, both of which are **subcommands** of `stats`. \ No newline at end of file diff --git a/docpages/03_installing.md b/docpages/03_installing.md index 2d1f439c41..559046847f 100644 --- a/docpages/03_installing.md +++ b/docpages/03_installing.md @@ -9,4 +9,4 @@ There are many ways to install D++, either from a package manager, or from sourc * \subpage install-windows-vs-zip * \subpage install-windows-clion-vcpkg * \subpage install-xmake -* \subpage install-from-source +* \subpage install-from-source \ No newline at end of file diff --git a/docpages/04_building_a_bot.md b/docpages/04_building_a_bot.md index 6cb0e13509..1d029f75aa 100644 --- a/docpages/04_building_a_bot.md +++ b/docpages/04_building_a_bot.md @@ -1,14 +1,13 @@ \page creating-a-discord-bot Creating a Discord Bot -If you are wanting to build a bot using C++, you're in the right place! The fast and easy tutorials below will guide you through how to build a bot using the D++ library on either a UNIX-like (e.g. Linux) system with CMake or with Windows using Visual Studio 2019. +If you are wanting to build a bot using C++, you're in the right place! The fast and easy tutorials below will guide you through how to build a bot using the D++ library on either a UNIX-like (e.g. Linux) system with CMake or with Windows using Visual Studio 2022. Click on a link below for a guide specifically for your system: -* \subpage creating-a-bot-application "Creating a Bot Token" -* \subpage build-a-discord-bot-windows-visual-studio "Building a discord bot in Windows using Visual Studio" -* \subpage build-a-discord-bot-windows-wsl "Building a discord bot in Windows using WSL (Windows Subsystem for Linux)" -* \subpage build-a-discord-bot-linux-clion "Building a discord bot in Linux using CLion" -* \subpage buildcmake "Building a Discord Bot using CMake/UNIX" -* \subpage buildmeson "Building a Discord Bot using Meson" -* \subpage building-a-cpp-discord-bot-in-repl "Creating a Discord bot in Repl.it" - +* \subpage creating-a-bot-application +* \subpage build-a-discord-bot-windows-visual-studio +* \subpage build-a-discord-bot-windows-wsl +* \subpage build-a-discord-bot-linux-clion +* \subpage buildcmake +* \subpage buildmeson +* \subpage building-a-cpp-discord-bot-in-repl \ No newline at end of file diff --git a/docpages/05_example_programs.md b/docpages/05_example_programs.md index 19a798271a..f8e7ac19be 100644 --- a/docpages/05_example_programs.md +++ b/docpages/05_example_programs.md @@ -7,4 +7,4 @@ There are example programs here for all skill levels demonstrating a great many * \subpage music-and-audio * \subpage misc -Is the example you are looking for missing from these sections? Pop over to our [discord server](https://discord.com/dpp) and let us know what you need... Or, even better, if you know how to do something and want to contribute an example of your own, just submit a PR! \ No newline at end of file +Is the example you are looking for missing from these sections? Pop over to our [Discord server](https://discord.com/dpp) and let us know what you need… Or, even better, if you know how to do something and want to contribute an example of your own, just submit a PR! \ No newline at end of file diff --git a/docpages/06_advanced_reference.md b/docpages/06_advanced_reference.md index 8292b7cbe0..42953aaeb5 100644 --- a/docpages/06_advanced_reference.md +++ b/docpages/06_advanced_reference.md @@ -1,13 +1,13 @@ \page advanced-reference Advanced Reference -* \subpage clusters-shards-guilds "Clusters, Shards and Guilds" -* \subpage thread-model "Thread Model" -* \subpage coding-standards "Coding Style Standards" -* \subpage unit-tests "Unit Tests" -* \subpage lambdas-and-locals "Ownership of local variables and safely transferring into a lambda" -* \subpage coroutines "Advanced commands with coroutines" -* \subpage governance "Project Governance" -* \subpage roadmap "Development Roadmap" -* \subpage security "Security" -* \subpage automating-with-jenkins "Automating your bot with Jenkins" -* \subpage separate-events "Separating events into new classes" \ No newline at end of file +* \subpage clusters-shards-guilds +* \subpage thread-model +* \subpage coding-standards +* \subpage unit-tests +* \subpage lambdas-and-locals +* \subpage coroutines +* \subpage governance +* \subpage roadmap +* \subpage security +* \subpage automating-with-jenkins +* \subpage separate-events \ No newline at end of file diff --git a/docpages/07_deprecated_list.md b/docpages/07_deprecated_list.md index 594b53edef..7ab8c8185b 100644 --- a/docpages/07_deprecated_list.md +++ b/docpages/07_deprecated_list.md @@ -1,9 +1,7 @@ \page deprecated Deprecated List -### Deprecation policy +# Deprecation Policy -We keep things marked as depreciated until next major API version. -If discord removes the function, we may remove the method from the library or replace it with a thrown exception depending on the type of function and at our discretion. -Such functions which are made to throw will then be removed at the next major API version. +We keep things marked as deprecated until the next major API version. If Discord removes the function, we may remove the method from the library or replace it with a thrown exception depending on the type of function and at our discretion. Such functions which are made to throw will then be removed at the next major API version. -
\ No newline at end of file +
\ No newline at end of file diff --git a/docpages/INDEX.md b/docpages/INDEX.md index 7d4e93f919..7ee4f3ca1c 100644 --- a/docpages/INDEX.md +++ b/docpages/INDEX.md @@ -2,7 +2,7 @@ ## What is D++ (DPP)? -D++ is a lightweight and simple library for Discord written in modern C++. It is designed to cover as much of the API specification as possible and to have a incredibly small memory footprint, even when caching large amounts of data. +D++ is a lightweight and simple library for Discord written in modern C++. It is designed to cover as much of the API specification as possible and to have an incredibly small memory footprint, even when caching large amounts of data. It is created by the developer of [TriviaBot](https://triviabot.co.uk) and contributed to by a dedicated team of developers. @@ -15,21 +15,21 @@ It is created by the developer of [TriviaBot](https://triviabot.co.uk) and contr The following downloads are for the most recent version: * [Source Code](https://github.com/brainboxdotcc/DPP) -* [x64 Linux .deb (64 bit Debian, Ubuntu etc)](https://dl.dpp.dev/latest) -* [x86 Linux .deb (32 bit Debian, Ubuntu etc)](https://dl.dpp.dev/latest/linux-i386) -* [x64 Linux .rpm (64 bit Redhat, CentOS etc)](https://dl.dpp.dev/latest/linux-x64/rpm) -* [x86 Linux .rpm (32 bit Redhat, CentOS etc)](https://dl.dpp.dev/latest/linux-i386/rpm) -* [x64 Windows (64 bit vs2019 release build)](https://dl.dpp.dev/latest/win64-release-vs2019) -* [x64 Windows (64 bit vs2022 release build)](https://dl.dpp.dev/latest/win64-release-vs2022) -* [x64 Windows (64 bit vs2019 debug build)](https://dl.dpp.dev/latest/win64-debug-vs2019) -* [x64 Windows (64 bit vs2022 debug build)](https://dl.dpp.dev/latest/win64-debug-vs2022) +* [x64 Linux .deb (64 bit Debian, Ubuntu etc.)](https://dl.dpp.dev/latest) +* [x86 Linux .deb (32 bit Debian, Ubuntu etc.)](https://dl.dpp.dev/latest/linux-i386) +* [x64 Linux .rpm (64 bit RedHat, CentOS etc.)](https://dl.dpp.dev/latest/linux-x64/rpm) +* [x86 Linux .rpm (32 bit RedHat, CentOS etc.)](https://dl.dpp.dev/latest/linux-i386/rpm) +* [x64 Windows (64 bit VS2019 release build)](https://dl.dpp.dev/latest/win64-release-vs2019) +* [x64 Windows (64 bit VS2022 release build)](https://dl.dpp.dev/latest/win64-release-vs2022) +* [x64 Windows (64 bit VS2019 debug build)](https://dl.dpp.dev/latest/win64-debug-vs2019) +* [x64 Windows (64 bit VS2022 debug build)](https://dl.dpp.dev/latest/win64-debug-vs2022) * [ARM6 Linux .deb (32 bit Raspberry Pi 1, 2)](https://dl.dpp.dev/latest/linux-rpi-arm6) * [ARM7 Linux .deb (32 bit Raspberry Pi 3, 4)](https://dl.dpp.dev/latest/linux-rpi-arm7hf) * [ARM64 Linux .deb (64 bit Raspberry Pi 4, Smartphones)](https://dl.dpp.dev/latest/linux-rpi-arm64) -You can find further releases in other architectures and formats or the source code on the [GitHub Repository](https://github.com/brainboxdotcc/DPP/releases). For a realtime JSON format list of all download links, click [here](https://dl.dpp.dev/json) +You can find further releases in other architectures and formats or the source code on the [GitHub Repository](https://github.com/brainboxdotcc/DPP/releases). For a realtime JSON format list of all download links, click [here](https://dl.dpp.dev/json). -## Library features +## Library Features * Support for Discord API v10 * Really small memory footprint @@ -46,33 +46,40 @@ You can find further releases in other architectures and formats or the source c ## Supported Operating Systems ### Linux + The library runs ideally on **Linux**. -### Mac OS X and FreeBSD -The library is well-functional and stable on **Mac OS X** and **FreeBSD** too. +### macOS and FreeBSD + +The library is well-functional and stable on **macOS** and **FreeBSD** too. ### Raspberry Pi + For running your bot on a **Raspberry Pi**, we offer a prebuilt .deb package for ARM64, ARM6, and ARM7 so that you do not have to wait for it to compile. ### Windows + **Windows** is well-supported with ready-made compiled DLL and LIB files, please check out our [Windows Bot Template repository](https://github.com/brainboxdotcc/windows-bot-template). The Windows Bot repository can be cloned and integrated immediately into any Visual Studio 2019 and 2022 project in a matter of minutes. ### Other OS + The library should work fine on other operating systems as well, and if you run a D++ bot on something not listed here, please let us know! ## Getting started + * [GitHub Repository](https://github.com/brainboxdotcc/DPP) * [Discord Server](https://discord.gg/dpp) * \ref frequently-asked-questions "Frequently Asked Questions" * \ref installing "Installing D++" * \ref example-programs "Example Programs" -* \ref glossary-of-common-discord-terms "Commonly used terms" +* \ref glossary-of-common-discord-terms "Commonly Used Terms" ## Architecture + * \ref clusters-shards-guilds * \ref thread-model ## Learning Resources -* [C++ for JavaScript Developers](https://pawelgrzybek.com/cpp-for-javascript-developers/) -* [C++ In Four Hours](https://www.youtube.com/watch?v=vLnPwxZdW4Y&vl=en) +* [C++ for JavaScript Developers](https://pawelgrzybek.com/cpp-for-javascript-developers/) +* [C++ in Four Hours](https://www.youtube.com/watch?v=vLnPwxZdW4Y&vl=en) \ No newline at end of file diff --git a/docpages/advanced_reference/automating-with-jenkins.md b/docpages/advanced_reference/automating-with-jenkins.md index cb9ccfc718..140c66fba0 100644 --- a/docpages/advanced_reference/automating-with-jenkins.md +++ b/docpages/advanced_reference/automating-with-jenkins.md @@ -1,27 +1,26 @@ -\page automating-with-jenkins Automating your bot with Jenkins +\page automating-with-jenkins Automating Your Bot with Jenkins \note This page does NOT go into explaining how to install Jenkins, nor how to initially setup Jenkins. This is a tutorial for the CMake version with Linux (more specifically Ubuntu 22.04 LTS). If you don't know how to use CMake or you don't use CMake for your bot (and would like to) then please visit \ref buildcmake. If you wish to automate this tutorial from GitHub pushes then you can simply download the GitHub plugin for Jenkins, set that up and this tutorial will still work as this tutorial will only build what it can see! -### Getting started +## Getting Started -First of all, you'll want to create your project. For this, we'll use a "Freestyle project" as we're just going to be calling some bash commands to tell CMake to build. We'll be calling this "DiscordBot" but you can name it whatever you want (I would advise against non-ascii characters). +First of all, you'll want to create your project. For this, we'll use a "Freestyle project" as we're just going to be calling some bash commands to tell CMake to build. We'll be calling this "DiscordBot" but you can name it whatever you want. (I would advise against non-ASCII characters.) \image html jenkinsproject.png -From here, just hit `Ok` and now you've created your Jenkins project, Well done! From here you can add a description, change the security policy (if your jenkins is public), really whatever your heart desires. +From here, just hit `Ok` and now you've created your Jenkins project. Well done! From here you can add a description, change the security policy (if your Jenkins is public), really whatever your heart desires. -### Automating the building process. +## Automating the Building Process -Scrolling down, you'll find `Build Steps` (You can also click `Build Steps` on the left). Here, you'll want to hit `Add build step` and hit `Execute shell`. +Scrolling down, you'll find `Build Steps`. (You can also click `Build Steps` on the left.) Here, you'll want to hit `Add build step` and hit `Execute shell`. \image html buildstepjenkins.png Inside of this, you'll want to enter this script below. -~~~~~~~~~~ -# Check if the "build" directory doesn't exist (if you've not setup CMake or deleted its content). -if [ ! -d "build/" ] -then # As it doesn't, create the build directory. +~~~~~~~~~~bash +# Check if the "build" directory doesn't exist (if you've not set up CMake or deleted its content). +if [ ! -d "build/" ]; then # As it doesn't, create the build directory. mkdir build cd build cmake .. # Begin the CMake initialisation. @@ -34,30 +33,30 @@ cmake --build build/ \note This script does not make use of multiple threads. If you know how to do this and you would like to use threads, then feel free to. However, I would be careful not to use all your threads as Jenkins may dislike this. -This script will build your project for you and also setup CMake if you've deleted the build directory, allowing you to easily refresh CMake. You can change this to a build parameter if you want, meaning you can hit `Build with Parameters` and state what you'd like to do (This would require the script to be changed so only do that if you know what you're doing)! +This script will build your project for you and also set up CMake if you've deleted the build directory, allowing you to easily refresh CMake. You can change this to a build parameter if you want, meaning you can hit `Build with Parameters` and state what you'd like to do. (This would require the script to be changed so only do that if you know what you're doing!) \image html shelljenkins.png Now you can hit save! -### Seeing the builds work +## Seeing the Builds Work Making sure you have your project files in the workspace directory (you can see this by pressing `Workspace` on the left, the files will automatically be pulled from GitHub if you're using the GitHub plugin), you should be able to hit `Build Now` and see a new build in the History appear. If everything went well, you should have a green tick! -\note Building can take a whilst if you haven't setup your build directory before (doing `cmake ..`), especially on less-powerful machines, so don't be alarmed! +\note Building can take a while if you haven't set up your build directory before (doing `cmake ..`), especially on less-powerful machines, so don't be alarmed! \image html buildhistoryjenkins.png -### Running the build +## Running the Build -Running the builds is the same as any other time, but we'll still cover it! However, we won't cover running it in background and whatnot, that part is completely down to you. +Running the builds is the same as any other time, but we'll still cover it! However, we won't cover running it in the background and whatnot, that part is completely down to you. -First, you need to get into the jenkins user. If you're like me and don't have the Jenkins user password, you can login with your normal login (that has sudo perms) and do `sudo su - jenkins`. Once logged in, you'll be in `/var/lib/jenkins/`. From here, you'll want to do `cd workspace/DiscordBot/` (make sure to replace "DiscordBot" with your bot's name. Remember, you can tab-complete this) and then `cd build`. Now, you can simply do `./DiscordBot`! +First, you need to get into the Jenkins user. If you're like me and don't have the Jenkins user password, you can login with your normal login (that has sudo perms) and do `sudo su - jenkins`. Once logged in, you'll be in `/var/lib/jenkins/`. From here, you'll want to do `cd workspace/DiscordBot/` (make sure to replace "DiscordBot" with your bot's name. Remember, you can tab-complete this) and then `cd build`. Now, you can simply do `./DiscordBot`! -\warning If you are going to be running the bot at the same time as builds, I would heavily advise that you copy the bot (if it's not statically linked, then copy the entire build directory) to a different location. This is so you can pick and choose when the bot gets updated (and even means you can run experimental builds as opposed to stable builds) but also means you avoid any risk of the bot crashing during build (as jenkins will be overwriting your executable and libraries). +\warning If you are going to be running the bot at the same time as builds, I would heavily advise that you copy the bot (if it's not statically linked, then copy the entire build directory) to a different location. This is so you can pick and choose when the bot gets updated (and even means you can run experimental builds as opposed to stable builds) but also means you avoid any risk of the bot crashing during build (as Jenkins will be overwriting your executable and libraries). Once you're happy with everything, then you're good to go! Enjoy your automated builds! -### Possible permission issues +## Possible Permission Issues Sometimes, doing `./DiscordBot` can end up with an error, saying you don't have permission to execute. If that's the case, simply do `chmod +x DiscordBot` and now you can re-run `./DiscordBot`. \ No newline at end of file diff --git a/docpages/advanced_reference/clusters_shards_and_guilds.md b/docpages/advanced_reference/clusters_shards_and_guilds.md index 13dadc5747..ee7087e9c9 100644 --- a/docpages/advanced_reference/clusters_shards_and_guilds.md +++ b/docpages/advanced_reference/clusters_shards_and_guilds.md @@ -1,87 +1,87 @@ -\page clusters-shards-guilds Clusters, Shards and Guilds +\page clusters-shards-guilds Clusters, Shards, and Guilds -D++ takes a three-tiered highly scalable approach to bots, with three levels known as Clusters, Shards and Guilds as documented below. +D++ takes a three-tiered highly scalable approach to bots, with three levels known as Clusters, Shards, and Guilds as documented below. \dot digraph "Clusters, Shards and Guilds" { - node [colorscheme="blues9",fontname="helvetica"]; - subgraph Bot { - node [style=filled, color=1]; - label = "Bot" - "Bot" [shape=folder, label="Bot", bordercolor=black]; - }; - subgraph Processes { - node [style=filled, color=2]; - label = "Processes" - "Bot" -> "Process 1" - "Bot" -> "Process 2" - "Process 1" [shape=record, label="Process"]; - "Process 2" [shape=record, label="Process"]; - }; - subgraph Clusters { - node [style=filled, color=3]; - label = "Clusters" - "Process 1" -> "Cluster 1" - "Process 2" -> "Cluster 2" - "Cluster 1" [shape=record, label="Cluster"]; - "Cluster 2" [shape=record, label="Cluster"]; - }; - subgraph Shards { - node [style=filled, color=4]; - label = "Shards" - "Shard 1" [shape=record, label="Shard"]; - "Shard 2" [shape=record, label="Shard"]; - "Shard 3" [shape=record, label="Shard"]; - "Shard 4" [shape=record, label="Shard"]; - "Shard 5" [shape=record, label="Shard"]; - "Shard 6" [shape=record, label="Shard"]; - "Shard 7" [shape=record, label="Shard"]; - "Shard 8" [shape=record, label="Shard"]; - "Cluster 1" -> "Shard 1" - "Cluster 1" -> "Shard 3" - "Cluster 2" -> "Shard 2" - "Cluster 2" -> "Shard 4" - "Cluster 1" -> "Shard 5" - "Cluster 1" -> "Shard 7" - "Cluster 2" -> "Shard 6" - "Cluster 2" -> "Shard 8" - }; - subgraph Guilds { - node [style=filled, color=5]; - label = "Guilds"; - "Guild 1" [shape=record, label="Guild"]; - "Guild 2" [shape=record, label="Guild"]; - "Guild 3" [shape=record, label="Guild"]; - "Guild 4" [shape=record, label="Guild"]; - "Guild 5" [shape=record, label="Guild"]; - "Guild 6" [shape=record, label="Guild"]; - "Guild 7" [shape=record, label="Guild"]; - "Guild 8" [shape=record, label="Guild"]; - "Guild 9" [shape=record, label="Guild"]; - "Guild 10" [shape=record, label="Guild"]; - "Guild 11" [shape=record, label="Guild"]; - "Guild 12" [shape=record, label="Guild"]; - "Guild 13" [shape=record, label="Guild"]; - "Guild 14" [shape=record, label="Guild"]; - "Guild 15" [shape=record, label="Guild"]; - "Guild 16" [shape=record, label="Guild"]; - "Shard 1" -> "Guild 1" - "Shard 1" -> "Guild 5" - "Shard 2" -> "Guild 2" - "Shard 2" -> "Guild 6" - "Shard 3" -> "Guild 3" - "Shard 3" -> "Guild 7" - "Shard 4" -> "Guild 4" - "Shard 4" -> "Guild 8" - "Shard 5" -> "Guild 9" - "Shard 5" -> "Guild 11" - "Shard 6" -> "Guild 10" - "Shard 6" -> "Guild 12" - "Shard 7" -> "Guild 13" - "Shard 7" -> "Guild 15" - "Shard 8" -> "Guild 14" - "Shard 8" -> "Guild 16" - }; + node [colorscheme="blues9",fontname="helvetica"]; + subgraph Bot { + node [style=filled, color=1]; + label = "Bot" + "Bot" [shape=folder, label="Bot", bordercolor=black]; + }; + subgraph Processes { + node [style=filled, color=2]; + label = "Processes" + "Bot" -> "Process 1" + "Bot" -> "Process 2" + "Process 1" [shape=record, label="Process"]; + "Process 2" [shape=record, label="Process"]; + }; + subgraph Clusters { + node [style=filled, color=3]; + label = "Clusters" + "Process 1" -> "Cluster 1" + "Process 2" -> "Cluster 2" + "Cluster 1" [shape=record, label="Cluster"]; + "Cluster 2" [shape=record, label="Cluster"]; + }; + subgraph Shards { + node [style=filled, color=4]; + label = "Shards" + "Shard 1" [shape=record, label="Shard"]; + "Shard 2" [shape=record, label="Shard"]; + "Shard 3" [shape=record, label="Shard"]; + "Shard 4" [shape=record, label="Shard"]; + "Shard 5" [shape=record, label="Shard"]; + "Shard 6" [shape=record, label="Shard"]; + "Shard 7" [shape=record, label="Shard"]; + "Shard 8" [shape=record, label="Shard"]; + "Cluster 1" -> "Shard 1" + "Cluster 1" -> "Shard 3" + "Cluster 2" -> "Shard 2" + "Cluster 2" -> "Shard 4" + "Cluster 1" -> "Shard 5" + "Cluster 1" -> "Shard 7" + "Cluster 2" -> "Shard 6" + "Cluster 2" -> "Shard 8" + }; + subgraph Guilds { + node [style=filled, color=5]; + label = "Guilds"; + "Guild 1" [shape=record, label="Guild"]; + "Guild 2" [shape=record, label="Guild"]; + "Guild 3" [shape=record, label="Guild"]; + "Guild 4" [shape=record, label="Guild"]; + "Guild 5" [shape=record, label="Guild"]; + "Guild 6" [shape=record, label="Guild"]; + "Guild 7" [shape=record, label="Guild"]; + "Guild 8" [shape=record, label="Guild"]; + "Guild 9" [shape=record, label="Guild"]; + "Guild 10" [shape=record, label="Guild"]; + "Guild 11" [shape=record, label="Guild"]; + "Guild 12" [shape=record, label="Guild"]; + "Guild 13" [shape=record, label="Guild"]; + "Guild 14" [shape=record, label="Guild"]; + "Guild 15" [shape=record, label="Guild"]; + "Guild 16" [shape=record, label="Guild"]; + "Shard 1" -> "Guild 1" + "Shard 1" -> "Guild 5" + "Shard 2" -> "Guild 2" + "Shard 2" -> "Guild 6" + "Shard 3" -> "Guild 3" + "Shard 3" -> "Guild 7" + "Shard 4" -> "Guild 4" + "Shard 4" -> "Guild 8" + "Shard 5" -> "Guild 9" + "Shard 5" -> "Guild 11" + "Shard 6" -> "Guild 10" + "Shard 6" -> "Guild 12" + "Shard 7" -> "Guild 13" + "Shard 7" -> "Guild 15" + "Shard 8" -> "Guild 14" + "Shard 8" -> "Guild 16" + }; } \enddot @@ -92,8 +92,7 @@ A bot may be made of one or more clusters. Each cluster maintains a queue of com ```cpp #include -int main() -{ +int main() { /* This is a cluster */ dpp::cluster bot("Token goes here"); } @@ -108,8 +107,7 @@ Small bots will require only one shard and this is the default when you instanti ```cpp #include -int main() -{ +int main() { /* This is a cluster */ int total_shards = 10; dpp::cluster bot("Token goes here", dpp::i_default_intents, total_shards); @@ -118,7 +116,7 @@ int main() Remember that if there are multiple clusters, the number of shards you request will be split equally across these clusters! -@note To spawn multiple clusters, you can specify this as the 4th and 5th parameter of the dpp::cluster constructor. You must do this, if you want this functionality. The library will not create additional clusters for you, as what you require is dependent upon your system specifications. It is your responsibility to somehow get the cluster id and total clusters into the process, e.g. via a command line argument. An example of this is shown below based on the cluster setup code of **TriviaBot**: +\note To spawn multiple clusters, you can specify this as the 4th and 5th parameter of the dpp::cluster constructor. You must do this, if you want this functionality. The library will not create additional clusters for you, as what you require is dependent upon your system specifications. It is your responsibility to somehow get the cluster id and total clusters into the process, e.g. via a command line argument. An example of this is shown below based on the cluster setup code of **TriviaBot**: ```cpp #include #include @@ -126,8 +124,7 @@ Remember that if there are multiple clusters, the number of shards you request w #include #include -int main(int argc, char** argv) -{ +int main(int argc, char** argv) { int total_shards = 64; int index; char arg; @@ -136,8 +133,7 @@ int main(int argc, char** argv) uint32_t maxclusters = 1; /* Parse command line parameters using getopt() */ - struct option longopts[] = - { + struct option longopts[] { { "clusterid", required_argument, NULL, 'c' }, { "maxclusters", required_argument, NULL, 'm' }, { 0, 0, 0, 0 } @@ -148,14 +144,14 @@ int main(int argc, char** argv) case 'c': clusterid = std::stoul(optarg); clusters_defined = true; - break; + break; case 'm': maxclusters = std::stoul(optarg); - break; + break; default: std::cerr << "Unknown parameter '" << argv[optind - 1] << "'\n"; exit(1); - break; + break; } } @@ -170,9 +166,8 @@ int main(int argc, char** argv) ### Large Bot Sharding -Discord restricts how many shards you can connect to at any one time to one per five seconds, unless your bot is in at least 150,000 guilds. Once you reach 150,000 guilds, Discord allow your bot to connect to more guilds concurrently, and your number of shards must divide cleanly into this value. By default, at 150,000 guilds this concurrency value is 16 meaning D++ will attempt to connect 16 shards in parallel, then wait for all these to connect and then connect another 16, until all shards are connected. In practice, this means a large bot with many shards (read: hundreds!) will connect significantly faster after a full restart. **You do not need to manually configure large bot sharding and connection concurrency, the D++ library will handle this for you if you are able to use it**. - +Discord restricts how many shards you can connect to at any one time to one per five seconds, unless your bot is in at least 150,000 guilds. Once you reach 150,000 guilds, Discord allows your bot to connect to more guilds concurrently, and your number of shards must divide cleanly into this value. By default, at 150,000 guilds this concurrency value is 16 meaning D++ will attempt to connect 16 shards in parallel, then wait for all these to connect and then connect another 16, until all shards are connected. In practice, this means a large bot with many shards (read: hundreds!) will connect significantly faster after a full restart. **You do not need to manually configure large bot sharding and connection concurrency, the D++ library will handle this for you if you are able to use it**. ## Guilds -Guilds are what servers are known as to the Discord API. There can be up to **2500** of these per shard. Once you reach 2500 guilds on your bot, Discord force your bot to shard, the D++ library will automatically create additional shards to accommodate if not explicitly configured with a larger number. Discord *does not restrict sharding* to bots on 2500 guilds or above. You can shard at any size of bot, although it would be a waste of resources to do so unless it is required. +Guilds are what servers are known as to the Discord API. There can be up to **2500** of these per shard. Once you reach 2500 guilds on your bot, Discord forces your bot to shard, the D++ library will automatically create additional shards to accommodate if not explicitly configured with a larger number. Discord *does not restrict sharding* to bots on 2500 guilds or above. You can shard at any size of bot, although it would be a waste of resources to do so unless it is required. \ No newline at end of file diff --git a/docpages/advanced_reference/coding_style_standards.md b/docpages/advanced_reference/coding_style_standards.md index f74ad16c99..7cce6af14a 100644 --- a/docpages/advanced_reference/coding_style_standards.md +++ b/docpages/advanced_reference/coding_style_standards.md @@ -1,29 +1,32 @@ \page coding-standards Coding Style Standards -This page lists the coding style we stick to when maintaining the D++ library. If you are submitting a pull request or other code contribution to the library, you should stick to the styles listed below. If something is not covered here, ask on the [official discord server](https://discord.gg/dpp)! +This page lists the coding style we stick to when maintaining the D++ library. If you are submitting a pull request or other code contribution to the library, you should stick to the styles listed below. If something is not covered here, ask on the [official Discord server](https://discord.gg/dpp)! + +## Class Names, Function Names, and Method Names -## Class names, function names and method names All class, variable/member, function and method names should use `snake_case`, similar to the style of the C++ standard library. ## Enums -Enums and their values should be `snake_case` as with class, function and method names. You do not need to use `enum class`, so make sure that enum values are prefixed with a prefix to make them unique and grouped within the IDE, e.g. `ll_debug`, `ll_trace` etc. +Enums and their values should be `snake_case` as with class, function and method names. You do not need to use `enum class`, so make sure that enum values are prefixed with a prefix to make them unique and grouped within the IDE, e.g. `ll_debug`, `ll_trace`, etc. + +## Curly Braces, Brackets, etc. -## Curly Braces, Brackets etc -This covers your standard Curly Braces (commonly known as squiggly brackets), and Lists. +This covers your standard Curly Braces (commonly known as squiggly brackets), and lists. ### Curly Braces + Curly Braces should be on the same line as the keyword, for example: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp void foo() { - if (a == b) { - c(); - } + if (a == b) { + c(); + } - while(true) { - // ... - } + while (true) { + // … + } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -33,28 +36,33 @@ This applies to functions, `while` statements, `if` statements, lambdas, nearly 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} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp std::vector clowns = { "pennywise", "bobo" }; evaluate_clown(clowns[0], evilness(2.5, factor)); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## Indentation + Indentation should always be tab characters. It is up to you how wide you set tab characters in your editor for your personal tastes. All code blocks delimited within curly braces should be indented neatly and uniformly. -## Constants and \#define macros +## Constants and \#define Macros + Constants and macros should be all `UPPERCASE` with `SNAKE_CASE` to separate words. Macros should not have any unexpected side effects. ## Comments + All comments should be in `doxygen` format (similar to javadoc). Please see existing class definitions for an example. You should use doxygen style comments in a class definition inside a header file, and can use any other comment types within the .cpp file. Be liberal with comments, especially if your code makes any assumptions! -## Spell checks +## Spell Checks + To prevent typos, a GitHub-Action checks the documentation. If it fails for a word that was falsely flagged, you can add them to `.cspell.json`. -## Symbol exporting +## Symbol Exporting + If you export a class which is to be accessible to users, be sure to prefix it with the `DPP_EXPORT` macro, for example: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp class DPP_EXPORT my_new_class { public: int hats; @@ -64,38 +72,47 @@ public: The `DPP_EXPORT` macro ensures that on certain platforms (notably Windows) the symbol is exported to be available to the library user. -## Public vs private vs protected +## Public vs Private vs Protected + It is a design philosophy of D++ that everything possible in a class should be public, unless the user really does not need it (you should consider justifying in comments why) or user adjustment of the variable could badly break the functioning of the library. Avoid the use of accessors for setting/getting values in a class, except for bit fields, where you should provide accessors for setting and getting individual bits (for example, see `user.h`), or in the event you want to provide a "fluent" interface. The exception to this is where you want to provide a logic validation of a field, for example if you have a string field with a minimum and maximum length, you can provide a setter the user can *optionally use* which will validate their input. ## Exceptions -All exceptions thrown should derive from dpp::exception (see dpp/exception.h) - when validating string lengths, a string which is too long should be truncated using dpp::utility::utf8substr and any strings that are too short should throw a dpp::length_exception. + +All exceptions thrown should derive from dpp::exception (see `dpp/exception.h`) - when validating string lengths, a string which is too long should be truncated using dpp::utility::utf8substr and any strings that are too short should throw a dpp::length_exception. ## Inheritance + Keep levels of inheritance low. If you need to inherit more than 3 levels deep, it is probable that the design could be simplified. Remember that at scale, there can be tens of millions of certain classes and each level of virtual nesting adds to the `vtable` of that object's instance in RAM. -## Bit field packing -Where discord provides boolean flags, if the user is expected to store many of the object in RAM, or in cache, you should pack all these booleans into bit fields (see `user.h` and `channel.h` for examples). In the event that the object is transient, such as an interaction or a message, packing the data into bit fields is counter intuitive. Remember that you should provide specific accessors for bit field values! +## Bit Field Packing + +Where Discord provides boolean flags, if the user is expected to store many of the objects in RAM, or in cache, you should pack all these booleans into bit fields (see `user.h` and `channel.h` for examples). In the event that the object is transient, such as an interaction or a message, packing the data into bit fields is counter intuitive. Remember that you should provide specific accessors for bit field values! + +## Keep Dependencies Internal! -## Keep dependencies internal! Where you are making use of an external dependency such as `opus` or `libssl`, do not place references to the types/structs, or the header files of these external libraries within the header files of D++. Doing so adds that library as a public dependency to the project (which is bad!). Instead make an opaque class, and/or forward-declare the structs (for examples see `sslclient.h` and `discordvoiceclient.h`). -## API type names -Where discord provide a name in PascalCase we should stick as closely to that name as possible but convert it to `snake_case`. For example, GuildMember would become `guild_member`. +## API Type Names + +Where Discord provides a name in PascalCase we should stick as closely to that name as possible but convert it to `snake_case`. For example, GuildMember would become `guild_member`. -## Don't introduce any platform-specific code -Do not introduce platform specific (e.g. windows only) code or libc functions. If you really must use these functions safely wrap them e.g. in `#ifdef _WIN32` and provide a cross-platform alternative so that it works for everyone. +## Don't Introduce Any Platform-Specific Code -## C++ version +Do not introduce platform specific (e.g. Windows only) code or libc functions. If you really must use these functions safely wrap them e.g. in `#ifdef _WIN32` and provide a cross-platform alternative so that it works for everyone. + +## C++ Version The code must work with the C++17 standard. -## Select the right size type for numeric types -If a value will only hold values up to 255, use `uint8_t`. If a value cannot hold over 65536, use `uint16_t`. These types can help use a lot less ram at scale. +## Select the Right Size Type for Numeric Types + +If a value will only hold values up to 255, use `uint8_t`. If a value cannot hold over 65536, use `uint16_t`. These types can help use a lot less RAM at scale. -## Fluent design -Where possible, if you are adding methods to a class you should consider fluent design. Fluent design is the use of class methods tha return a reference to self (via `return *this`), so that you can chain object method calls together (in the way `dpp::message` and `dpp::embed` do). For example: +## Fluent Design -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +Where possible, if you are adding methods to a class you should consider fluent design. Fluent design is the use of class methods that return a reference to self (via `return *this`), so that you can chain object method calls together (in the way dpp::message and dpp::embed do). For example: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp class DPP_EXPORT my_new_class { public: int hats; @@ -114,27 +131,26 @@ my_new_class& my_new_class::set_clowns(int new_clowns) { clowns = new_clowns; return *this; } - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This would allow the user to do this: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp dpp::my_new_class nc; nc.set_hats(3).set_clowns(9001); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -## Keep all D++ related types in the dpp namespace +## Keep All D++ Related Types in the dpp Namespace -All types for the library should be within the `dpp` namespace. There are a couple of additional namespaces, e.g. `dpp::utility` for static standalone helper functions and helper classes, and `dpp::events` for internal websocket event handlers. +All types for the library should be within the `dpp` namespace. There are a couple of additional namespaces, e.g. dpp::utility for static standalone helper functions and helper classes, and dpp::events for internal websocket event handlers. -## Commit messages and Git +## Commit Messages and Git All pull requests ("PRs") should be submitted against the `dev` branch in GitHub. -### Naming conventions +### Naming Conventions -It’s good to have descriptive commit messages, or PR titles so that other contributors can understand about your commit or the PR Created. Commits must be prefixed with a type, which consists of a noun, `feat`, `fix`, etc., followed by a colon and a space. Other commit types can be `breaking`, `docs`, `refactor`, `deprecate`, `perf`, `test`, `chore` and `misc`. Read [conventional commits](https://www.conventionalcommits.org/en/v1.0.0-beta.3/) for more information on how we like to format commit messages. +It’s good to have descriptive commit messages, or PR titles so that other contributors can understand about your commit or the PR Created. Commits must be prefixed with a type, which consists of a noun, `feat`, `fix`, etc., followed by a colon and a space. Other commit types can be `breaking`, `docs`, `refactor`, `deprecate`, `perf`, `test`, `chore`, and `misc`. Read [conventional commits](https://www.conventionalcommits.org/en/v1.0.0-beta.3/) for more information on how we like to format commit messages. ### GitHub Actions diff --git a/docpages/advanced_reference/coroutines.md b/docpages/advanced_reference/coroutines.md index b8fd5070ed..393bf6935c 100644 --- a/docpages/advanced_reference/coroutines.md +++ b/docpages/advanced_reference/coroutines.md @@ -1,225 +1,227 @@ -\page coroutines Advanced commands with coroutines - -\warning D++ Coroutines are a very new feature and are currently only supported by D++ on g++ 11, clang/LLVM 14, and MSVC 19.37 or above. Additionally, D++ must be built with the CMake option DPP_CORO, and your program must both define the macro DPP_CORO and use C++20 or above. The feature is experimental and may have bugs or even crashes, please report any to [GitHub Issues](https://github.com/brainboxdotcc/DPP/issues) or to our [Discord Server](https://discord.gg/dpp). - -### What is a coroutine? - -Introduced in C++20, coroutines are the solution to the impracticality of callbacks. In short, a coroutine is a function that can be paused and resumed later. They are an extremely powerful alternative to callbacks for asynchronous APIs in particular, as the function can be paused when waiting for an API response, and resumed when it is received. - -Let's revisit \ref attach-file "attaching a downloaded file", but this time with a coroutine: - - -~~~~~~~~~~~~~~~{.cpp} -#include - -int main() { - dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); - - bot.on_log(dpp::utility::cout_logger()); - - /* Message handler to look for a command called !file */ - /* Make note of passing the event by value, this is important (explained below) */ - bot.on_message_create([](dpp::message_create_t event) -> dpp::job { - dpp::cluster *cluster = event.from->creator; - - if (event.msg.content == "!file") { - // request an image and co_await the response - dpp::http_request_completion_t result = co_await cluster->co_request("https://dpp.dev/DPP-Logo.png", dpp::m_get); - - // create a message - dpp::message msg(event.msg.channel_id, "This is my new attachment:"); - - // attach the image on success - if (result.status == 200) { - msg.add_file("logo.png", result.body); - } - - // send the message - cluster->message_create(msg); - } - }); - - bot.start(dpp::st_wait); - return 0; -} -~~~~~~~~~~~~~~~ - - -Coroutines can make commands simpler by eliminating callbacks, which can be very handy in the case of complex commands that rely on a lot of different data or steps. - -In order to be a coroutine, a function has to return a special type with special functions; D++ offers dpp::job, dpp::task, and dpp::coroutine, which are designed to work seamlessly with asynchronous calls through dpp::async, which all the functions starting with `co_` such as dpp::cluster::co_message_create return. Event routers can have a dpp::job attached to them, as this object allows to create coroutines that can execute on their own, asynchronously. More on that and the difference between it and the other two types later. To turn a function into a coroutine, simply make it return dpp::job as seen in the example at line 10, then use `co_await` on awaitable types or `co_return`. The moment the execution encounters one of these two keywords, the function is transformed into a coroutine. Coroutines that use dpp::job can be used for event handlers, they can be attached to an event router just the same way as regular event handlers. - -When using a `co_*` function such as `co_message_create`, the request is sent immediately and the returned dpp::async can be `co_await`-ed, at which point the coroutine suspends (pauses) and returns back to its caller; in other words, the program is free to go and do other things while the data is being retrieved and D++ will resume your coroutine when it has the data you need, which will be returned from the `co_await` expression. - -\attention You may hear that coroutines are "writing async code as if it was sync", while this is sort of correct, it may limit your understanding and especially the dangers of coroutines. I find **they are best thought of as a shortcut for a state machine**, if you've ever written one, you know what this means. Think of the lambda as *its constructor*, in which captures are variable parameters. Think of the parameters passed to your lambda as data members in your state machine. When you `co_await` something, the state machine's function exits, the program goes back to the caller, at this point the calling function may return. References are kept as references in the state machine, which means by the time the state machine is resumed, the reference may be dangling : \ref lambdas-and-locals "this is not good"! As a rule of thumb when making coroutines, **always prefer taking parameters by value and avoid lambda capture**. Another way to think of them is just like callbacks but keeping the current scope intact. In fact this is exactly what it is, the co_* functions call the normal API calls, with a callback that resumes the coroutine, *in the callback thread*. This means you cannot rely on thread_local variables and need to keep in mind concurrency issues with global states, as your coroutine will be resumed in another thread than the one it started on. - -### Several steps in one - -\note The next example assumes you are already familiar with how to use \ref firstbot "slash commands", \ref slashcommands "parameters", and \ref discord-application-command-file-upload "sending files through a command". - -Here is another example of what is made easier with coroutines, an "addemoji" command taking a file and a name as a parameter. This means downloading the emoji, submitting it to Discord, and finally replying, with some error handling along the way. Normally we would have to use callbacks and some sort of object keeping track of our state, but with coroutines, it becomes much simpler: - -~~~~~~~~~~{.cpp} -#include - -int main() { - dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); - - bot.on_log(dpp::utility::cout_logger()); - - bot.on_slashcommand([](dpp::slashcommand_t event) -> dpp::job { - if (event.command.get_command_name() == "addemoji") { - dpp::cluster *cluster = event.from->creator; - // Retrieve parameter values - dpp::snowflake file_id = std::get(event.get_parameter("file")); - std::string emoji_name = std::get(event.get_parameter("name")); - - // Get the attachment from the resolved list - const dpp::attachment &attachment = event.command.get_resolved_attachment(file_id); - - // For simplicity for this example we only support PNG - if (attachment.content_type != "image/png") { - // While event.co_reply is available, we can just use event.reply, as we will exit the command anyway and don't need to wait on the result - event.reply("Error: type " + attachment.content_type + " not supported"); - co_return; - } - // Send a " is thinking..." message, to wait on later so we can edit - dpp::async thinking = event.co_thinking(false); - - // Download and co_await the result - dpp::http_request_completion_t response = co_await cluster->co_request(attachment.url, dpp::m_get); - - if (response.status != 200) { // Page didn't send the image - co_await thinking; // Wait for the thinking response to arrive so we can edit - event.edit_response("Error: could not download the attachment"); - } - else { - // Load the image data in a dpp::emoji - dpp::emoji emoji(emoji_name); - emoji.load_image(response.body, dpp::image_type::i_png); - - // Create the emoji and co_await the response - dpp::confirmation_callback_t confirmation = co_await cluster->co_guild_emoji_create(event.command.guild_id, emoji); - - co_await thinking; // Wait for the thinking response to arrive so we can edit - if (confirmation.is_error()) - event.edit_response("Error: could not add emoji: " + confirmation.get_error().message); - else // Success - event.edit_response("Successfully added " + confirmation.get().get_mention()); // Show the new emoji - } - } - }); - - bot.on_ready([&bot](const dpp::ready_t & event) { - if (dpp::run_once()) { - dpp::slashcommand command("addemoji", "Add an emoji", bot.me.id); - - // Add file and name as required parameters - command.add_option(dpp::command_option(dpp::co_attachment, "file", "Select an image", true)); - command.add_option(dpp::command_option(dpp::co_string, "name", "Name of the emoji to add", true)); - - bot.global_command_create(command); - } - }); - - bot.start(dpp::st_wait); -} -~~~~~~~~~~ - -### I heard you liked tasks - -\note This next example is fairly advanced and makes use of many of both C++ and D++'s advanced features. - -Earlier we mentioned two other types of coroutines provided by dpp: dpp::coroutine and dpp::task. They both take their return type as a template parameter, which may be void. Both dpp::job and dpp::task start on the constructor for asynchronous execution, however only the latter can be `co_await`-ed, this allows you to retrieve its return value. If a dpp::task is destroyed before it ends, it is cancelled and will stop when it is resumed from the next `co_await`. dpp::coroutine also has a return value and can be `co_await`-ed, however it only starts when `co_await`-ing, meaning it is executed synchronously. - -Here is an example of a command making use of dpp::task to retrieve the avatar of a specified user, or if missing, the sender: - -~~~~~~~~~~{.cpp} -#include - -int main() { - dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); - - bot.on_log(dpp::utility::cout_logger()); - - bot.on_slashcommand([](dpp::slashcommand_t event) -> dpp::job { - if (event.command.get_command_name() == "avatar") { - // Make a nested coroutine to fetch the guild member requested, that returns it as an optional - constexpr auto resolve_member = [](const dpp::slashcommand_t &event) -> dpp::task> { - const dpp::command_value &user_param = event.get_parameter("user"); - dpp::snowflake user_id; - - if (std::holds_alternative(user_param)) - user_id = event.command.usr.id; // Parameter is empty so user is sender - else if (std::holds_alternative(user_param)) - user_id = std::get(user_param); // Parameter has a user - - // If we have the guild member in the command's resolved data, return it - const auto &member_map = event.command.resolved.members; - if (auto member = member_map.find(user_id); member != member_map.end()) - co_return member->second; - - // Try looking in guild cache - dpp::guild *guild = dpp::find_guild(event.command.guild_id); - if (guild) { - // Look in guild's member cache - if (auto member = guild->members.find(user_id); member != guild->members.end()) { - co_return member->second; - } - } - - // Finally if everything else failed, request API - dpp::confirmation_callback_t confirmation = co_await event.from->creator->co_guild_get_member(event.command.guild_id, user_id); - if (confirmation.is_error()) - co_return std::nullopt; // Member not found, return empty - else - co_return confirmation.get(); - }; - - // Send a " is thinking..." message, to wait on later so we can edit - dpp::async thinking = event.co_thinking(false); - - // Call our coroutine defined above to retrieve the member requested - std::optional member = co_await resolve_member(event); - - if (!member.has_value()) { - // Wait for the thinking response to arrive to make sure we can edit - co_await thinking; - event.edit_original_response(dpp::message{"User not found in this server!"}); - co_return; - } - - std::string avatar_url = member->get_avatar_url(512); - if (avatar_url.empty()) { // Member does not have a custom avatar for this server, get their user avatar - dpp::confirmation_callback_t confirmation = co_await event.from->creator->co_user_get_cached(member->user_id); - - if (confirmation.is_error()) - { - // Wait for the thinking response to arrive to make sure we can edit - co_await thinking; - event.edit_original_response(dpp::message{"User not found!"}); - co_return; - } - avatar_url = confirmation.get().get_avatar_url(512); - } - - // Wait for the thinking response to arrive to make sure we can edit - co_await thinking; - event.edit_original_response(dpp::message{avatar_url}); - } - }); - - - bot.on_ready([&bot](const dpp::ready_t & event) { - if (dpp::run_once()) { - dpp::slashcommand command("avatar", "Get your or another user's avatar image", bot.me.id); - - command.add_option(dpp::command_option(dpp::co_user, "user", "User to fetch the avatar from")); - - bot.global_command_create(command); - } - }); - - bot.start(dpp::st_wait); -} -~~~~~~~~~~ +\page coroutines Advanced Commands with Coroutines + +\warning D++ Coroutines are a very new feature and are currently only supported by D++ on g++ 11, clang/LLVM 14, and MSVC 19.37 or above. Additionally, D++ must be built with the CMake option `DPP_CORO`, and your program must both define the macro `DPP_CORO` and use C++20 or above. The feature is experimental and may have bugs or even crashes, please report any to [GitHub Issues](https://github.com/brainboxdotcc/DPP/issues) or to our [Discord Server](https://discord.gg/dpp). + +## What is a Coroutine? + +Introduced in C++20, coroutines are the solution to the impracticality of callbacks. In short, a coroutine is a function that can be paused and resumed later. They are an extremely powerful alternative to callbacks for asynchronous APIs in particular, as the function can be paused when waiting for an API response, and resumed when it is received. + +Let's revisit \ref attach-file "attaching a downloaded file", but this time with a coroutine: + +~~~~~~~~~~~~~~~cpp +#include + +int main() { + dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); + bot.on_log(dpp::utility::cout_logger()); + + /* Message handler to look for a command called !file */ + /* Make note of passing the event by value, this is important (explained below) */ + bot.on_message_create([](dpp::message_create_t event) -> dpp::job { + dpp::cluster *cluster = event.from->creator; + + if (event.msg.content == "!file") { + // request an image and co_await the response + dpp::http_request_completion_t result = co_await cluster->co_request("https://dpp.dev/DPP-Logo.png", dpp::m_get); + + // create a message + dpp::message msg(event.msg.channel_id, "This is my new attachment:"); + + // attach the image on success + if (result.status == 200) { + msg.add_file("logo.png", result.body); + } + + // send the message + cluster->message_create(msg); + } + }); + + bot.start(dpp::st_wait); + return 0; +} +~~~~~~~~~~~~~~~ + +Coroutines can make commands simpler by eliminating callbacks, which can be very handy in the case of complex commands that rely on a lot of different data or steps. + +In order to be a coroutine, a function has to return a special type with special functions; D++ offers dpp::job, dpp::task, and dpp::coroutine, which are designed to work seamlessly with asynchronous calls through dpp::async, which all the functions starting with `co_` such as dpp::cluster::co_message_create return. Event routers can have a dpp::job attached to them, as this object allows to create coroutines that can execute on their own, asynchronously. More on that and the difference between it and the other two types later. To turn a function into a coroutine, simply make it return dpp::job as seen in the example at line 10, then use `co_await` on awaitable types or `co_return`. The moment the execution encounters one of these two keywords, the function is transformed into a coroutine. Coroutines that use dpp::job can be used for event handlers, they can be attached to an event router just the same way as regular event handlers. + +When using a `co_*` function such as `co_message_create`, the request is sent immediately and the returned dpp::async can be `co_await`-ed, at which point the coroutine suspends (pauses) and returns back to its caller; in other words, the program is free to go and do other things while the data is being retrieved and D++ will resume your coroutine when it has the data you need, which will be returned from the `co_await` expression. + +\attention You may hear that coroutines are "writing async code as if it was sync", while this is sort of correct, it may limit your understanding and especially the dangers of coroutines. I find **they are best thought of as a shortcut for a state machine**, if you've ever written one, you know what this means. Think of the lambda as *its constructor*, in which captures are variable parameters. Think of the parameters passed to your lambda as data members in your state machine. When you `co_await` something, the state machine's function exits, the program goes back to the caller, at this point the calling function may return. References are kept as references in the state machine, which means by the time the state machine is resumed, the reference may be dangling: \ref lambdas-and-locals "this is not good"! As a rule of thumb when making coroutines, **always prefer taking parameters by value and avoid lambda capture**. Another way to think of them is just like callbacks but keeping the current scope intact. In fact this is exactly what it is, the `co_*` functions call the normal API calls, with a callback that resumes the coroutine, *in the callback thread*. This means you cannot rely on thread_local variables and need to keep in mind concurrency issues with global states, as your coroutine will be resumed in another thread than the one it started on. + +## Several Steps in One + +\note The next example assumes you are already familiar with how to use \ref firstbot "slash commands", \ref slashcommands "parameters", and \ref discord-application-command-file-upload "sending files through a command". + +Here is another example of what is made easier with coroutines, an "addemoji" command taking a file and a name as a parameter. This means downloading the emoji, submitting it to Discord, and finally replying, with some error handling along the way. Normally we would have to use callbacks and some sort of object keeping track of our state, but with coroutines, it becomes much simpler: + +~~~~~~~~~~cpp +#include + +int main() { + dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); + bot.on_log(dpp::utility::cout_logger()); + + bot.on_slashcommand([](dpp::slashcommand_t event) -> dpp::job { + if (event.command.get_command_name() == "addemoji") { + dpp::cluster *cluster = event.from->creator; + // Retrieve parameter values + dpp::snowflake file_id = std::get(event.get_parameter("file")); + std::string emoji_name = std::get(event.get_parameter("name")); + + // Get the attachment from the resolved list + const dpp::attachment &attachment = event.command.get_resolved_attachment(file_id); + + // For simplicity for this example we only support PNG + if (attachment.content_type != "image/png") { + // While event.co_reply is available, we can just use event.reply, as we will exit the command anyway and don't need to wait on the result + event.reply("Error: type " + attachment.content_type + " not supported"); + co_return; + } + // Send a " is thinking…" message, to wait on later so we can edit + dpp::async thinking = event.co_thinking(false); + + // Download and co_await the result + dpp::http_request_completion_t response = co_await cluster->co_request(attachment.url, dpp::m_get); + + if (response.status != 200) { // Page didn't send the image + co_await thinking; // Wait for the thinking response to arrive so we can edit + event.edit_response("Error: could not download the attachment"); + } + else { + // Load the image data in a dpp::emoji + dpp::emoji emoji(emoji_name); + emoji.load_image(response.body, dpp::image_type::i_png); + + // Create the emoji and co_await the response + dpp::confirmation_callback_t confirmation = co_await cluster->co_guild_emoji_create(event.command.guild_id, emoji); + + co_await thinking; // Wait for the thinking response to arrive so we can edit + if (confirmation.is_error()) { + event.edit_response("Error: could not add emoji: " + confirmation.get_error().message); + } + else { // Success + event.edit_response("Successfully added " + confirmation.get().get_mention()); // Show the new emoji + } + } + } + }); + + bot.on_ready([&bot](const dpp::ready_t & event) { + if (dpp::run_once()) { + dpp::slashcommand command("addemoji", "Add an emoji", bot.me.id); + + // Add file and name as required parameters + command.add_option(dpp::command_option(dpp::co_attachment, "file", "Select an image", true)); + command.add_option(dpp::command_option(dpp::co_string, "name", "Name of the emoji to add", true)); + + bot.global_command_create(command); + } + }); + + bot.start(dpp::st_wait); + return 0; +} +~~~~~~~~~~ + +## I Heard You Liked Tasks + +\note This next example is fairly advanced and makes use of many of both C++ and D++'s advanced features. + +Earlier we mentioned two other types of coroutines provided by D++: dpp::coroutine and dpp::task. They both take their return type as a template parameter, which may be void. Both dpp::job and dpp::task start on the constructor for asynchronous execution, however only the latter can be `co_await`-ed, this allows you to retrieve its return value. If a dpp::task is destroyed before it ends, it is cancelled and will stop when it is resumed from the next `co_await`. dpp::coroutine also has a return value and can be `co_await`-ed, however it only starts when `co_await`-ing, meaning it is executed synchronously. + +Here is an example of a command making use of dpp::task to retrieve the avatar of a specified user, or if missing, the sender: + +~~~~~~~~~~cpp +#include + +int main() { + dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); + bot.on_log(dpp::utility::cout_logger()); + + bot.on_slashcommand([](dpp::slashcommand_t event) -> dpp::job { + if (event.command.get_command_name() == "avatar") { + // Make a nested coroutine to fetch the guild member requested, that returns it as an optional + constexpr auto resolve_member = [](const dpp::slashcommand_t &event) -> dpp::task> { + const dpp::command_value &user_param = event.get_parameter("user"); + dpp::snowflake user_id; + + if (std::holds_alternative(user_param)) { + user_id = event.command.usr.id; // Parameter is empty so user is sender + } + else if (std::holds_alternative(user_param)) { + user_id = std::get(user_param); // Parameter has a user + } + + // If we have the guild member in the command's resolved data, return it + const auto &member_map = event.command.resolved.members; + if (auto member = member_map.find(user_id); member != member_map.end()) { + co_return member->second; + } + + // Try looking in guild cache + dpp::guild *guild = dpp::find_guild(event.command.guild_id); + if (guild) { + // Look in guild's member cache + if (auto member = guild->members.find(user_id); member != guild->members.end()) { + co_return member->second; + } + } + + // Finally if everything else failed, request API + dpp::confirmation_callback_t confirmation = co_await event.from->creator->co_guild_get_member(event.command.guild_id, user_id); + if (confirmation.is_error()) { + co_return std::nullopt; // Member not found, return empty + } + else { + co_return confirmation.get(); + } + }; + + // Send a " is thinking…" message, to wait on later so we can edit + dpp::async thinking = event.co_thinking(false); + + // Call our coroutine defined above to retrieve the member requested + std::optional member = co_await resolve_member(event); + + if (!member.has_value()) { + // Wait for the thinking response to arrive to make sure we can edit + co_await thinking; + event.edit_original_response(dpp::message{"User not found in this server!"}); + co_return; + } + + std::string avatar_url = member->get_avatar_url(512); + if (avatar_url.empty()) { // Member does not have a custom avatar for this server, get their user avatar + dpp::confirmation_callback_t confirmation = co_await event.from->creator->co_user_get_cached(member->user_id); + + if (confirmation.is_error()) { + // Wait for the thinking response to arrive to make sure we can edit + co_await thinking; + event.edit_original_response(dpp::message{"User not found!"}); + co_return; + } + avatar_url = confirmation.get().get_avatar_url(512); + } + + // Wait for the thinking response to arrive to make sure we can edit + co_await thinking; + event.edit_original_response(dpp::message{avatar_url}); + } + }); + + bot.on_ready([&bot](const dpp::ready_t & event) { + if (dpp::run_once()) { + dpp::slashcommand command("avatar", "Get your or another user's avatar image", bot.me.id); + + command.add_option(dpp::command_option(dpp::co_user, "user", "User to fetch the avatar from")); + + bot.global_command_create(command); + } + }); + + bot.start(dpp::st_wait); + return 0; +} +~~~~~~~~~~ \ No newline at end of file diff --git a/docpages/advanced_reference/governance.md b/docpages/advanced_reference/governance.md index 8955f2eaaa..da06b050bc 100644 --- a/docpages/advanced_reference/governance.md +++ b/docpages/advanced_reference/governance.md @@ -8,7 +8,7 @@ The D++ Project was originally created by Craig Edwards, A.K.A. @brain on Discor ## Project Maintainers -Other maintainers with access to merge pull requests (those with the `@PR Review` role on the discord) have access to and responsibility for checking pull requests sent in by contributors and may request additional changes to keep the pulls aligned with the project goals. These members of the D++ team may and do also merge pull requests at their discretion. +Other maintainers with access to merge pull requests (those with the `@PR Review` role on the Discord) have access to and responsibility for checking pull requests sent in by contributors and may request additional changes to keep the pulls aligned with the project goals. These members of the D++ team may and do also merge pull requests at their discretion. ## Decision Making @@ -16,4 +16,4 @@ For most decisions, these are discussed in our `#library-development` channel on ## Contingency -*In the case of any unforeseen disaster such as death of the project leader, control over domain (the only part of the project which has a direct cost attached) would pass to his next of kin who would arrange for transfer to a pre-arranged trusted third party who would administrate the domain going forward. Everything else relating to D++ is hosted on GitHub and would continue as normal.* \ No newline at end of file +*In the case of any unforeseen disaster such as death of the project leader, control over domain (the only part of the project which has a direct cost attached) would pass to his next of kin who would arrange for transfer to a pre-arranged trusted third party who would administer the domain going forward. Everything else relating to D++ is hosted on GitHub and would continue as normal.* \ No newline at end of file diff --git a/docpages/advanced_reference/lambdas_and_locals.md b/docpages/advanced_reference/lambdas_and_locals.md index 20fba2b68c..2484659634 100644 --- a/docpages/advanced_reference/lambdas_and_locals.md +++ b/docpages/advanced_reference/lambdas_and_locals.md @@ -1,4 +1,4 @@ -\page lambdas-and-locals Ownership of local variables and safely transferring into a lambda +\page lambdas-and-locals Ownership of Local Variables and Safely Transferring into a Lambda If you are reading this page, you have likely been sent here by someone helping you diagnose why your bot is crashing or why seemingly invalid values are being passed into lambdas within your program that uses D++. @@ -10,7 +10,7 @@ To explain this situation and how it causes issues I'd like you to imagine the a Now imagine the following code scenario. We will describe this code scenario as the magic trick above, in the steps below: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp bot.on_message_create([&bot](const dpp::message_create_t & event) { int myvar = 0; bot.message_create(dpp::message(event.msg.channel_id, "foobar"), [&](const auto & cc) { @@ -24,18 +24,18 @@ In this scenario, the outer event, `on_message_create` is your tablecloth. The l * The magician executes his magic trick (D++ the `bot.on_message_create entering` the outer lambda) * Your code executes `bot.message_create()` inside this outer lambda * D++ inserts your request to send a message into its queue, in another thread. The inner lambda, where you might later set `myvar = 42` is safely copied into the queue for later calling. -* The tablecloth is whipped away... in other words, `bot.on_message_create` ends, and all local variables including `myvar` become invalid -* At a later time (usually 80ms through to anything up to 4 seconds depending on rate limits!) the message is sent, and your inner lambda which was saved at the earlier step is called. -* Your inner lambda attempts to set `myvar` to 42... but `myvar` no longer exists, as the outer lambda has been destroyed.... -* The table wobbles... the cutlery shakes... and... +* The tablecloth is whipped away… in other words, `bot.on_message_create` ends, and all local variables including `myvar` become invalid +* At a later time (usually 80 ms through to anything up to 4 seconds depending on rate limits!) the message is sent, and your inner lambda which was saved at the earlier step is called. +* Your inner lambda attempts to set `myvar` to 42… but `myvar` no longer exists, as the outer lambda has been destroyed… +* The table wobbles… the cutlery shakes… and… * Best case scenario: you access invalid RAM no longer owned by your program by trying to write to `myvar`, and [your bot outright crashes horribly](https://www.youtube.com/watch?v=sm8qb2kP-fQ)! -* Worse case scenario: you silently corrupt ram and end up spending days trying to track down a bug that subtly breaks your bot... +* Worse case scenario: you silently corrupt RAM and end up spending days trying to track down a bug that subtly breaks your bot… The situation I am trying to describe here is one of object and variable ownership. When you call a lambda, **always assume that every non-global reference outside of that lambda will be invalid when the lambda is called**! For any non-global variable always take a **copy** of the variable (not reference, or pointer). Global variables or those declared directly in `main()` are safe to pass as references. For example, if we were to fix the broken code above, we could rewrite it like this: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp bot.on_message_create([&bot](const dpp::message_create_t & event) { int myvar = 0; bot.message_create(dpp::message(event.msg.channel_id, "foobar"), [myvar](const auto & cc) { @@ -45,7 +45,7 @@ bot.on_message_create([&bot](const dpp::message_create_t & event) { }); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Note, however that when you set `myvar` within the inner lambda, this does **not effect** the value of the var outside it. Lambdas should be considered self-contained silos, and as they execute in other threads should not be relied upon to set anything that exists **outside of that lambda**. +Note, however that when you set `myvar` within the inner lambda, this does **not effect** the value of the `myvar` outside it. Lambdas should be considered self-contained silos, and as they execute in other threads should not be relied upon to set anything that exists **outside of that lambda**. \warning Always avoid just using `[&]` in a lambda to access all in the scope above. It is unlikely that half of this scope will still even be valid by the time you get a look at it! @@ -53,4 +53,4 @@ Similarly, and important to note, your program **will not wait for bot.message_c If you do want to get variables out of your lambda, create a class, or call a separate function, and pass what you need into that function from the lambda **by value** or alternatively, you can use `std::bind` to bind a lambda directly to an object's method instead (this is great for modular bots). -If you are stuck, as this is a complex subject please do feel free to ask on the [official support server](https://discord.gg/dpp)! +If you are stuck, as this is a complex subject please do feel free to ask on the [official support server](https://discord.gg/dpp)! \ No newline at end of file diff --git a/docpages/advanced_reference/roadmap.md b/docpages/advanced_reference/roadmap.md index ab966dd60b..aa30c4c514 100644 --- a/docpages/advanced_reference/roadmap.md +++ b/docpages/advanced_reference/roadmap.md @@ -4,4 +4,4 @@ At present our roadmap is: *Short term (6 months):*: Stabilise coroutine support and release it as stable a feature -*Long term*: Continue development of the library to implement Discord new features as they add them. Discord do not share their internal roadmap with library developers, so we are informed of these new features shortly before they become public given enough time to implement them. This is our permanent ongoing goal. \ No newline at end of file +*Long term*: Continue development of the library to implement Discord new features as they add them. Discord does not share their internal roadmap with library developers, so we are informed of these new features shortly before they become public given enough time to implement them. This is our permanent ongoing goal. \ No newline at end of file diff --git a/docpages/advanced_reference/security.md b/docpages/advanced_reference/security.md index 9c87e08eb7..aca5b9a78d 100644 --- a/docpages/advanced_reference/security.md +++ b/docpages/advanced_reference/security.md @@ -4,7 +4,7 @@ D++ is designed with the following security goals in mind: * D++ design will be user friendly to help avoid shooting yourself in the foot and introducing security vulnerabilities in the code. * D++ will keep external dependencies to an absolute minimum at all times so there is less chance of third party code making your bot vulnerable to attack. -* D++ design will take the path of 'least surprise', and will be simple and straightforward to use, leading to less developer errors that could lead to vulnerabilities -* Any reported CVEs which are logged via the proper channels will be fixed within 14 days -* All settings, configuration and parameters will be secure by default -* D++ settings and design will conform to Discord TOS and will not implement or support features that break the Discord TOS. +* D++ design will take the path of 'least surprise', and will be simple and straightforward to use, leading to less developer errors that could lead to vulnerabilities. +* Any reported CVEs which are logged via the proper channels will be fixed within 14 days. +* All settings, configuration, and parameters will be secure by default. +* D++ settings and design will conform to Discord ToS and will not implement or support features that break the Discord ToS. \ No newline at end of file diff --git a/docpages/advanced_reference/separate-events.md b/docpages/advanced_reference/separate-events.md index dc2764cbca..460355df51 100644 --- a/docpages/advanced_reference/separate-events.md +++ b/docpages/advanced_reference/separate-events.md @@ -1,4 +1,4 @@ -\page separate-events Separating events into new classes +\page separate-events Separating Events into New Classes If you're someone that loves file organisation (or you hate how cluttered your `main.cpp` has become) then you may be interested in moving events into separate classes outside of the `main.cpp` file. This is a great way to improve readability and can be helpful in many cases! For example, you can have two classes on the same event, except one could be reading messages for spam and one could be reading messages for bad words! @@ -16,54 +16,49 @@ Once that's done, it should look similar to this (this screenshot has more files First, we need to define the function that will be called when the event fires. We do this in the `message_listener.h`, like so: -~~~~~~~~~~{.cpp} +~~~~~~~~~~cpp #pragma once #include class message_listener { - public: - - /* Create a static function that can be called anywhere. */ - static void on_message_create(const dpp::message_create_t& event); - + /* Create a static function that can be called anywhere. */ + static void on_message_create(const dpp::message_create_t& event); }; ~~~~~~~~~~ Then we need to add our code for what should happen when this event fires. We do this in the `message_listener.cpp`, like so: -~~~~~~~~~~{.cpp} +~~~~~~~~~~cpp #include "message_listener.h" void message_listener::on_message_create(const dpp::message_create_t &event) { - /* See if the message contains the phrase we want to check for. - * If there's at least a single match, we reply and say it's not allowed. - */ - if (event.msg.content.find("bad word") != std::string::npos) { - event.reply("That is not allowed here. Please, mind your language!", true); - } + /* See if the message contains the phrase we want to check for. + * If there's at least a single match, we reply and say it's not allowed. + */ + if (event.msg.content.find("bad word") != std::string::npos) { + event.reply("That is not allowed here. Please, mind your language!", true); + } } - ~~~~~~~~~~ Now, you'll have a nice area where you can easily see the code, without scrolling through all of your `main.cpp` file just to get to this event! However, we've not finished yet! If you thought "How does the `main.cpp` file actually know to call this?" then, 10 points to you! It doesn't know! We need to go do that now. So, let's do exactly that. -~~~~~~~~~~{.cpp} +~~~~~~~~~~cpp #include #include "listeners/message_listener.h" -int main() -{ - /* Create the bot, but with our intents so we can use messages. */ +int main() { + /* Create the bot, but with our intents so we can use messages. */ dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); bot.on_log(dpp::utility::cout_logger()); - /* Fires our event that is located in MessageListener when the bot detects a message in any server and any channel it has access to. */ - bot.on_message_create(&message_listener::on_message_create); + /* Fires our event that is located in MessageListener when the bot detects a message in any server and any channel it has access to. */ + bot.on_message_create(&message_listener::on_message_create); bot.start(dpp::st_wait); diff --git a/docpages/advanced_reference/thread_model.md b/docpages/advanced_reference/thread_model.md index 274fdde017..f17b1014b8 100644 --- a/docpages/advanced_reference/thread_model.md +++ b/docpages/advanced_reference/thread_model.md @@ -24,19 +24,19 @@ digraph "Thread Model" { node [style=filled,color=4] "Shard 1" [style=filled, color=4] "Shard 2" - "Shard 3..." - label = "Shards (Each is a thread, one per 2500 discord guilds)"; + "Shard 3…" + label = "Shards (Each is a thread, one per 2500 Discord guilds)"; } subgraph cluster_1 { style=filled color=lightgrey; node [style=filled,color=4] - "REST Requests" + "REST Requests" "Request In Queue 1" "Request In Queue 2" - "Request In Queue 3..." - "Request Out Queue" + "Request In Queue 3…" + "Request Out Queue" label = "REST Requests (Each in queue, and the out queue, are threads)" } @@ -44,7 +44,7 @@ digraph "Thread Model" { style=filled color=lightgrey; node [style=filled,color=4] - "Discord Events" [style=filled,color=4] + "Discord Events" [style=filled,color=4] "User Callback Functions" label = "Events and Callbacks" } @@ -53,10 +53,10 @@ digraph "Thread Model" { "REST Requests" [shape=rect] "Request In Queue 1" [shape=rect] "Request In Queue 2" [shape=rect] - "Request In Queue 3..." [shape=rect] + "Request In Queue 3…" [shape=rect] "Shard 1" [shape=rect] "Shard 2" [shape=rect] - "Shard 3..." [shape=rect] + "Shard 3…" [shape=rect] "Request Out Queue" [shape=rect] "Discord Events" [shape=rect] "User Callback Functions" [shape=rect] @@ -64,18 +64,18 @@ digraph "Thread Model" { "Cluster" -> "REST Requests" "Shard 1" -> "Discord Events" "Shard 2" -> "Discord Events" - "Shard 3..." -> "Discord Events" + "Shard 3…" -> "Discord Events" "Your Program" -> "Cluster" "Cluster" -> "Shard 1" "Cluster" -> "Shard 2" - "Cluster" -> "Shard 3..." + "Cluster" -> "Shard 3…" "REST Requests" -> "Request In Queue 1" "REST Requests" -> "Request In Queue 2" - "REST Requests" -> "Request In Queue 3..." + "REST Requests" -> "Request In Queue 3…" "Request In Queue 1" -> "Request Out Queue" "Request In Queue 2" -> "Request Out Queue" - "Request In Queue 3..." -> "Request Out Queue" + "Request In Queue 3…" -> "Request Out Queue" "Request Out Queue" -> "User Callback Functions" "User Callback Functions" -> "Your Program" } -\enddot +\enddot \ No newline at end of file diff --git a/docpages/advanced_reference/unit_tests.md b/docpages/advanced_reference/unit_tests.md index bdd2a0b61e..c14f5ea1c2 100644 --- a/docpages/advanced_reference/unit_tests.md +++ b/docpages/advanced_reference/unit_tests.md @@ -2,7 +2,7 @@ ## Running Unit Tests -If you are adding functionality to DPP, make sure to run unit tests. This makes sure that the changes do not break anything. All pull requests must pass all unit tests before merging. +If you are adding functionality to D++, make sure to run unit tests. This makes sure that the changes do not break anything. All pull requests must pass all unit tests before merging. Before running test cases, create a test server for your test bot. You should: @@ -13,16 +13,17 @@ Before running test cases, create a test server for your test bot. You should: * Create at least one voice channel * Create at least one text channel -Then, set the following variables to the appropriate values. (Below is a fake token, don't bother trying to use it) +Then, set the following variables to the appropriate values. (Below is a fake token, don't bother trying to use it.) - export DPP_UNIT_TEST_TOKEN="ODI2ZSQ4CFYyMzgxUzkzzACy.HPL5PA.9qKR4uh8po63-pjYVrPAvQQO4ln" - export TEST_GUILD_ID="907951970017480704" - export TEST_TEXT_CHANNEL_ID="907951970017480707" - export TEST_VC_ID="907951970017480708" - export TEST_USER_ID="826535422381391913" - export TEST_EVENT_ID="909928577951203360" +```bash +export DPP_UNIT_TEST_TOKEN="ODI2ZSQ4CFYyMzgxUzkzzACy.HPL5PA.9qKR4uh8po63-pjYVrPAvQQO4ln" +export TEST_GUILD_ID="907951970017480704" +export TEST_TEXT_CHANNEL_ID="907951970017480707" +export TEST_VC_ID="907951970017480708" +export TEST_USER_ID="826535422381391913" +export TEST_EVENT_ID="909928577951203360" +``` -Then, after cloning and building DPP, run `cd build && ctest -VV` for unit test cases. - -If you do not specify the `DPP_UNIT_TEST_TOKEN` environment variable, a subset of the tests will run which do not require discord connectivity. +Then, after cloning and building D++, run `cd build && ctest -VV` for unit test cases. +If you do not specify the `DPP_UNIT_TEST_TOKEN` environment variable, a subset of the tests will run which do not require Discord connectivity. \ No newline at end of file diff --git a/docpages/building/02_build.md b/docpages/building/02_build.md index 5ff74290c3..68b62d65ea 100644 --- a/docpages/building/02_build.md +++ b/docpages/building/02_build.md @@ -1,10 +1,10 @@ -\page install-from-source Building D++ From Source +\page install-from-source Building D++ from Source The way you build D++ varies from system to system. Please follow the guide below for your OS: -* \subpage buildlinux "Building on Linux" -* \subpage buildwindows "Building on Windows" -* \subpage buildosx "Building on OSX" -* \subpage buildfreebsd "Building on FreeBSD" +* \subpage buildlinux +* \subpage buildwindows +* \subpage buildosx +* \subpage buildfreebsd -@warning Note that you most likely don't need to build D++ from source if you're on Linux or Windows. We offer prebuilt binaries for these platforms and are listed in package managers! Check the downloads in the releases section on github. +\warning Note that you most likely don't need to build D++ from source if you're on Linux or Windows. We offer prebuilt binaries for these platforms and are listed in package managers! Check the downloads in the releases section on GitHub. \ No newline at end of file diff --git a/docpages/building/freebsd.md b/docpages/building/freebsd.md index 745346fab5..411845ca55 100644 --- a/docpages/building/freebsd.md +++ b/docpages/building/freebsd.md @@ -1,49 +1,62 @@ \page buildfreebsd Building on FreeBSD ## 1. Toolchain -This project uses CMake. Install it with `pkg install cmake` + +This project uses CMake. Install it with `pkg install cmake`. ## 2. Install External Dependencies + Your FreeBSD base system should have all the required dependencies installed by default. -For voice support, additional dependencies are required +For voice support, additional dependencies are required: - pkg install libsodium opus pkgconf +```bash +pkg install libsodium opus pkgconf +``` ## 3. Build Source Code - cmake -B ./build - cmake --build ./build -j8 - +```bash +cmake -B ./build +cmake --build ./build -j8 +``` + Replace the number after `-j` with a number suitable for your setup, usually the same as the number of cores on your machine. `cmake` will fetch any dependencies that are required for you and ensure they are compiled alongside the library. -## 4. Install globally +## 4. Install Globally - cd build; make install +```bash +cd build +make install +``` -## 5. Installation to a different directory +## 5. Installation to a Different Directory -If you want to install the library, its dependencies and header files to a different directory, specify this directory when running `cmake`: +If you want to install the library, its dependencies, and header files to a different directory, specify this directory when running `cmake`: - cmake .. -DCMAKE_INSTALL_PREFIX=/path/to/install +```bash +cmake .. -DCMAKE_INSTALL_PREFIX=/path/to/install +``` Then once the build is complete, run `make install` to install to the location you specified. -## 6. Using the library +## 6. Using the Library Once installed, you can make use of the library in standalone programs simply by including it and linking to it: - clang++ -std=c++17 -ldpp mydppbot.cpp -o dppbot +```bash +clang++ -std=c++17 -ldpp mydppbot.cpp -o dppbot +``` The important flags in this command-line are: - * `-std=c++17` - Required to compile the headers - * `-ldpp` - Link to libdpp.dylib - * `mydppbot.cpp` - Your source code - * `dppbot` - The name of the executable to make +* `-std=c++17` - Required to compile the headers +* `-ldpp` - Link to libdpp.dylib +* `mydppbot.cpp` - Your source code +* `dppbot` - The name of the executable to make -Of course, this is just a proof of concept - you should really use a more robust build system like [`cmake`](@ref buildcmake). +Of course, this is just a proof of concept - you should really use a more robust build system like [CMake](\ref buildcmake). If you are having trouble setting up CMake, you can try [our template bot](https://github.com/brainboxdotcc/templatebot). -**Have fun!** +**Have fun!** \ No newline at end of file diff --git a/docpages/building/linux.md b/docpages/building/linux.md index 043823a042..ba2b3cd6bc 100644 --- a/docpages/building/linux.md +++ b/docpages/building/linux.md @@ -4,39 +4,47 @@ ## 1. Build Source Code - cmake -B ./build - cmake --build ./build -j8 +```bash +cmake -B ./build +cmake --build ./build -j8 +``` Replace the number after `-j` with a number suitable for your setup, usually the same as the number of cores on your machine. `cmake` will fetch any dependencies that are required for you and ensure they are compiled alongside the library. ## 2. Install to /usr/local/include and /usr/local/lib - cd build; sudo make install +```bash +cd build +sudo make install +``` -## 3. Installation to a different directory +## 3. Installation to a Different Directory -If you want to install the library, its dependencies and header files to a different directory, specify this directory when running `cmake`: +If you want to install the library, its dependencies, and header files to a different directory, specify this directory when running `cmake`: - cmake .. -DCMAKE_INSTALL_PREFIX=/path/to/install +```bash +cmake .. -DCMAKE_INSTALL_PREFIX=/path/to/install +``` Then once the build is complete, run `make install` to install to the location you specified. -## 4. Using the library +## 4. Using the Library Once installed to the `/usr/local` directory, you can make use of the library in standalone programs simply by including it and linking to it: - g++ -std=c++17 mydppbot.cpp -o dppbot -ldpp +```bash +g++ -std=c++17 mydppbot.cpp -o dppbot -ldpp +``` The important flags in this command-line are: - * `-std=c++17` - Required to compile the headers - * `mydppbot.cpp` - Your source code - * `dppbot` - The name of the executable to make +* `-std=c++17` - Required to compile the headers +* `-ldpp` - Link to libdpp.so +* `mydppbot.cpp` - Your source code +* `dppbot` - The name of the executable to make -Of course, this is just a proof of concept — you should really use a more robust build system like GNU `make` or [`cmake`](@ref buildcmake). +Of course, this is just a proof of concept — you should really use a more robust build system like GNU `make` or [CMake](\ref buildcmake). If you are having trouble setting up CMake, you can try [our template bot](https://github.com/brainboxdotcc/templatebot). -**Have fun!** - - +**Have fun!** \ No newline at end of file diff --git a/docpages/building/osx.md b/docpages/building/macos.md similarity index 54% rename from docpages/building/osx.md rename to docpages/building/macos.md index 45b855373e..7256be3c9a 100644 --- a/docpages/building/osx.md +++ b/docpages/building/macos.md @@ -1,55 +1,67 @@ -\page buildosx Building on OSX +\page buildosx Building on macOS ## 1. Toolchain -Before compiling make sure you have all the tools installed. -1. To install the dependencies, this guide will use homebrew which has [installation instructions on their project page](https://brew.sh/). +Before compiling make sure you have all the tools installed. +1. To install the dependencies, this guide will use Homebrew which has [installation instructions on their project page](https://brew.sh/). 2. This project uses CMake to generate the makefiles. Install it with `brew install cmake`. ## 2. Install External Dependencies - brew install openssl - +```bash +brew install openssl +``` + For voice support, additional dependencies are required: - brew install libsodium opus +```bash +brew install libsodium opus +``` ## 3. Build Source Code - cmake -B ./build - cmake --build ./build -j8 - +```bash +cmake -B ./build +cmake --build ./build -j8 +``` + Replace the number after `-j` with a number suitable for your setup, usually the same as the number of cores on your machine. `cmake` will fetch any dependencies that are required for you and ensure they are compiled alongside the library. -## 4. Install globally +## 4. Install Globally - cd build; sudo make install +```bash +cd build +sudo make install +``` -## 5. Installation to a different directory +## 5. Installation to a Different Directory -If you want to install the library, its dependencies and header files to a different directory, specify this directory when running `cmake`: +If you want to install the library, its dependencies, and header files to a different directory, specify this directory when running `cmake`: - cmake .. -DCMAKE_INSTALL_PREFIX=/path/to/install +```bash +cmake .. -DCMAKE_INSTALL_PREFIX=/path/to/install +``` Then once the build is complete, run `make install` to install to the location you specified. -## 6. Using the library +## 6. Using the Library Once installed, you can make use of the library in standalone programs simply by including it and linking to it: - clang++ -std=c++17 -ldpp mydppbot.cpp -o dppbot +```bash +clang++ -std=c++17 -ldpp mydppbot.cpp -o dppbot +``` The important flags in this command-line are: - * `-std=c++17` - Required to compile the headers - * `-ldpp` - Link to libdpp.dylib - * `mydppbot.cpp` - Your source code - * `dppbot` - The name of the executable to make +* `-std=c++17` - Required to compile the headers +* `-ldpp` - Link to libdpp.dylib +* `mydppbot.cpp` - Your source code +* `dppbot` - The name of the executable to make -Of course, this is just a proof of concept - you should really use a more robust build system like GNU `make` or [`cmake`](@ref buildcmake). +Of course, this is just a proof of concept - you should really use a more robust build system like GNU `make` or [CMake](\ref buildcmake). If you are having trouble setting up CMake, you can try [our template bot](https://github.com/brainboxdotcc/templatebot). -**Have fun!** - +**Have fun!** \ No newline at end of file diff --git a/docpages/building/windows.md b/docpages/building/windows.md index 20643eff4c..bce7f07801 100644 --- a/docpages/building/windows.md +++ b/docpages/building/windows.md @@ -4,26 +4,25 @@ To build on Windows follow these steps *exactly*. The build process depends on s ## Wait a minute! Read this first! -\warning **You do not need to follow this tutorial unless you plan to contribute to or modify the library itself**. Unless you consider yourself an **advanced user** with a specific **requirement to build from source** you should [obtain a pre-made visual studio template containing the latest D++ build (for 32 and 64 bit, release and debug profiles) by clicking here](https://github.com/brainboxdotcc/windows-bot-template/) and completely skip this guide! Instead, read \ref build-a-discord-bot-windows-visual-studio. +\warning **You do not need to follow this tutorial unless you plan to contribute to or modify the library itself**. Unless you consider yourself an **advanced user** with a specific **requirement to build from source** you should [obtain a pre-made Visual Studio template containing the latest D++ build (for 32 and 64 bit, release and debug profiles) by clicking here](https://github.com/brainboxdotcc/windows-bot-template/) and completely skip this guide! Instead, read \ref build-a-discord-bot-windows-visual-studio. ## If you are absolutely sure you need this guide, read on: 1. Make sure you have Visual Studio 2019 or Visual Studio 2022. The Community, Professional or Enterprise versions all work, however you will probably want to install Community. You do **NOT** want to use *Visual Studio Code* for this. You can [download the correct version here](https://visualstudio.microsoft.com/downloads/). -2. Check out the DPP project source using git -3. From within Visual Studio 2019, click the "File" menu, choose "Open" then "CMake", and select the CMakeLists.txt within the project folder - \image html winbuild_1.png - \image html winbuild_2.png +2. Check out the D++ project source using Git +3. From within Visual Studio, click the "File" menu, choose "Open" then "CMake", and select the `CMakeLists.txt` within the project folder +\image html winbuild_1.png +\image html winbuild_2.png 4. Go to the "Build" menu and choose "Build all" or just press F7 - \image html winbuild_3.png +\image html winbuild_3.png 5. Check that compilation succeeded. You may now use the library in your projects! - \image html winbuild_4.png +\image html winbuild_4.png ## Troubleshooting -* If you do not have an option to open the CMakeLists.txt, ensure that you have installed the C++ development portions of Visual Studio (not just web development portions) with at least the default options. -* If the project does not build, please ask for help on the [official discord server](https://discord.gg/dpp). +* If you do not have an option to open the `CMakeLists.txt`, ensure that you have installed the C++ development portions of Visual Studio (not just web development portions) with at least the default options. +* If the project does not build, please ask for help on the [official Discord server](https://discord.gg/dpp). -## After compiling - -After compilation you can directly reference the compiled project in your own CMakeLists.txt as a library or use the `lib/dll/headers` as you wish. Note that `openssl` and `zlib` will also be an indirect dependency of your program (as `DLL` files) and should be copied alongside `dpp.dll`. +## After Compiling +After compilation you can directly reference the compiled project in your own `CMakeLists.txt` as a library or use the `lib/dll/headers` as you wish. Note that `openssl` and `zlib` will also be an indirect dependency of your program (as `DLL` files) and should be copied alongside `dpp.dll`. \ No newline at end of file diff --git a/docpages/example_programs/interactions_and_components.md b/docpages/example_programs/interactions_and_components.md index e952faf039..b20fa78c6b 100644 --- a/docpages/example_programs/interactions_and_components.md +++ b/docpages/example_programs/interactions_and_components.md @@ -1,16 +1,16 @@ -\page interactions-and-components Interactions And Components +\page interactions-and-components Interactions and Components -The example programs listed here demonstrate lots of things to do with interactions, application commands (slash commands) and message components. If you're looking to make your bot **modern and user friendly** these examples are what you need. +The example programs listed here demonstrate lots of things to do with interactions, application commands (slash commands), and message components. If you're looking to make your bot **modern and user friendly** these examples are what you need. -* \subpage slashcommands "Using Slash Commands and Interactions" -* \subpage subcommands "Slash command sub-commands" -* \subpage user-only-messages "Ephemeral replies ('Only you can see this' replies)" -* \subpage components "Using button components" -* \subpage components2 "Advanced button components" -* \subpage components3 "Using select menu components" -* \subpage detecting-messages "Listening to messages" -* \subpage context-menu "Context Menus" -* \subpage modal-dialog-interactions "Modal Dialogs" -* \subpage commandhandler "Unified message/slash command handler" -* \subpage application-command-autocomplete "Slash command auto completion" -* \subpage discord-application-command-file-upload "Using file parameters in slash commands" +* \subpage slashcommands +* \subpage subcommands +* \subpage user-only-messages +* \subpage components +* \subpage components2 +* \subpage components3 +* \subpage detecting-messages +* \subpage context-menu +* \subpage modal-dialog-interactions +* \subpage commandhandler +* \subpage application-command-autocomplete +* \subpage discord-application-command-file-upload \ No newline at end of file diff --git a/docpages/example_programs/interactions_and_components/autocomplete.md b/docpages/example_programs/interactions_and_components/autocomplete.md index 87bee8b4fe..2317f1ddb6 100644 --- a/docpages/example_programs/interactions_and_components/autocomplete.md +++ b/docpages/example_programs/interactions_and_components/autocomplete.md @@ -1,48 +1,44 @@ -\page application-command-autocomplete Slash command auto completion +\page application-command-autocomplete Slash Command Autocompletion Discord now supports sending auto completion lists for slash command choices. To use this feature you can use code such as the example below: -~~~~~~~~~~{.cpp} +~~~~~~~~~~cpp #include - -int main() -{ - dpp::cluster bot("token"); - bot.on_log(dpp::utility::cout_logger()); +int main() { + dpp::cluster bot("token"); + bot.on_log(dpp::utility::cout_logger()); bot.on_ready([&bot](const dpp::ready_t & event) { - if (dpp::run_once()) { - - /* Create a new global command once on ready event */ - bot.global_command_create(dpp::slashcommand("blep", "Send a random adorable animal photo", bot.me.id) - .add_option( - /* If you set the auto complete setting on a command option, it will trigger the on_autocomplete - * event whenever discord needs to fill information for the choices. You cannot set any choices - * here if you set the auto complete value to true. - */ - dpp::command_option(dpp::co_string, "animal", "The type of animal").set_auto_complete(true) - ) - ); + if (dpp::run_once()) { + /* Create a new global command once on ready event */ + bot.global_command_create(dpp::slashcommand("blep", "Send a random adorable animal photo", bot.me.id) + .add_option( + /* If you set the autocomplete setting on a command option, it will trigger the on_autocomplete + * event whenever Discord needs to fill information for the choices. You cannot set any choices + * here if you set the autocomplete value to true. + */ + dpp::command_option(dpp::co_string, "animal", "The type of animal").set_auto_complete(true) + ) + ); } }); /* The interaction create 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. - */ + * call that accepts a dpp::message so you can send embeds. + */ event.reply("Blep! You chose " + animal); } }); - - /* The on_autocomplete event is fired whenever discord needs information to fill in a command options's choices. - * You must reply with a REST event within 500ms, so make it snappy! + + /* The on_autocomplete event is fired whenever Discord needs information to fill in a command options' choices. + * You must reply with a REST event within 500 ms, so make it snappy! */ bot.on_autocomplete([&bot](const dpp::autocomplete_t & event) { for (auto & opt : event.options) { @@ -51,7 +47,7 @@ int main() /* In a real world usage of this function you should return values that loosely match * opt.value, which contains what the user has typed so far. The opt.value is a variant * and will contain the type identical to that of the slash command parameter. - * Here we can safely know it is string. + * Here we can safely know it is a string. */ std::string uservalue = std::get(opt.value); bot.interaction_response_create(event.command.id, event.command.token, dpp::interaction_response(dpp::ir_autocomplete_reply) @@ -67,8 +63,6 @@ int main() }); bot.start(dpp::st_wait); - return 0; } -~~~~~~~~~~ - +~~~~~~~~~~ \ No newline at end of file diff --git a/docpages/example_programs/interactions_and_components/commandhandler.md b/docpages/example_programs/interactions_and_components/commandhandler.md index 140fc9aab3..7f9941d9ba 100644 --- a/docpages/example_programs/interactions_and_components/commandhandler.md +++ b/docpages/example_programs/interactions_and_components/commandhandler.md @@ -1,25 +1,19 @@ -\page commandhandler Using a command handler object +\page commandhandler Unified Message/Slash Command Handler -If you have many commands in your bot, and want to handle commands from multiple sources, you should consider instantiating a dpp::commandhandler object. This object can be used to automatically route -commands and their parameters to functions in your program. A simple example of using this object to route commands is shown below, and will -route both the /ping (global slash command) and .ping (prefixed channel message command) to a lambda where a reply can be generated. +If you have many commands in your bot, and want to handle commands from multiple sources, you should consider instantiating a dpp::commandhandler object. This object can be used to automatically route commands and their parameters to functions in your program. A simple example of using this object to route commands is shown below, and will route both the `/ping` (global slash command) and `.ping` (prefixed channel message command) to a lambda where a reply can be generated. \note This example automatically hooks the dpp::cluster::on_message_create and dpp::cluster::on_slashcommand events. This can be overridden if needed to allow you to still make use of these functions for your own code, if you need to do this please see the constructor documentation for dpp::commandhandler. -Note that because the dpp::commandhandler::add_command method accepts a `std::function` as the command handler, you may point a command handler -at a simple lambda (as shown in this example), a function pointer, or an instantiated class method of an object. This is extremely flexible -and allows you to decide how and where commands should be routed, either to an object oriented system or to a lambda based system. +Note that because the dpp::commandhandler::add_command method accepts a `std::function` as the command handler, you may point a command handler at a simple lambda (as shown in this example), a function pointer, or an instantiated class method of an object. This is extremely flexible and allows you to decide how and where commands should be routed, either to an object oriented system or to a lambda based system. \warning As of [August 30th, 2022](https://support-dev.discord.com/hc/en-us/articles/6025578854295-Why-We-Moved-to-Slash-Commands), you are advised to only be using slash commands, not messages for commands. To prevent the command handler from handling commands with messages, you should only use the "/" prefix. If you wish to still use messages for commands, this tutorial will still cover it but, again, it is discouraged by Discord. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp #include -int main() -{ +int main() { /* If your bot only uses the "/" prefix, you can remove the intents here. */ dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); - bot.on_log(dpp::utility::cout_logger()); /* Create command handler, and specify prefixes */ @@ -28,7 +22,6 @@ int main() command_handler.add_prefix(".").add_prefix("/"); bot.on_ready([&command_handler](const dpp::ready_t &event) { - command_handler.add_command( /* Command name */ "ping", @@ -59,12 +52,9 @@ int main() * that are registered already! */ command_handler.register_commands(); - }); bot.start(dpp::st_wait); - return 0; } -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \ No newline at end of file diff --git a/docpages/example_programs/interactions_and_components/components.md b/docpages/example_programs/interactions_and_components/components.md index dbdba23af1..c0e57c5fdf 100644 --- a/docpages/example_programs/interactions_and_components/components.md +++ b/docpages/example_programs/interactions_and_components/components.md @@ -1,25 +1,20 @@ -\page components Using button components +\page components Using Button Components -Discord's newest features support sending buttons alongside messages, which when clicked by the user trigger an interaction which is routed by -D++ as an `on_button_click` event. To make use of this, use this code as in this example. +Discord's newest features support sending buttons alongside messages, which when clicked by the user trigger an interaction which is routed by D++ as an `on_button_click` event. To make use of this, use this code as in this example. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp #include #include #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() == "button") { - /* Create a message */ dpp::message msg(event.command.channel_id, "this text has a button"); @@ -51,20 +46,17 @@ int main() { }); 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)); - } - }); + 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; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When the feature is functioning, the code below will produce buttons on the reply message like in the image below: -\image html button.png - +\image html button.png \ No newline at end of file diff --git a/docpages/example_programs/interactions_and_components/components2.md b/docpages/example_programs/interactions_and_components/components2.md index 1bc4ae8599..5adb587094 100644 --- a/docpages/example_programs/interactions_and_components/components2.md +++ b/docpages/example_programs/interactions_and_components/components2.md @@ -1,43 +1,42 @@ -\page components2 Advanced button components +\page components2 Advanced Button Components -This example demonstrates adding multiple buttons, receiving button clicks and sending response messages. +This example demonstrates adding multiple buttons, receiving button clicks, and sending response messages. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp #include int main() { - 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") { - + if (event.command.get_command_name() == "maths") { /* 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") - ) + 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. */ @@ -48,26 +47,24 @@ int main() { bot.on_button_click([&bot](const dpp::button_click_t & event) { if (event.custom_id == "10") { event.reply(dpp::message("You got it right!").set_flags(dpp::m_ephemeral)); - } else { + } + else { event.reply(dpp::message("Wrong! Try again.").set_flags(dpp::m_ephemeral)); } }); 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)); - } - }); + if (dpp::run_once()) { + /* Create and register a command when the bot is ready */ + bot.global_command_create(dpp::slashcommand("maths", "A quick maths question!", bot.me.id)); + } + }); bot.start(dpp::st_wait); - return 0; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This code will send a different message for correct and incorrect answers. -\image html button_2.png - +\image html button_2.png \ No newline at end of file diff --git a/docpages/example_programs/interactions_and_components/components3.md b/docpages/example_programs/interactions_and_components/components3.md index e368414a83..9c97fd3c4f 100644 --- a/docpages/example_programs/interactions_and_components/components3.md +++ b/docpages/example_programs/interactions_and_components/components3.md @@ -1,22 +1,18 @@ -\page components3 Using select menu components +\page components3 Using Select Menu Components -This example demonstrates creating a select menu, receiving select menu clicks and sending a response message. +This example demonstrates creating a select menu, receiving select menu clicks, and sending a response message. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp #include int main() { - 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() == "select") { - /* Create a message */ dpp::message msg(event.command.channel_id, "This text has a select menu!"); @@ -48,15 +44,13 @@ int main() { }); 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)); - } - }); + 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; } -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \ No newline at end of file diff --git a/docpages/example_programs/interactions_and_components/context_menus.md b/docpages/example_programs/interactions_and_components/context_menus.md index d810fcc0a0..fef650d432 100644 --- a/docpages/example_programs/interactions_and_components/context_menus.md +++ b/docpages/example_programs/interactions_and_components/context_menus.md @@ -1,6 +1,6 @@ \page context-menu Context Menus -Context menus are application commands that appear on the context menu (right click or tap) of users or messages to perform context-specific actions. They can be created using dpp::slashcommand. Once you create a context menu, try right-clicking either a user or message to see it in your server! +Context menus are application commands that appear on the context menu (right click or tap) of users or messages to perform context-specific actions. They can be created using the dpp::slashcommand. Once you create a context menu, try right-clicking either a user or message to see it in your server! \image html context_menu_user_command.png @@ -8,45 +8,39 @@ Context menus are application commands that appear on the context menu (right cl The following example shows how to create and handle **user context menus** for message context menus, read the notice above. -~~~~~~~~~~{.cpp} +~~~~~~~~~~cpp #include #include -int main() -{ - dpp::cluster bot("token"); - - bot.on_log(dpp::utility::cout_logger()); - - /* 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) { - - /* check if the context menu name is 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()); - } - }); - - bot.on_ready([&bot](const dpp::ready_t &event) { - if (dpp::run_once()) { - - /* Create the command */ - dpp::slashcommand command; - command.set_name("High Five"); - command.set_application_id(bot.me.id); - command.set_type(dpp::ctxm_user); - - /* Register the command */ - bot.guild_command_create(command, 857692897221033129); /* Replace this with the guild id you want */ - } - }); - - /* Start bot */ - bot.start(dpp::st_wait); - - return 0; +int main() { + dpp::cluster bot("token"); + bot.on_log(dpp::utility::cout_logger()); + + /* 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) { + /* check if the context menu name is 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()); + } + }); + + bot.on_ready([&bot](const dpp::ready_t &event) { + if (dpp::run_once()) { + /* Create the command */ + dpp::slashcommand command; + command.set_name("High Five"); + command.set_application_id(bot.me.id); + command.set_type(dpp::ctxm_user); + + /* Register the command */ + bot.guild_command_create(command, 857692897221033129); /* Replace this with the guild id you want */ + } + }); + + bot.start(dpp::st_wait); + return 0; } ~~~~~~~~~~ diff --git a/docpages/example_programs/interactions_and_components/detecting-messages.md b/docpages/example_programs/interactions_and_components/detecting-messages.md index a3278c85a5..4f2ee81a20 100644 --- a/docpages/example_programs/interactions_and_components/detecting-messages.md +++ b/docpages/example_programs/interactions_and_components/detecting-messages.md @@ -1,32 +1,29 @@ -\page detecting-messages Listening to messages +\page detecting-messages Listening to Messages Sometimes, you may want to listen out for a message, rather than a command. This could be used for many cases like a spam filter, a bot that would respond to movie quotes with gifs, or a chat bot! However, in this page, we'll be using this to create a moderation filter (detect bad words). \warning As of August 30th, 2022, Discord made Message Content a privileged intent. Whilst this means you can still use prefixed messages as commands, Discord does not encourage this and heavily suggests you use \ref slashcommands "slash commands". If you wish to create commands, use \ref slashcommands "slash commands", not messages. -~~~~~~~~~~{.cpp} +~~~~~~~~~~cpp #include -int main() -{ - /* Create the bot, but with our intents so we can use messages. */ +int main() { + /* Create the bot, but with our intents so we can use messages. */ dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); bot.on_log(dpp::utility::cout_logger()); - /* The event is fired when the bot detects a message in any server and any channel it has access to. */ - bot.on_message_create([&bot](const dpp::message_create_t& event) { - - /* See if the message contains the phrase we want to check for. - * If there's at least a single match, we reply and say it's not allowed. - */ - if (event.msg.content.find("bad word") != std::string::npos) { - event.reply("That is not allowed here. Please, mind your language!", true); - } - }); + /* The event is fired when the bot detects a message in any server and any channel it has access to. */ + bot.on_message_create([&bot](const dpp::message_create_t& event) { + /* See if the message contains the phrase we want to check for. + * If there's at least a single match, we reply and say it's not allowed. + */ + if (event.msg.content.find("bad word") != std::string::npos) { + event.reply("That is not allowed here. Please, mind your language!", true); + } + }); bot.start(dpp::st_wait); - return 0; } ~~~~~~~~~~ diff --git a/docpages/example_programs/interactions_and_components/modal_dialog_interactions.md b/docpages/example_programs/interactions_and_components/modal_dialogue_interactions.md similarity index 55% rename from docpages/example_programs/interactions_and_components/modal_dialog_interactions.md rename to docpages/example_programs/interactions_and_components/modal_dialogue_interactions.md index f9a99bcde6..9ac0d115f3 100644 --- a/docpages/example_programs/interactions_and_components/modal_dialog_interactions.md +++ b/docpages/example_programs/interactions_and_components/modal_dialogue_interactions.md @@ -1,23 +1,20 @@ -\page modal-dialog-interactions Modal Dialog Interactions +\page modal-dialog-interactions Modal Dialogue Interactions -Modal dialog interactions are a new Discord API feature that allow you to have pop-up windows which prompt the user to input information. Once the user has filled in this information, your program will receive an `on_form_submit` event which will contain the data which was input. You must use a slash command interaction response to submit your modal form data to Discord, via the `on_slashcommand` event. From here calling the `dialog` method of the `interaction_create_t` event object will trigger the dialog to appear. +Modal dialogue interactions are a new Discord API feature that allow you to have pop-up windows which prompt the user to input information. Once the user has filled in this information, your program will receive an `on_form_submit` event which will contain the data which was input. You must use a slash command interaction response to submit your modal form data to Discord, via the `on_slashcommand` event. From here calling the `dialog` method of the `interaction_create_t` event object will trigger the dialogue to appear. -Each dialog box may have up to five rows of input fields. The example below demonstrates a simple setup with just one text input: +Each dialogue box may have up to five rows of input fields. The example below demonstrates a simple setup with just one text input: -~~~~~~~~~~{.cpp} +~~~~~~~~~~cpp #include #include -int main(int argc, char const *argv[]) -{ +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_slashcommand([&bot](const dpp::slashcommand_t& event) { - /* Check for our /dialog command */ - if (event.command.get_command_name() == "dialog") { - + /* Check for our /dialogue command */ + if (event.command.get_command_name() == "dialogue") { /* Instantiate an interaction_modal_response object */ dpp::interaction_modal_response modal("my_modal", "Please enter stuff"); @@ -46,14 +43,13 @@ int main(int argc, char const *argv[]) set_text_style(dpp::text_paragraph) ); - /* Trigger the dialog box. All dialog boxes are ephemeral */ + /* Trigger the dialogue box. All dialogue boxes are ephemeral */ event.dialog(modal); } }); - /* This event handles form submission for the modal dialog we create above */ + /* This event handles form submission for the modal dialogue 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! */ @@ -67,20 +63,17 @@ int main(int argc, char const *argv[]) }); bot.on_ready([&](const dpp::ready_t & event) { - if (dpp::run_once()) { + 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.global_command_create(dpp::slashcommand("dialogue", "Make a modal dialogue box", bot.me.id)); } }); - /* Start bot */ - bot.start(dpp::st_wait); return 0; } ~~~~~~~~~~ -If you compile and run this program and wait for the global command to register, typing `/dialog` will present you with a dialog box like the one below: - -\image html modal_dialog.png +If you compile and run this program and wait for the global command to register, typing `/dialogue` will present you with a dialogue box like the one below: +\image html modal_dialog.png \ No newline at end of file diff --git a/docpages/example_programs/interactions_and_components/slashcommands.md b/docpages/example_programs/interactions_and_components/slashcommands.md index 57f3bac606..33d5d486c4 100644 --- a/docpages/example_programs/interactions_and_components/slashcommands.md +++ b/docpages/example_programs/interactions_and_components/slashcommands.md @@ -4,26 +4,23 @@ Slash commands and interactions are a newer feature of Discord which allow bot's 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 and 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. +\note dpp::cluster::global_bulk_command_create and 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. +When a user issues these commands the reply will arrive via the `on_slashcommand` event which you can hook into, 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. dpp::interaction_create_t::reply has two overloaded versions of the method, one of which accepts simple `std::string` replies, for basic text-only messages (if your message is 'ephemeral' you must use this) and one which accepts a dpp::message for more advanced replies. Please note that at present, Discord only supports a small subset of message and embed features within an interaction response object. This first example goes over creating a single command globally. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp #include -int main() -{ +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") { @@ -31,28 +28,26 @@ int main() 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. - */ + * 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.global_command_create(newcommand); + 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.global_command_create(newcommand); } }); @@ -64,18 +59,16 @@ int main() 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} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp #include -int main() -{ +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") { @@ -83,128 +76,120 @@ int main() 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. - */ + * 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 */ + 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} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp #include -int main() -{ +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") { + } + else if (event.command.get_command_name() == "pong") { event.reply("Ping!"); - } else if (event.command.get_command_name() == "ding") { + } + else if (event.command.get_command_name() == "ding") { event.reply("Dong!"); - } else if (event.command.get_command_name() == "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 }); + 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} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp #include -int main() -{ +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") { + } + else if (event.command.get_command_name() == "pong") { event.reply("Ping!"); - } else if (event.command.get_command_name() == "ding") { + } + else if (event.command.get_command_name() == "ding") { event.reply("Dong!"); - } else if (event.command.get_command_name() == "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); - + 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 +\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 command line 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/subcommands.md b/docpages/example_programs/interactions_and_components/subcommands.md index 250463332d..e967682f7b 100644 --- a/docpages/example_programs/interactions_and_components/subcommands.md +++ b/docpages/example_programs/interactions_and_components/subcommands.md @@ -1,15 +1,13 @@ -\page subcommands Using sub-commands in slash commands +\page subcommands Using Sub-Commands in Slash Commands This demonstrates how to use sub-commands within slash commands. Also shown below is an example of how to get a "resolved" parameter without having to use the cache or an extra API call. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp #include #include int main() { - dpp::cluster bot("token"); - bot.on_log(dpp::utility::cout_logger()); /* Executes on ready. */ @@ -49,7 +47,8 @@ int main() { subcommand.get_value(0) ); event.reply(user.get_mention() + " has now been turned into a dog."); - } else { + } + else { /* Reply if there were no options.. */ event.reply("No user specified"); } @@ -63,7 +62,8 @@ int main() { subcommand.get_value(0) ); event.reply(user.get_mention() + " has now been turned into a cat."); - } else { + } + else { /* Reply if there were no options.. */ event.reply("No user specified"); } @@ -72,7 +72,6 @@ int main() { }); bot.start(dpp::st_wait); - return 0; } -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \ 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 f971f20926..66ac22a553 100644 --- a/docpages/example_programs/interactions_and_components/upload_parameter.md +++ b/docpages/example_programs/interactions_and_components/upload_parameter.md @@ -1,27 +1,23 @@ -\page discord-application-command-file-upload Using file parameters for application commands (slash commands) +\page discord-application-command-file-upload Using File Parameters for Application Commands (Slash Commands) The program below demonstrates how to use the 'file' type parameter to an application command (slash command). -You must first get the file_id via `std::get`, and then you can find the attachment details in the 'resolved' +You must first get the `file_id` via `std::get`, and then you can find the attachment details in the 'resolved' section, `event.command.resolved`. The file is uploaded to Discord's CDN so if you need it locally you should fetch the `.url` value, e.g. by using something like dpp::cluster::request(). -~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~cpp #include -int main() -{ +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() == "show") { - /* Get the file id from the parameter attachment. */ dpp::snowflake file_id = std::get(event.get_parameter("file")); @@ -35,7 +31,6 @@ int main() 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); @@ -48,7 +43,6 @@ int main() }); bot.start(dpp::st_wait); - return 0; } -~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~ \ No newline at end of file diff --git a/docpages/example_programs/interactions_and_components/user-only-messages.md b/docpages/example_programs/interactions_and_components/user-only-messages.md index 36b182cfe2..3ba0e01384 100644 --- a/docpages/example_programs/interactions_and_components/user-only-messages.md +++ b/docpages/example_programs/interactions_and_components/user-only-messages.md @@ -1,40 +1,34 @@ -\page user-only-messages Ephemeral replies ('Only you can see this' replies) +\page user-only-messages Ephemeral Replies ('Only You Can See This' Replies) -If you've used a discord bot, there's a chance that you've encountered a message from one that said "Only you can see this" after you interacted with it (or executed a command). These messages are pretty helpful and can be used in many instances where you'd only like the user that's interacting to see what's going on. +If you've used a Discord bot, there's a chance that you've encountered a message from one that said "Only you can see this" after you interacted with it (or executed a command). These messages are pretty helpful and can be used in many instances where you'd only like the user that's interacting to see what's going on. Here's how you can do exactly that! -~~~~~~~~~~{.cpp} +~~~~~~~~~~cpp #include -int main() -{ - /* Create the bot */ +int main() { + /* Create the bot */ dpp::cluster bot("token"); - bot.on_log(dpp::utility::cout_logger()); - /* The event is fired when someone issues your commands */ + /* 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() == "hello") { - /* Reply to the user, but only let them see the response. */ event.reply(dpp::message("Hello! How are you today?").set_flags(dpp::m_ephemeral)); } }); bot.on_ready([&bot](const dpp::ready_t & event) { - if (dpp::run_once()) { - - /* Create and Register the command */ - bot.global_command_create(dpp::slashcommand("hello", "Hello there!", bot.me.id)); + if (dpp::run_once()) { + /* Create and Register the command */ + bot.global_command_create(dpp::slashcommand("hello", "Hello there!", bot.me.id)); } }); bot.start(dpp::st_wait); - return 0; } ~~~~~~~~~~ diff --git a/docpages/example_programs/misc.md b/docpages/example_programs/misc.md index b299a0595b..c63a9c83e6 100644 --- a/docpages/example_programs/misc.md +++ b/docpages/example_programs/misc.md @@ -2,9 +2,9 @@ This section lists examples that do not fit neatly into any of the categories above. -* \subpage making_a_http_request "Making arbitrary HTTP requests using D++" -* \subpage spdlog "Integrating with spdlog" -* \subpage caching-messages "Caching messages" -* \subpage collecting-reactions "Collecting Reactions" -* \subpage cpp-eval-command-discord "Making an eval command in C++" -* \subpage checking-member-permissions "Checking permissions" +* \subpage making_a_http_request +* \subpage spdlog +* \subpage caching-messages +* \subpage collecting-reactions +* \subpage cpp-eval-command-discord +* \subpage checking-member-permissions \ 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 865cedd8f5..a0ad57f6b9 100644 --- a/docpages/example_programs/misc/cache_messages.md +++ b/docpages/example_programs/misc/cache_messages.md @@ -4,11 +4,9 @@ By default D++ does not cache messages. The example program below demonstrates h This can be adjusted to cache any type derived from dpp::managed including types you define yourself. -@note This example will cache and hold onto messages forever! In a real world situation this would be bad. If you do use this, -you should use the dpp::cache::remove() method periodically to remove stale items. This is left out of this example as a learning -exercise to the reader. For further reading please see the documentation of dpp::cache +\note This example will cache and hold onto messages forever! In a real world situation this would be bad. If you do use this, you should use the dpp::cache::remove() method periodically to remove stale items. This is left out of this example as a learning exercise to the reader. For further reading please see the documentation of dpp::cache. -~~~~~~~~~~{.cpp} +~~~~~~~~~~cpp #include #include @@ -19,7 +17,7 @@ int main() { /* 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) { @@ -37,7 +35,6 @@ int main() { 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"))); /* If find_msg is null, tell the user and return. */ @@ -51,23 +48,19 @@ int main() { }); bot.on_ready([&bot](const dpp::ready_t& event) { - if (dpp::run_once()) { - + 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); - } - }); + /* Register the command */ + bot.global_command_create(newcommand); + } + }); - /* Start bot */ bot.start(dpp::st_wait); - return 0; } -~~~~~~~~~~ - +~~~~~~~~~~ \ No newline at end of file diff --git a/docpages/example_programs/the_basics/checking-member-permissions.md b/docpages/example_programs/misc/checking-member-permissions.md similarity index 69% rename from docpages/example_programs/the_basics/checking-member-permissions.md rename to docpages/example_programs/misc/checking-member-permissions.md index b10bdab43e..04641f3848 100644 --- a/docpages/example_programs/the_basics/checking-member-permissions.md +++ b/docpages/example_programs/misc/checking-member-permissions.md @@ -1,7 +1,6 @@ -\page checking-member-permissions Checking permissions +\page checking-member-permissions Checking Permissions -Of course most people do just iterate over the roles of a member to check for a permission. -But there's a helper method for that: dpp::guild::base_permissions gets a member's permission taking into account the server owner and role permissions. +Of course most people do just iterate over the roles of a member to check for a permission. But there's a helper method for that: dpp::guild::base_permissions gets a member's permission taking into account the server owner and role permissions. For total member permissions including channel overwrites use either the dpp::channel::get_user_permissions or dpp::guild::permission_overwrites method. Both do the same under the hood. @@ -12,17 +11,15 @@ Demonstration: ```cpp dpp::channel* c = dpp::find_channel(some_channel_id); if (c && c->get_user_permissions(member).can(dpp::p_send_messages)) { - //... + // … } ``` -## Permissions in Interaction events +## Permissions in Interaction Events ### Default Command Permissions -Discord's intended way to manage permissions for commands is through default member permissions. -You set them using dpp::slashcommand::set_default_permissions when creating or updating a command to set the default permissions a user must have to use it. -However, Server-Admins can then overwrite these permissions by their own restrictions. +Discord's intended way to manage permissions for commands is through default member permissions. You set them using dpp::slashcommand::set_default_permissions when creating or updating a command to set the default permissions a user must have to use it. However, server administrators can then overwrite these permissions by their own restrictions. The corresponding code to create a command with default permissions would look something like this: @@ -37,12 +34,9 @@ command.add_option(dpp::command_option(dpp::co_string, "reason", "The reason for bot.global_command_create(command); ``` -### Checking permissions on your own +### Checking Permissions on Your Own -If you want to check permissions on your own, the easiest way to check if a member has certain permissions in interaction events is by using the dpp::interaction::get_resolved_permission function. -The resolved list contains associated structures for the command and does not use the cache or require any extra API calls. -Note that the permissions in the resolved set are pre-calculated by discord and taking into account channel overwrites, roles and admin privileges. -So no need to loop through roles or stuff like that. +If you want to check permissions on your own, the easiest way to check if a member has certain permissions in interaction events is by using the dpp::interaction::get_resolved_permission function. The resolved list contains associated structures for the command and does not use the cache or require any extra API calls. Note that the permissions in the resolved set are pre-calculated by Discord and taking into account channel overwrites, roles and admin privileges. So no need to loop through roles or stuff like that. Let's imagine the following scenario: @@ -51,14 +45,14 @@ You have a ban command and want to make sure the issuer has the ban permission. ```cpp bot.on_interaction_create([](const dpp::interaction_create_t& event) { dpp::permission perms = event.command.get_resolved_permission(event.command.usr.id); - if (! perms.can(dpp::p_ban_members)) { + if (!perms.can(dpp::p_ban_members)) { event.reply("You don't have the required permissions to ban someone!"); return; } }); ``` -\note When using default permissions you don't necessarily need to check the issuing user for any permissions in the interaction event as Discord handles all that for you. But if you'd sleep better... +\note When using default permissions you don't necessarily need to check the issuing user for any permissions in the interaction event as Discord handles all that for you. But if you'd sleep better… ### From Parameters @@ -79,16 +73,15 @@ bot.on_interaction_create([](const dpp::interaction_create_t& event) { }); ``` -### The Bot's permissions +### The Bot's Permissions -You also might want to check if the bot itself has the ban permission before processing the command further. -You can access the bot's permissions in the dpp::interaction::app_permissions field. +You also might want to check if the bot itself has the ban permission before processing the command further. You can access the bot's permissions in the dpp::interaction::app_permissions field. ```cpp bot.on_interaction_create([](const dpp::interaction_create_t& event) { - if (! event.command.app_permissions.can(dpp::p_ban_members)) { + if (!event.command.app_permissions.can(dpp::p_ban_members)) { event.reply("The bot doesn't have the required permission to ban anyone!"); return; } }); -``` +``` \ No newline at end of file diff --git a/docpages/example_programs/misc/collect_reactions.md b/docpages/example_programs/misc/collect_reactions.md index 6a290e43d5..2dc4826c05 100644 --- a/docpages/example_programs/misc/collect_reactions.md +++ b/docpages/example_programs/misc/collect_reactions.md @@ -1,10 +1,10 @@ \page collecting-reactions Collecting Reactions -D++ comes with many useful helper classes, but amongst these is something called dpp::collector. Collector is a template which can be specialised to automatically collect objects of a pre-determined type from events for a specific interval of time. Once this time period is up, or the class is otherwise signalled, a method is called with the complete set of collected objects. +D++ comes with many useful helper classes, but amongst these is something called dpp::collector. Collector is a template which can be specialised to automatically collect objects of a predetermined type from events for a specific interval of time. Once this time period is up, or the class is otherwise signalled, a method is called with the complete set of collected objects. In the example below we will use it to collect all reactions on a message. -~~~~~~~~~~{.cpp} +~~~~~~~~~~cpp #include /* To create a collector we must derive from dpp::collector. As dpp::collector is a complicated template, @@ -13,19 +13,19 @@ In the example below we will use it to collect all reactions on a message. class react_collector : public dpp::reaction_collector { public: /* Collector will run for 20 seconds */ - react_collector(dpp::cluster* cl, snowflake id) : dpp::reaction_collector(cl, 20, id) { } + react_collector(dpp::cluster* cl, snowflake id) : dpp::reaction_collector(cl, 20, id) {} /* Override the "completed" event and then output the number of collected reactions as a message. */ virtual void completed(const std::vector& list) override { if (list.size()) { owner->message_create(dpp::message(list[0].react_channel->id, "I collected " + std::to_string(list.size()) + " reactions!")); - } else { - owner->message_create(dpp::message("... I got nothin'.")); + } + else { + owner->message_create(dpp::message("… I got nothin'.")); } } }; - int main() { /* Create bot */ dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); @@ -33,23 +33,19 @@ int main() { /* Pointer to reaction collector */ react_collector* r = nullptr; - 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) { - /* If someone sends a message that has the text 'collect reactions!' start a reaction collector */ if (event.msg.content == "collect reactions!" && r == nullptr) { /* Create a new reaction collector to collect reactions */ r = new react_collector(&bot, event.msg.id); } - }); /* Start bot */ bot.start(dpp::st_wait); - return 0; } -~~~~~~~~~~ - +~~~~~~~~~~ \ No newline at end of file diff --git a/docpages/example_programs/misc/eval.md b/docpages/example_programs/misc/eval.md index 6f65bb300f..d56592d3d7 100644 --- a/docpages/example_programs/misc/eval.md +++ b/docpages/example_programs/misc/eval.md @@ -1,37 +1,34 @@ -\page cpp-eval-command-discord Making an eval command in C++ +\page cpp-eval-command-discord Making an eval Command in C++ -### What is an eval command anyway? +## What is an eval command anyway? -Many times people will ask: "How do I make a command like 'eval' in C++?". For the uninitiated, an `eval` command is a command often found in interpreted languages such as Javascript and Python, which allows the developer to pass in raw interpreter statements which are then executed within the context of the running program, without any sandboxing. Eval commands are plain **evil**, if not properly coded in. +Many times people will ask: "How do I make a command like 'eval' in C++?". For the uninitiated, an `eval` command is a command often found in interpreted languages such as JavaScript and Python, which allows the developer to pass in raw interpreter statements which are then executed within the context of the running program, without any sandboxing. Eval commands are plain **evil**, if not properly coded in. Needless to say, this is very dangerous. If you are asking how to do this, and want to put this into your bot, we trust that you have a very good reason to do so and have considered alternatives before resorting to this. The code below is for educational purposes only and makes several assumptions: -1. This code will only operate on UNIX-like systems such as Linux (not **Darwin**) -2. It assumes you use GCC, and have `g++` installed on your server and in your $PATH -3. The program will attempt to write to the current directory +1. This code will only operate on UNIX-like systems such as Linux (not **Darwin**). +2. It assumes you use GCC, and have `g++` installed on your server and in your `${PATH}`. +3. The program will attempt to write to the current directory. 4. No security checks will be done against the code, except for to check that it is being run by the bot's developer by snowflake id. It is entirely possible to send an `!eval exit(0);` and make the bot quit, for example, or delete files from the host operating system, if misused or misconfigured. 5. You're willing to wait a few seconds for compilation before your evaluated code runs. There isn't a way around this, as C++ is a compiled language. -To create this program you must create two files, `eval.h` and `eval.cpp`. The header file lists forward declarations of functions that you will be able to use directly within your `eval` code. As well as this the entire of D++ will be available to the eval command via the local variable `bot`, and the entire `on_message_create` event variable via a local variable called `event`. +To create this program you must create two files, `eval.h` and `eval.cpp`. The header file lists forward declarations of functions that you will be able to use directly within your `eval` code. As well as this the entirety of D++ will be available to the eval command via the local variable `bot`, and the entire `on_message_create` event variable via a local variable called `event`. The evaluated code will run within its own thread, so can execute for as long as it needs (but use common sense, don't go spawning a tight `while` loop that runs forever, you'll lock a thread at 100% CPU that won't ever end!). -### Implementation details +## Implementation Details -This code operates by outputting your provided code to be evaluated into a simple boilerplate program which can be compiled to a -shared object library (`.so`) file. This `.so` file is then compiled with `g++`, using the `-shared` and `-fPIC` flags. If the program can be successfully compiled, it is then loaded using `dlopen()`, and the symbol `so_exec()` searched for within it, and called. This `so_exec()` function will contain the body of the code given to the eval command. Once this has been called and it has returned, -the `dlclose()` function is called to unload the library, and finally any temporary files (such as the `.so` file and its corresponding `.cpp` file) are cleaned up. -Docker is definitely recommended if you code on Windows/Mac OS, because docker desktop still uses a linux VM, so your code can easily use `.so` file and your code runs the same on your vps (if it also uses Linux distro) +This code operates by outputting your provided code to be evaluated into a simple boilerplate program which can be compiled to a shared object library (`.so`) file. This `.so` file is then compiled with `g++`, using the `-shared` and `-fPIC` flags. If the program can be successfully compiled, it is then loaded using `dlopen()`, and the symbol `so_exec()` searched for within it, and called. This `so_exec()` function will contain the body of the code given to the eval command. Once this has been called and it has returned, the `dlclose()` function is called to unload the library, and finally any temporary files (such as the `.so` file and its corresponding `.cpp` file) are cleaned up. Docker is definitely recommended if you code on Windows/macOS, because Docker desktop still uses a Linux VM, so your code can easily use the `.so` file and your code runs the same on your VPS (if it also uses Linux distro). -### Source code +## Source code \warning If you manage to get your system, network, or anything else harmed by use or misuse of this code, we are not responsible. Don't say we didn't warn you! Find another way to solve your problem! -#### eval.h +### eval.h Remember that `eval.h` contains forward-declarations of any functions you want to expose to the eval command. It is included both by the bot itself, and by any shared object files compiled for evaluation. -~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~cpp #pragma once /* This is the snowflake ID of the bot's developer. @@ -44,15 +41,14 @@ Remember that `eval.h` contains forward-declarations of any functions you want t * can put here as forward declarations. The test_function() * serves as an example. */ - int test_function(); ~~~~~~~~~~~~~~~~ -#### eval.cpp +### eval.cpp This is the main body of the example program. -~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~cpp /** * D++ eval command example. * This is dangerous and for educational use only, here be dragons! @@ -64,7 +60,7 @@ This is the main body of the example program. #include /* We have to define this to make certain functions visible */ #ifndef _GNU_SOURCE - #define _GNU_SOURCE + #define _GNU_SOURCE #endif #include #include @@ -76,23 +72,20 @@ int test_function() { } /* Important: This code is for UNIX-like systems only, e.g. - * Linux, BSD, OSX. It will NOT work on Windows! - * Note for OSX you'll probably have to change all references + * Linux, BSD, macOS. It will NOT work on Windows! + * Note for macOS you'll probably have to change all references * from .so to .dylib. */ -int main() -{ +int main() { dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); - - bot.on_log(dpp::utility::cout_logger()); + bot.on_log(dpp::utility::cout_logger()); /* This won't work in a slash command very well yet, as there is not yet * a multi-line slash command input type. */ bot.on_message_create([&bot](const auto & event) { if (dpp::utility::utf8substr(event.msg.content, 0, 5) == "!eval") { - - /** + /** * THIS IS CRITICALLY IMPORTANT! * Never EVER make an eval command that isn't restricted to a specific developer by user id. * With access to this command the person who invokes it has at best full control over @@ -101,7 +94,7 @@ int main() * vulnerability. YOU HAVE BEEN WARNED! */ if (event.msg.author.id != MY_DEVELOPER) { - bot.message_create(dpp::message(event.msg.channel_id, "On the day i do this for you, Satan will be ice skating to work.")); + bot.message_create(dpp::message(event.msg.channel_id, "On the day I do this for you, Satan will be ice skating to work.")); return; } @@ -109,29 +102,29 @@ int main() * The library will contain one exported function called so_exec() that is called * containing the raw C++ code to eval. */ - std::string code = "#include \n\ - #include \n\ - #include \n\ - #include \n\ - #include \n\ - #include \n\ - #include \n\ - #include \n\ - #include \"eval.h\"\n\ - extern \"C\" void so_exec(dpp::cluster& bot, dpp::message_create_t event) {\n\ - " + dpp::utility::utf8substr( + std::string code = "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \n" + "#include \"eval.h\"\n" + "extern \"C\" void so_exec(dpp::cluster& bot, dpp::message_create_t event) {\n" + + dpp::utility::utf8substr( event.msg.content, 6, dpp::utility::utf8len(event.msg.content) - ) + ";\n\ - return;\n\ - }"; + ) + ";\n" + "return;\n" + "}"; /* Next we output this string full of C++ to a cpp file on disk. * This code assumes the current directory is writeable. The file will have a * unique name made from the user's id and the message id. */ - std::string source_filename = std::to_string(event.msg.author.id) + "_" + std::to_string(event.msg.id) + ".cpp"; + std::string source_filename = std::to_string(event.msg.author.id) + "_" + std::to_string(event.msg.id) + ".cpp"; std::fstream code_file(source_filename, std::fstream::binary | std::fstream::out); if (!code_file.is_open()) { bot.message_create(dpp::message(event.msg.channel_id, "Unable to create source file for `eval`")); @@ -146,7 +139,7 @@ int main() double compile_start = dpp::utility::time_f(); dpp::utility::exec("g++", { "-std=c++17", - "-shared", /* Build the output as a .so file */ + "-shared", /* Build the output as a .so file */ "-fPIC", std::string("-o") + std::to_string(event.msg.author.id) + "_" + std::to_string(event.msg.id) + ".so", std::to_string(event.msg.author.id) + "_" + std::to_string(event.msg.id) + ".cpp", @@ -164,8 +157,8 @@ int main() /* On successful compilation g++ outputs nothing, so any output here is error output */ if (output.length()) { bot.message_create(dpp::message(event.msg.channel_id, "Compile error: ```\n" + output + "\n```")); - } else { - + } + else { /* Now for the meat of the function. To actually load * our shared object we use dlopen() to load it into the * memory space of our bot. If dlopen() returns a nullptr, @@ -203,7 +196,7 @@ int main() } /* Now we have a function pointer to our actual exec code in - * 'exec_run', so lets call it, and pass it a reference to + * 'exec_run', so let's call it, and pass it a reference to * the cluster, and also a copy of the message_create_t. */ double run_start = dpp::utility::time_f(); @@ -230,15 +223,14 @@ int main() } ~~~~~~~~~~~~~~~~ -### Compilation +## Compilation To compile this program you must link against `libdl`. It is also critically important to include the `-rdynamic` flag. For example: -``` +```bash g++ -std=c++17 -rdynamic -oeval eval.cpp -ldpp -ldl ``` -### Example usage - -\image html eval_example.png +## Example usage +\image html eval_example.png \ No newline at end of file diff --git a/docpages/example_programs/misc/http_request.md b/docpages/example_programs/misc/http_request.md index ff01ba5e0c..cc1e7d67ef 100644 --- a/docpages/example_programs/misc/http_request.md +++ b/docpages/example_programs/misc/http_request.md @@ -1,13 +1,12 @@ -\page making_a_http_request Making arbitrary HTTP requests using D++ +\page making_a_http_request Making Arbitrary HTTP Requests Using D++ If you wish to make arbitrary HTTP(S) requests to websites and APIs, e.g. to update statistics on bot lists, you can use code similar to the code below. You may pass any arbitrary POST data: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp #include int main() { dpp::cluster bot("TOKEN GOES HERE"); - bot.on_log(dpp::utility::cout_logger()); bot.on_ready([&bot](const dpp::ready_t& event) { @@ -23,11 +22,12 @@ int main() { mypostdata, "application/json", { - {"Authorization", "Bearer tokengoeshere"} + {"Authorization", "Bearer token goes here"} } ); }); bot.start(dpp::st_wait); + return 0; } -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \ No newline at end of file diff --git a/docpages/example_programs/misc/spdlog.md b/docpages/example_programs/misc/spdlog.md index 9edeb7a226..43e4170b39 100644 --- a/docpages/example_programs/misc/spdlog.md +++ b/docpages/example_programs/misc/spdlog.md @@ -1,8 +1,8 @@ \page spdlog Integrating with spdlog -If you want to make your bot use spdlog, like aegis does, you can attach it to the on_log event. You can do this as follows: +If you want to make your bot use spdlog, like aegis does, you can attach it to the `on_log` event. You can do this as follows: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp #include #include #include @@ -11,8 +11,7 @@ If you want to make your bot use spdlog, like aegis does, you can attach it to t #include #include -int main(int argc, char const *argv[]) -{ +int main(int argc, char const *argv[]) { dpp::cluster bot("token"); const std::string log_name = "mybot.log"; @@ -35,23 +34,23 @@ int main(int argc, char const *argv[]) switch (event.severity) { case dpp::ll_trace: log->trace("{}", event.message); - break; + break; case dpp::ll_debug: log->debug("{}", event.message); - break; + break; case dpp::ll_info: log->info("{}", event.message); - break; + break; case dpp::ll_warning: log->warn("{}", event.message); - break; + break; case dpp::ll_error: log->error("{}", event.message); - break; + break; case dpp::ll_critical: default: log->critical("{}", event.message); - break; + break; } }); @@ -60,4 +59,4 @@ int main(int argc, char const *argv[]) bot.start(dpp::st_wait); return 0; } -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \ No newline at end of file diff --git a/docpages/example_programs/music_and_audio.md b/docpages/example_programs/music_and_audio.md index 5c222df106..dfe254ca05 100644 --- a/docpages/example_programs/music_and_audio.md +++ b/docpages/example_programs/music_and_audio.md @@ -2,8 +2,8 @@ If you want to make noise, or capture noise, you're in the right place. You'll find examples here for creating basic music bots, or recording voice, amongst other things. -* \subpage soundboard "Creating a Sound Board" -* \subpage oggopus "Streaming Ogg Opus file" -* \subpage stream-mp3-discord-bot "Streaming MP3 files" -* \subpage record-user "Record yourself in a VC" -* \subpage joinvc "Join or switch to the voice channel of the user issuing a command" +* \subpage soundboard +* \subpage oggopus +* \subpage stream-mp3-discord-bot +* \subpage record-user +* \subpage joinvc \ No newline at end of file diff --git a/docpages/example_programs/music_and_audio/join_voice.md b/docpages/example_programs/music_and_audio/join_voice.md index 2e0920e64f..41e78f8c7c 100644 --- a/docpages/example_programs/music_and_audio/join_voice.md +++ b/docpages/example_programs/music_and_audio/join_voice.md @@ -1,27 +1,23 @@ -\page joinvc Join or switch to the voice channel of the user issuing a command +\page joinvc Join or Switch to the Voice Channel of the User Issuing a Command When a user issues a command you may want to join their voice channel, e.g. in a music bot. If you are already on the same voice channel, the bot should do nothing (but be ready to instantly play audio) and if the user is on a different voice channel, the bot should switch to it. If the user is on no voice channel at all, this should be considered an error. This example shows how to do this. \note Please be aware this example sends no audio, but indicates clearly in the comments where and how you should do so. -~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~~~cpp #include #include #include -int main(int argc, char const *argv[]) -{ +int main(int argc, char const *argv[]) { /* Setup the bot */ 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() == "join") { - /* Get the guild */ dpp::guild* g = dpp::find_guild(event.command.guild_id); @@ -39,10 +35,10 @@ int main(int argc, char const *argv[]) 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(...) + * current_vc->send_audio_raw(…) */ - } else { + } + else { /* We are on a different voice channel. We should leave it, then join the new one * by falling through to the join_vc branch below. */ @@ -65,7 +61,7 @@ int main(int argc, char const *argv[]) /* 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(...); + * 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! @@ -73,15 +69,15 @@ int main(int argc, char const *argv[]) /* 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!"); + } + 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)); } @@ -89,8 +85,6 @@ int main(int argc, char const *argv[]) /* Start bot */ bot.start(dpp::st_wait); - return 0; } - ~~~~~~~~~~~~~~~~~~~~~~~~~ \ No newline at end of file diff --git a/docpages/example_programs/music_and_audio/mp3.md b/docpages/example_programs/music_and_audio/mp3.md index a6181a75d2..cc5b64f650 100644 --- a/docpages/example_programs/music_and_audio/mp3.md +++ b/docpages/example_programs/music_and_audio/mp3.md @@ -1,15 +1,13 @@ -\page stream-mp3-discord-bot Streaming MP3 files +\page stream-mp3-discord-bot Streaming MP3 Files To stream MP3 files via D++ you need to link an additional dependency to your bot, namely `libmpg123`. It is relatively simple when linking this library to your bot to then decode audio to PCM and send it to the dpp::discord_voice_client::send_audio_raw function as shown below: - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~cpp #include #include #include #include #include - #include #include #include @@ -19,12 +17,11 @@ To stream MP3 files via D++ you need to link an additional dependency to your bo /* For an example we will hardcode a path to some awesome music here */ #define MUSIC_FILE "/media/music/Rick Astley/Whenever You Need Somebody/Never Gonna Give You Up.mp3" -int main(int argc, char const *argv[]) -{ +int main(int argc, char const *argv[]) { /* This will hold the decoded MP3. - * The D++ library expects PCM format, which are raw sound - * data, 2 channel stereo, 16 bit signed 48000Hz. - */ + * The D++ library expects PCM format, which are raw sound + * data, 2 channel stereo, 16 bit signed 48000 Hz. + */ std::vector pcmdata; mpg123_init(); @@ -39,10 +36,10 @@ int main(int argc, char const *argv[]) mpg123_handle *mh = mpg123_new(NULL, &err); mpg123_param(mh, MPG123_FORCE_RATE, 48000, 48000.0); - /* Decode entire file into a vector. You could do this on the fly, but if you do that - * you may get timing issues if your CPU is busy at the time and you are streaming to - * a lot of channels/guilds. - */ + /* Decode the entire file into a vector. You could do this on the fly, but if you do that + * you may get timing issues if your CPU is busy at the time and you are streaming to + * a lot of channels/guilds. + */ buffer_size = mpg123_outblock(mh); buffer = new unsigned char[buffer_size]; @@ -65,7 +62,7 @@ int main(int argc, char const *argv[]) /* Setup the bot */ 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, &pcmdata](const dpp::slashcommand_t& event) { @@ -84,7 +81,8 @@ int main(int argc, char const *argv[]) /* Tell the user we joined their channel. */ event.reply("Joined your channel!"); - } else if (event.command.get_command_name() == "mp3") { + } + 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); @@ -126,5 +124,6 @@ int main(int argc, char const *argv[]) To compile this program you must remember to specify `libmpg123` alongside `libdpp` in the build command, for example: -` g++ -std=c++17 -o musictest musictest.cpp -lmpg123 -ldpp` - +```bash +g++ -std=c++17 -o musictest musictest.cpp -lmpg123 -ldpp +``` \ No newline at end of file diff --git a/docpages/example_programs/music_and_audio/oggopus.md b/docpages/example_programs/music_and_audio/oggopus.md index 991597b6c5..22d2973794 100644 --- a/docpages/example_programs/music_and_audio/oggopus.md +++ b/docpages/example_programs/music_and_audio/oggopus.md @@ -2,36 +2,31 @@ This example shows how to stream an Ogg Opus file to a voice channel. This example requires some additional dependencies, namely `libogg` and `opusfile`. -~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~~~cpp #include #include #include - #include #include #include #include #include -int main(int argc, char const *argv[]) -{ +int main(int argc, char const *argv[]) { /* Load an ogg opus file into memory. - * The bot expects opus packets to be 2 channel stereo, 48000Hz. + * The bot expects opus packets to be 2 channel stereo, 48000 Hz. * * 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"); - - 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() == "join") { - /* Get the guild */ dpp::guild* g = dpp::find_guild(event.command.guild_id); @@ -43,7 +38,8 @@ int main(int argc, char const *argv[]) /* Tell the user we joined their channel. */ event.reply("Joined your channel!"); - } else if (event.command.get_command_name() == "play") { + } + 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); @@ -80,9 +76,9 @@ int main(int argc, char const *argv[]) ogg_sync_wrote(&oy, sz); /** - * We must first verify that the stream is indeed ogg opus - * by reading the header and parsing it - */ + * 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); @@ -115,11 +111,11 @@ int main(int argc, char const *argv[]) /* 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"); + fprintf(stderr,"Wrong encoding for Discord, must be 48000 Hz sample rate with 2 channels.\n"); exit(1); } - /* Now loop though all the pages and send the packets to the vc */ + /* Now loop through 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)); @@ -139,7 +135,7 @@ int main(int argc, char const *argv[]) } 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"); + fprintf(stderr,"Wrong encoding for Discord, must be 48000 Hz sample rate with 2 channels.\n"); exit(1); } @@ -177,53 +173,45 @@ int main(int argc, char const *argv[]) } }); - /* Start bot */ bot.start(dpp::st_wait); - return 0; } ~~~~~~~~~~~~~~~~~~~~~~~~~ You can compile this example using the following command - c++ /path/to/source.cc -ldpp -lopus -lopusfile -logg -I/usr/include/opus +```bash +c++ /path/to/source.cc -ldpp -lopus -lopusfile -logg -I/usr/include/opus +``` ## Using liboggz -You can use `liboggz` to stream an Ogg Opus file to discord voice channel. -`liboggz` provides higher level abstraction and useful APIs. Some features `liboggz` provides include: seeking and timestamp interpretation. -Read more on the [documentation](https://www.xiph.org/oggz/doc/). +You can use `liboggz` to stream an Ogg Opus file to Discord voice channel. `liboggz` provides higher level abstraction and useful APIs. Some features `liboggz` provides include: seeking and timestamp interpretation. Read more on the [documentation](https://www.xiph.org/oggz/doc/). -~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~~~cpp #include #include #include - #include #include #include #include -int main(int argc, char const *argv[]) -{ +int main(int argc, char const *argv[]) { /* Load an ogg opus file into memory. - * The bot expects opus packets to be 2 channel stereo, 48000Hz. + * The bot expects opus packets to be 2 channel stereo, 48000 Hz. * * 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 */ - /* Setup the bot */ 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() == "join") { - /* Get the guild */ dpp::guild* g = dpp::find_guild(event.command.guild_id); @@ -235,7 +223,8 @@ int main(int argc, char const *argv[]) /* Tell the user we joined their channel. */ event.reply("Joined your channel!"); - } else if (event.command.get_command_name() == "play") { + } + 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); @@ -283,9 +272,10 @@ int main(int argc, char const *argv[]) const long read_bytes = oggz_read(track_og, CHUNK_READ); - // break on eof - if (!read_bytes) + // break on EOF + if (!read_bytes) { break; + } } // don't forget to free the memory @@ -297,7 +287,6 @@ 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 joincommand("join", "Joins your voice channel.", bot.me.id); @@ -306,14 +295,14 @@ int main(int argc, char const *argv[]) 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 \ No newline at end of file +```bash +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 f80f53f38e..cd32a09dc3 100644 --- a/docpages/example_programs/music_and_audio/record_user.md +++ b/docpages/example_programs/music_and_audio/record_user.md @@ -1,21 +1,20 @@ -\page record-user Record yourself in a VC +\page record-user Record Yourself in a VC -DPP supports receiving audio. This examples show how to use it to record some user in a VC. +D++ supports receiving audio. This example shows how to use it to record some user in a VC. \note Voice receiving by bots is not officially supported by the Discord API. We cannot guarantee that this feature will work in the future. -~~~~~~~~~~{.cpp} +~~~~~~~~~~cpp #include #include #include -int main(int argc, char const *argv[]) -{ +int main(int argc, char const *argv[]) { /* Example to record a user in a VC - * - * Recording is output as './me.pcm' and you can play it via the soundboard example - * or use ffmpeg 'ffplay -f s16le -ar 48000 -ac 2 -i ./me.pcm' - */ + * + * Recording is output as './me.pcm' and you can play it via the soundboard example + * or use ffmpeg 'ffplay -f s16le -ar 48000 -ac 2 -i ./me.pcm' + */ /* Replace with the user's id you wish to record */ dpp::snowflake user_id = 407877550216314882; @@ -26,14 +25,12 @@ int main(int argc, char const *argv[]) FILE *fd; fd = fopen("./me.pcm", "wb"); - 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, &fd](const dpp::slashcommand_t& event) { - /* Check which command they ran */ if (event.command.get_command_name() == "record") { - /* Get the guild */ dpp::guild* g = dpp::find_guild(event.command.guild_id); @@ -45,8 +42,8 @@ int main(int argc, char const *argv[]) /* Tell the user we joined their channel. */ event.reply("Joined your channel, now recording!"); - } else if (event.command.get_command_name() == "stop") { - + } + else if (event.command.get_command_name() == "stop") { event.from->disconnect_voice(event.command.guild_id); fclose(fd); @@ -62,7 +59,6 @@ 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); @@ -74,8 +70,6 @@ int main(int argc, char const *argv[]) /* Start bot */ bot.start(dpp::st_wait); - return 0; } -~~~~~~~~~~ - +~~~~~~~~~~ \ No newline at end of file diff --git a/docpages/example_programs/music_and_audio/soundboard.md b/docpages/example_programs/music_and_audio/soundboard.md index 88d6940b6e..024dbf4e71 100644 --- a/docpages/example_programs/music_and_audio/soundboard.md +++ b/docpages/example_programs/music_and_audio/soundboard.md @@ -1,28 +1,27 @@ \page soundboard Creating a Sound Board -This example script shows how to send a sound file to a voice channel. A few shortcuts are taken here, for more advanced techniques for connecting to a voice channel see the tutorial \ref joinvc +This example script shows how to send a sound file to a voice channel. A few shortcuts are taken here, for more advanced techniques for connecting to a voice channel see the tutorial \ref joinvc . -~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~cpp #include #include #include -int main(int argc, char const *argv[]) -{ +int main(int argc, char const *argv[]) { /* Load a sound file called Robot.pcm into memory. * The bot expects PCM format, which are raw sound data, - * 2 channel stereo, 16 bit signed 48000Hz. + * 2 channel stereo, 16 bit signed 48000 Hz. * - * You can use audacity to export these from WAV or MP3 etc. + * You can use Audacity to export these from WAV or MP3 etc. * * If you wanted to send a more complicated format, you could * use a separate library to decode that audio to PCM. For * example purposes, a raw PCM will suffice. This PCM file can - * be found within the bot's github repo. + * be found within the bot's GitHub repo. */ uint8_t* robot = nullptr; size_t robot_size = 0; - std::ifstream input ("../testdata/Robot.pcm", std::ios::in|std::ios::binary|std::ios::ate); + std::ifstream input ("../testdata/Robot.pcm", std::ios::in | std::ios::binary | std::ios::ate); if (input.is_open()) { robot_size = input.tellg(); robot = new uint8_t[robot_size]; @@ -33,15 +32,12 @@ int main(int argc, char const *argv[]) /* Setup the bot */ 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, robot, robot_size](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); @@ -53,8 +49,8 @@ int main(int argc, char const *argv[]) /* Tell the user we joined their channel. */ event.reply("Joined your channel!"); - } else if (event.command.get_command_name() == "robot") { - + } + 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); @@ -73,7 +69,6 @@ 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 joincommand("join", "Joins your voice channel.", bot.me.id); @@ -85,7 +80,6 @@ int main(int argc, char const *argv[]) /* Start bot */ bot.start(dpp::st_wait); - return 0; } ~~~~~~~~~~~~~~~~~~~~~~~ \ No newline at end of file diff --git a/docpages/example_programs/the_basics.md b/docpages/example_programs/the_basics.md index c5c430977b..f6b588b79a 100644 --- a/docpages/example_programs/the_basics.md +++ b/docpages/example_programs/the_basics.md @@ -2,7 +2,7 @@ These example programs are great to get started with simple things in the D++ library, ideal for beginners to the language or to the Discord API. -* \subpage firstbot "Creating Your First Bot" -* \subpage embed-message "Sending Embeds" -* \subpage attach-file "Attaching a file" -* \subpage webhooks "Webhooks" +* \subpage firstbot +* \subpage embed-message +* \subpage attach-file +* \subpage webhooks \ 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 a6a398a119..9de82cf0de 100644 --- a/docpages/example_programs/the_basics/attachments.md +++ b/docpages/example_programs/the_basics/attachments.md @@ -1,4 +1,4 @@ -\page attach-file Attaching a file to a message +\page attach-file Attaching a File to a Message Attached files must be locally stored. @@ -8,90 +8,81 @@ D++ has this helper function to read a file: dpp::utility::read_file. An example program: -~~~~~~~~~~{.cpp} +~~~~~~~~~~cpp #include int main() { - dpp::cluster bot("token"); + 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 */ + /* 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") { + 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 */ - msg.add_file("foobar.txt", dpp::utility::read_file("path_to_your_file.txt")); + /* attach the file to the message */ + msg.add_file("foobar.txt", dpp::utility::read_file("path_to_your_file.txt")); /* 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); + 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)); + } + }); - return 0; + bot.start(dpp::st_wait); + return 0; } ~~~~~~~~~~ -Attachments via an url aren't possible. But there's a workaround for. You can download the file and then attach it to the message. +Attachments via an URL aren't possible. But there's a workaround for that. You can download the file and then attach it to the message. To make requests, D++ also has a helper function: dpp::cluster::request. The following example program shows how to request a file and attach it to a message. -~~~~~~~~~~{.cpp} +~~~~~~~~~~cpp #include int main() { - dpp::cluster bot("token"); - - bot.on_log(dpp::utility::cout_logger()); + dpp::cluster bot("token"); + bot.on_log(dpp::utility::cout_logger()); - /* The event is fired when someone issues your commands */ + /* 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") { - - /* 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) { - - /* 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, with our attachment. */ - event.reply(msg); - }); + /* 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) { + /* 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, 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); + 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)); + } + }); - return 0; + bot.start(dpp::st_wait); + return 0; } ~~~~~~~~~~ @@ -99,46 +90,42 @@ Here's another example of how to add a local image to an embed. Upload the image in the same message as the embed and then reference it in the embed. -~~~~~~~~~~{.cpp} +~~~~~~~~~~cpp #include int main() { - dpp::cluster bot("token"); + 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 */ + /* 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, ""); - /* Create a message. */ - dpp::message msg(event.msg.channel_id, ""); - - /* Attach the image to the message we just created. */ - msg.add_file("image.jpg", dpp::utility::read_file("path_to_your_image.jpg")); + /* 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"); /* Set the image of the embed to the attached image. */ + /* Create an embed. */ + dpp::embed embed; + 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); + /* Add the embed to the message. */ + msg.add_embed(embed); - event.reply(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); + 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)); + } + }); - return 0; + bot.start(dpp::st_wait); + return 0; } -~~~~~~~~~~ +~~~~~~~~~~ \ No newline at end of file diff --git a/docpages/example_programs/the_basics/embeds.md b/docpages/example_programs/the_basics/embeds.md index aad11535a8..4a3efdda33 100644 --- a/docpages/example_programs/the_basics/embeds.md +++ b/docpages/example_programs/the_basics/embeds.md @@ -2,43 +2,43 @@ 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 message type, 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} +~~~~~~~~~~cpp #include int main() { - /* Setup the bot */ - dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); + /* Setup the bot */ + dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); - /* The event is fired when someone issues your commands */ + /* 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 an embed */ - dpp::embed embed = dpp::embed(). - set_color(dpp::colors::sti_blue). - set_title("Some name"). - set_url("https://dpp.dev/"). - set_author("Some name", "https://dpp.dev/", "https://dpp.dev/DPP-Logo.png"). - set_description("Some description here"). - set_thumbnail("https://dpp.dev/DPP-Logo.png"). - add_field( - "Regular field title", - "Some value here" - ). - add_field( - "Inline field title", - "Some value here", - true - ). - add_field( - "Inline field title", - "Some value here", - true - ). - set_image("https://dpp.dev/DPP-Logo.png"). - set_footer(dpp::embed_footer().set_text("Some footer text here").set_icon("https://dpp.dev/DPP-Logo.png")). - set_timestamp(time(0)); + /* Create an embed */ + dpp::embed embed = dpp::embed(). + set_color(dpp::colors::sti_blue). + set_title("Some name"). + set_url("https://dpp.dev/"). + set_author("Some name", "https://dpp.dev/", "https://dpp.dev/DPP-Logo.png"). + set_description("Some description here"). + set_thumbnail("https://dpp.dev/DPP-Logo.png"). + add_field( + "Regular field title", + "Some value here" + ). + add_field( + "Inline field title", + "Some value here", + true + ). + add_field( + "Inline field title", + "Some value here", + true + ). + set_image("https://dpp.dev/DPP-Logo.png"). + set_footer(dpp::embed_footer().set_text("Some footer text here").set_icon("https://dpp.dev/DPP-Logo.png")). + set_timestamp(time(0)); /* Create a message with the content as our new embed. */ dpp::message msg(event.command.channel_id, embed); @@ -48,19 +48,18 @@ int main() { } }); - 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)); - } - }); + 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)); + } + }); - bot.start(dpp::st_wait); - return 0; + bot.start(dpp::st_wait); + return 0; } ~~~~~~~~~~ The code will send the following message. -\image html embed.png +\image html embed.png \ No newline at end of file diff --git a/docpages/example_programs/the_basics/firstbot.md b/docpages/example_programs/the_basics/firstbot.md index d80ca5ebad..ce97172cc7 100644 --- a/docpages/example_programs/the_basics/firstbot.md +++ b/docpages/example_programs/the_basics/firstbot.md @@ -12,233 +12,234 @@ The two programs can be seen side by side below: - -~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~cpp #include -const std::string BOT_TOKEN = "add your token here"; +const std::string BOT_TOKEN = "add your token here"; int main() { - dpp::cluster bot(BOT_TOKEN); - - bot.on_log(dpp::utility::cout_logger()); - - bot.on_slashcommand([](const dpp::slashcommand_t& event) { - if (event.command.get_command_name() == "ping") { - event.reply("Pong!"); - } - }); - - bot.on_ready([&bot](const dpp::ready_t& event) { - if (dpp::run_once()) { - bot.global_command_create( - dpp::slashcommand("ping", "Ping pong!", bot.me.id) - ); - } - }); - - bot.start(dpp::st_wait); + dpp::cluster bot(BOT_TOKEN); + + bot.on_slashcommand([](const dpp::slashcommand_t& event) { + if (event.command.get_command_name() == "ping") { + event.reply("Pong!"); + } + }); + + bot.on_ready([&bot](const dpp::ready_t& event) { + if (dpp::run_once()) { + bot.global_command_create( + dpp::slashcommand("ping", "Ping pong!", bot.me.id) + ); + } + }); + + bot.start(dpp::st_wait); + return 0; } ~~~~~~~~~~~~~~~ - - -~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~js let Discord = require('discord.js'); - -let BOT_TOKEN = 'add your token here'; +let BOT_TOKEN = 'add your token here'; let bot = new Discord.Client({ intents: [] }); - bot.on('interactionCreate', (interaction) => { - if (interaction.isCommand() && interaction.commandName === 'ping') { - interaction.reply({content: 'Pong!'}); - } + if (interaction.isCommand() && interaction.commandName === 'ping') { + interaction.reply({content: 'Pong!'}); + } }); bot.once('ready', async () => { - await client.commands.create({ - name: 'ping', - description: "Ping pong!" - }); + await client.commands.create({ + name: 'ping', + description: "Ping pong!" + }); }); +bot.login(BOT_TOKEN); -bot.login(BOT_TOKEN);‍ +// ~~~~~~~~~~~~~~~ - Let's break this program down step by step: -### 1. Start with an empty C++ program +## 1. Start with an empty C++ program -Make sure to include the header file for the D++ library with the instruction \#include ``! +Make sure to include the header file for the D++ library with the instruction `#include `! -~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~cpp #include int main() { + return 0; } ~~~~~~~~~~~~~~ -### 2. Create an instance of dpp::cluster +## 2. Create an instance of dpp::cluster To make use of the library you must create a dpp::cluster object. This object is the main object in your program like the `Discord.Client` object in Discord.js. You can instantiate this class as shown below. Remember to put your bot token in the constant! -~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~cpp #include -const std::string BOT_TOKEN = "add your token here"; +const std::string BOT_TOKEN = "add your token here"; int main() { - dpp::cluster bot(BOT_TOKEN); + dpp::cluster bot(BOT_TOKEN); + return 0; } ~~~~~~~~~~~~~~~ -### 3. Attach to an event +## 3. Attach to an event -To have a bot that does something, you should attach to some events. Let's start by attaching to the `on_ready` event (dpp::cluster::on_ready) which will notify your program when the bot is connected. In this event, we will register a slash -command called 'ping'. Note that we must wrap our registration of the command in a template called dpp::run_once which prevents it from being re-run -every time your bot does a full reconnection (e.g. if the connection fails). +To have a bot that does something, you should attach to some events. Let's start by attaching to the `on_ready` event (dpp::cluster::on_ready) which will notify your program when the bot is connected. In this event, we will register a slash command called 'ping'. Note that we must wrap our registration of the command in a template called dpp::run_once which prevents it from being re-run every time your bot does a full reconnection (e.g. if the connection fails). -~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~cpp #include -const std::string BOT_TOKEN = "add your token here"; +const std::string BOT_TOKEN = "add your token here"; int main() { - dpp::cluster bot(BOT_TOKEN); + dpp::cluster bot(BOT_TOKEN); + + bot.on_ready([&bot](const dpp::ready_t& event) { + if (dpp::run_once()) { + bot.global_command_create(dpp::slashcommand("ping", "Ping pong!", bot.me.id)); + } + }); - bot.on_ready([&bot](const dpp::ready_t& event) { - if (dpp::run_once()) { - bot.global_command_create(dpp::slashcommand("ping", "Ping pong!", bot.me.id)); - } - }); + return 0; } ~~~~~~~~~~~~~~~~ -### 4. Attach to another event to receive slash commands +## 4. Attach to another event to receive slash commands If you want to handle a slash command, you should also attach your program to the `on_slashcommand` event (dpp::cluster::on_slashcommand) which is basically the same as the Discord.js `interactionCreate` event. Lets add this to the program before the `on_ready` event: -~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~cpp #include -const std::string BOT_TOKEN = "add your token here"; +const std::string BOT_TOKEN = "add your token here"; int main() { - dpp::cluster bot(BOT_TOKEN); + dpp::cluster bot(BOT_TOKEN); + + bot.on_slashcommand([](const dpp::slashcommand_t& event) { - bot.on_slashcommand([](const dpp::slashcommand_t& event) { - }); + }); - bot.on_ready([&bot](const dpp::ready_t& event) { - if (dpp::run_once()) { - bot.global_command_create(dpp::slashcommand("ping", "Ping pong!", bot.me.id)); - } - }); + bot.on_ready([&bot](const dpp::ready_t& event) { + if (dpp::run_once()) { + bot.global_command_create(dpp::slashcommand("ping", "Ping pong!", bot.me.id)); + } + }); + + return 0; } ~~~~~~~~~~~~~~ -### 5 . Add some content to the events +## 5. Add some content to the events Attaching to an event is a good start, but to make a bot you should actually put some program code into the interaction event. We will add some code to the `on_slashcommand` to look for our slash command '/ping' and reply with `Pong!`: -~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~cpp #include -const std::string BOT_TOKEN = "add your token here"; +const std::string BOT_TOKEN = "add your token here"; int main() { - dpp::cluster bot(BOT_TOKEN); + dpp::cluster bot(BOT_TOKEN); - bot.on_slashcommand([](const dpp::slashcommand_t& event) { - if (event.command.get_command_name() == "ping") { - event.reply("Pong!"); - } - }); + bot.on_slashcommand([](const dpp::slashcommand_t& event) { + if (event.command.get_command_name() == "ping") { + event.reply("Pong!"); + } + }); - bot.on_ready([&bot](const dpp::ready_t& event) { - if (dpp::run_once()) { - bot.global_command_create(dpp::slashcommand("ping", "Ping pong!", bot.me.id)); - } - }); + bot.on_ready([&bot](const dpp::ready_t& event) { + if (dpp::run_once()) { + bot.global_command_create(dpp::slashcommand("ping", "Ping pong!", bot.me.id)); + } + }); + return 0; } ~~~~~~~~~~~~~~~~~~~~~~~ Let's break down the code in the `on_slashcommand` event so that we can discuss what it is doing: -~~~~~~~~~~~~~~~~~~~~~~~{.cpp} - bot.on_slashcommand([](const dpp::slashcommand_t& event) { - if (event.command.get_command_name() == "ping") { - event.reply("Pong!"); - } - }); +~~~~~~~~~~~~~~~~~~~~~~~cpp + bot.on_slashcommand([](const dpp::slashcommand_t& event) { + if (event.command.get_command_name() == "ping") { + event.reply("Pong!"); + } + }); ~~~~~~~~~~~~~~~~~~~~~~~ This code is simply comparing the command name `event.command.get_command_name()` (dpp::interaction::get_command_name) against the value in a constant string value `"ping"`. If they match, then the `event.reply` method is called. The `event.reply` function (dpp::slashcommand_t::reply) replies to a slash command with a message. There are many ways to call this function to send embed messages, upload files, and more, but for this simple demonstration we will just send some message text. -### 6. Add code to start the bot! +## 6. Add code to start the bot! To make the bot start, we must call the dpp::cluster::start method, e.g. in our program by using `bot.start(dpp::st_wait)`. We also add a line to tell the library to output all its log information to the console, `bot.on_log(dpp::utility::cout_logger());` - if you wanted to do something more advanced, you can replace this parameter with a lambda just like all other events. -The parameter which we set to false indicates if the function should return once all shards are created. Passing `false` here tells the program you do not need to do anything once `bot.start` is called. +The parameter which we set to false indicates if the function should return once all shards are created. Passing dpp::st_wait here tells the program you do not need to do anything once `bot.start` is called. -~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~cpp #include -const std::string BOT_TOKEN = "add your token here"; +const std::string BOT_TOKEN = "add your token here"; int main() { - dpp::cluster bot(BOT_TOKEN); - - bot.on_log(dpp::utility::cout_logger()); - - bot.on_slashcommand([](const dpp::slashcommand_t& event) { - if (event.command.get_command_name() == "ping") { - event.reply("Pong!"); - } - }); - - bot.on_ready([&bot](const dpp::ready_t& event) { - if (dpp::run_once()) { - bot.global_command_create(dpp::slashcommand("ping", "Ping pong!", bot.me.id)); - } - }); - - bot.start(dpp::st_wait); + dpp::cluster bot(BOT_TOKEN); + bot.on_log(dpp::utility::cout_logger()); + + bot.on_slashcommand([](const dpp::slashcommand_t& event) { + if (event.command.get_command_name() == "ping") { + event.reply("Pong!"); + } + }); + + bot.on_ready([&bot](const dpp::ready_t& event) { + if (dpp::run_once()) { + bot.global_command_create(dpp::slashcommand("ping", "Ping pong!", bot.me.id)); + } + }); + + bot.start(dpp::st_wait); + return 0; } ~~~~~~~~~~~~~~ -### 7. Compile and run your bot +## 7. Compile and run your bot Compile your bot using `g++ -std=c++17 -o bot bot.cpp -ldpp` (if your .cpp file is called `bot.cpp`) and run it with `./bot`. -### 8. Inviting your bot to your server +## 8. Inviting your bot to your server When you invite your bot, you must use the `applications.commands` and `bots` scopes to ensure your bot can create guild slash commands. For example: -`https://discord.com/oauth2/authorize?client_id=YOUR-BOTS-ID-HERE&scope=bot+applications.commands&permissions=BOT-PERMISSIONS-HERE` +```url +https://discord.com/oauth2/authorize?client_id=YOUR-BOTS-ID-HERE&scope=bot+applications.commands&permissions=BOT-PERMISSIONS-HERE +``` Replace `YOUR-BOTS-ID-HERE` with your bot's user ID, and `BOT-PERMISSIONS-HERE` with the permissions your bot requires. -**Congratulations** - you now have a working bot written using the D++ library! - +**Congratulations** - you now have a working bot written using the D++ library! \ No newline at end of file diff --git a/docpages/example_programs/the_basics/webhooks.md b/docpages/example_programs/the_basics/webhooks.md index 02e1c8c438..ceac988375 100644 --- a/docpages/example_programs/the_basics/webhooks.md +++ b/docpages/example_programs/the_basics/webhooks.md @@ -4,23 +4,21 @@ Webhooks are a simple way to post messages from other apps and websites into Dis The following code shows how to send messages in a channel using a webhook. -~~~~~~~~~~{.cpp} +~~~~~~~~~~cpp #include -int main() -{ - dpp::cluster bot(""); // normally, you put your bot token in here. But to just run a webhook its not required +int main() { + dpp::cluster bot(""); // normally, you put your bot token in here. But to just run a webhook its not required + bot.on_log(dpp::utility::cout_logger()); - bot.on_log(dpp::utility::cout_logger()); + /* construct a webhook object using the URL you got from Discord */ + dpp::webhook wh("https://discord.com/api/webhooks/833047646548133537/ntCHEYYIoHSLy_GOxPx6pmM0sUoLbP101ct-WI6F-S4beAV2vaIcl_Id5loAMyQwxqhE"); - /* construct a webhook object using the URL you got from Discord */ - dpp::webhook wh("https://discord.com/api/webhooks/833047646548133537/ntCHEYYIoHSLy_GOxPx6pmM0sUoLbP101ct-WI6F-S4beAV2vaIcl_Id5loAMyQwxqhE"); + /* send a message with this webhook */ + bot.execute_webhook_sync(wh, dpp::message("Have a great time here :smile:")); - /* send a message with this webhook */ - bot.execute_webhook_sync(wh, dpp::message("Have a great time here :smile:")); - - return 0; + return 0; } ~~~~~~~~~~ -The above is just a very simple example. You can also send embed messages. All you have to do is to add an embed to the message you want to send. If you want to, you can also send it into a thread. +The above is just a very simple example. You can also send embed messages. All you have to do is to add an embed to the message you want to send. If you want to, you can also send it into a thread. \ No newline at end of file diff --git a/docpages/install/install-arch-aur.md b/docpages/install/install-arch-aur.md index 8450dc8a28..7906953110 100644 --- a/docpages/install/install-arch-aur.md +++ b/docpages/install/install-arch-aur.md @@ -2,15 +2,15 @@ To install [D++ from AUR](https://aur.archlinux.org/packages/dpp), follow the steps below (as root): -``` +```bash git clone https://aur.archlinux.org/dpp.git cd dpp makepkg -si ``` -or use your favorite package manager: +or use your favourite package manager: -```sh +```bash # example with `yay` (without root) yay -Sy dpp ``` @@ -23,6 +23,6 @@ This will do the following three things: You will now be able to use D++ by including its library on the command line: -``` +```bash g++ mybot.cpp -o mybot -ldpp -``` +``` \ No newline at end of file diff --git a/docpages/install/install-linux-deb.md b/docpages/install/install-linux-deb.md index 80efdb092a..cf704b66d4 100644 --- a/docpages/install/install-linux-deb.md +++ b/docpages/install/install-linux-deb.md @@ -1,8 +1,8 @@ -\page install-linux-deb Installing from a .deb file (Debian, Ubuntu, Derivatives) +\page install-linux-deb Installing from a .deb file (Debian, Ubuntu, and Derivatives) To install D++ on a system from `.deb` using `dpkg` (as root): -``` +```bash apt install wget wget -O dpp.deb https://dl.dpp.dev/ dpkg -i dpp.deb @@ -16,6 +16,6 @@ This will do the following three things: You will now be able to use D++ by including its library on the command line: -``` +```bash g++ mybot.cpp -o mybot -ldpp ``` \ No newline at end of file diff --git a/docpages/install/install-linux-rpm.md b/docpages/install/install-linux-rpm.md index a5faea8350..d4145c580c 100644 --- a/docpages/install/install-linux-rpm.md +++ b/docpages/install/install-linux-rpm.md @@ -1,8 +1,8 @@ -\page install-linux-rpm Installing from a .rpm file (RedHat, CentOS and derivatives) +\page install-linux-rpm Installing from a .rpm file (RedHat, CentOS, and Derivatives) To install D++ on a system from `.rpm` using `yum` (as root): -``` +```bash yum install wget wget -O dpp.rpm https://dl.dpp.dev/latest/linux-x64/rpm yum localinstall dpp.rpm @@ -16,6 +16,6 @@ This will do the following three things: You will now be able to use D++ by including its library on the command line: -``` +```bash g++ mybot.cpp -o mybot -ldpp ``` \ No newline at end of file diff --git a/docpages/install/install-vcpkg.md b/docpages/install/install-vcpkg.md index f7f44629f1..ed58edd0e6 100644 --- a/docpages/install/install-vcpkg.md +++ b/docpages/install/install-vcpkg.md @@ -1,19 +1,19 @@ -\page install-vcpkg Installing from VCPKG (Windows, Linux, OSX) +\page install-vcpkg Installing from VCPKG (Windows, Linux, macOS) To install D++ on a system from VCPKG: -- Ensure VCPKG is correctly installed, and run `vcpkg integrate install` to integrate it with your preferred IDE. This has been reported to work with Visual Studio, vscode, and JetBrains CLion. +- Ensure VCPKG is correctly installed, and run `vcpkg integrate install` to integrate it with your preferred IDE. This has been reported to work with Visual Studio, VSCode, and JetBrains CLion. - From a command line, type `vcpkg install dpp:x64-windows` (replace `x64-windows` with whichever OS and architecture you want the library to be built for) \image html vcpkg.png - VCPKG will install the library and dependencies for you! Once completed you will receive a message indicating success: - Use `vcpkg list dpp` to check that the package is installed: -``` +```cmd c:\vcpkg>vcpkg list dpp -dpp:x64-windows 10.0.15 D++ Extremely Lightweight C++ Discord Library. +dpp:x64-windows 10.0.24 D++ Extremely Lightweight C++ Discord Library. ``` - You may now use the library within a `CMake` based project by adding instructions such as these to your `CMakeLists.txt`: ```cmake - find_package(dpp CONFIG REQUIRED) - target_link_libraries(your_target_name PRIVATE dpp::dpp) -``` +find_package(dpp CONFIG REQUIRED) +target_link_libraries(your_target_name PRIVATE dpp::dpp) +``` \ No newline at end of file diff --git a/docpages/install/install-windows-clion-vcpkg.md b/docpages/install/install-windows-clion-vcpkg.md index 66a65a4f5b..b7e7c020ed 100644 --- a/docpages/install/install-windows-clion-vcpkg.md +++ b/docpages/install/install-windows-clion-vcpkg.md @@ -1,36 +1,33 @@ -\page install-windows-clion-vcpkg Installing from vcpkg for CLion +\page install-windows-clion-vcpkg Installing for CLion from VCPKG -To add D++ to a CLion project, you need obtain the library through vcpkg and then configure your CLion project and `CMakeLists.txt`. +To add D++ to a CLion project, you need to obtain the library through VCPKG and then configure your CLion project and `CMakeLists.txt`. -1. Build [vcpkg](https://vcpkg.io/) on your system (skip if you already have it). +1. Build [VCPKG](https://vcpkg.io/) on your system (skip if you already have it). 2. Run `vcpkg install dpp:x64-windows` (replace x64-windows with whichever OS and architecture you want the library to be built for). -3. vcpkg will install the library along with the dependencies for you. +3. VCPKG will install the library along with the dependencies for you. 4. Now check if dpp has been installed using `vcpkg list dpp`. - ``` - C:/vcpkg>vcpkg list dpp - dpp:x64-windows 10.0.23 D++ Extremely Lightweight C++ Discord Library. - ``` - -5. To use vcpkg in CLion, add the following line to your CMake options in the settings (Located under Settings > Build, Execution, Deployment > CMake) - ``` - -DCMAKE_TOOLCHAIN_FILE=path_to_vcpkg_root_folder/scripts/buildsystems/vcpkg.cmake - ``` +```cmd +C:/vcpkg>vcpkg list dpp +dpp:x64-windows 10.0.24 D++ Extremely Lightweight C++ Discord Library. +``` +5. To use VCPKG in CLion, add the following line to your CMake options in the settings (Located under Settings > Build, Execution, Deployment > CMake) +```cmd +-DCMAKE_TOOLCHAIN_FILE=path_to_vcpkg_root_folder/scripts/buildsystems/vcpkg.cmake +``` For example, if your root folder is `C:/vcpkg/` then the CMake option will be: - ``` - -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake - ``` - +```cmd +-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake +``` 6. Now proceed to add the following lines to your `CMakeLists.txt`: - ```cmake - find_package(dpp CONFIG REQUIRED) - target_link_libraries(main PRIVATE dpp::dpp) - target_include_directories(main PRIVATE path_to_vcpkg_root_folder/installed/architecture-os/include) - ``` - For example, if built for x64-windows and vcpkg root is `C:/vcpkg/` then your `CMakeLists.txt` should look like this: - ```cmake - find_package(dpp CONFIG REQUIRED) - target_link_libraries(main PRIVATE dpp::dpp) - target_include_directories(main PRIVATE C:/vcpkg/installed/x64-windows/include) - ``` - -7. Congratulations! Now try to build a test program to see if the installation succeeded. If you get stuck somewhere, feel free to ask us on the D++ [discord server](https://discord.gg/dpp). \ No newline at end of file +```cmake +find_package(dpp CONFIG REQUIRED) +target_link_libraries(main PRIVATE dpp::dpp) +target_include_directories(main PRIVATE path_to_vcpkg_root_folder/installed/architecture-os/include) +``` + For example, if built for x64-windows and VCPKG root is `C:/vcpkg/` then your `CMakeLists.txt` should look like this: +```cmake +find_package(dpp CONFIG REQUIRED) +target_link_libraries(main PRIVATE dpp::dpp) +target_include_directories(main PRIVATE C:/vcpkg/installed/x64-windows/include) +``` +7. Congratulations! Now try to build a test program to see if the installation succeeded. If you get stuck somewhere, feel free to ask us on the D++ [Discord server](https://discord.gg/dpp). \ No newline at end of file diff --git a/docpages/install/install-windows-vs-zip.md b/docpages/install/install-windows-vs-zip.md index 3bf5a10885..36b3c52546 100644 --- a/docpages/install/install-windows-vs-zip.md +++ b/docpages/install/install-windows-vs-zip.md @@ -1,44 +1,43 @@ -\page install-windows-vs-zip Installing from zip (Windows) for Visual Studio +\page install-windows-vs-zip Installing for Visual Studio from ZIP (Windows) To add D++ to a Visual Studio project, using **Visual Studio 2019** or **Visual Studio 2022**, follow the steps below. The steps below assume an empty project, if you are adding to an existing project simply skip steps 1 through 4, and step 13. -\note It is possible to skip this entire tutorial, and obtain a [pre-made visual studio template containing the latest D++ build (for 32 and 64 bit, release and debug profiles) by clicking here](https://github.com/brainboxdotcc/windows-bot-template/). +\note It is possible to skip this entire tutorial, and obtain a [pre-made Visual Studio template containing the latest D++ build (for 32 and 64 bit, release and debug profiles) by clicking here](https://github.com/brainboxdotcc/windows-bot-template/). 1. Make sure you have Visual Studio 2019 or 2022. Community, Professional or Enterprise work fine. These instructions are not for Visual Studio Code. You can [download the correct version here](https://visualstudio.microsoft.com/downloads/). Note that older versions of Visual Studio will not work as they do not support enough of the C++17 standard. -2. Start visual studio and choose to create a new project - \image html zip_vsproj_1.png -3. Choose the project type "Console Project" and click next - \image html zip_vsproj_2.png -4. Name your bot project. In this example i just chose the name 'MyBot'. You can have any name you like here. - \image html zip_vsproj_3.png -5. Open the zip file you downloaded which contains the D++ dlls, include files and lib file. Drag and drop this to your local machine and make note of where you placed it. This location will be important in later steps. - \image html zip_vsproj_4.png -6. Back inside visual studio, right click on the project (not solution!) in the tree in your visual studio window. choose 'Properties'. - \image html zip_vsproj_5.png +2. Start Visual Studio and choose to create a new project: +\image html zip_vsproj_1.png +3. Choose the project type "Console Project" and click next: +\image html zip_vsproj_2.png +4. Name your bot project. In this example I just chose the name 'MyBot'. You can have any name you like here. +\image html zip_vsproj_3.png +5. Open the ZIP file you downloaded which contains the D++ DLLs, include files, and lib file. Drag and drop this to your local machine and make note of where you placed it. This location will be important in later steps. +\image html zip_vsproj_4.png +6. Back inside Visual Studio, right click on the project (not solution!) in the tree in your Visual Studio window. choose 'Properties'. +\image html zip_vsproj_5.png 7. The next step is to populate the include directories and library directories sections with the paths to the D++ library and include files. The next steps will guide you through how to do this. - \image html zip_vsproj_6.png +\image html zip_vsproj_6.png 8. Click 'edit' when prompted to edit the include paths section. Add the path to the include folder you extracted to your machine, which we took note of earlier. Note that it is important to add the dpp-10.0 folder, not any other folder, to this list: - \image html zip_vsproj_7.png -9. Going back to the previous window, now edit the library paths. Again click 'edit' when prompted to edit the library paths section. Add the path to the library folder you extracted to your machine, which we took note of earlier. Note that once more it is important to add the dpp-9.0 folder within it, not any other folder, to this list. Also be aware this is a **different folder** than the one you just added for includes! - \image html zip_vsproj_8.png +\image html zip_vsproj_7.png +9. Going back to the previous window, now edit the library paths. Again click 'edit' when prompted to edit the library paths section. Add the path to the library folder you extracted to your machine, which we took note of earlier. Note that once more it is important to add the dpp-10.0 folder within it, not any other folder, to this list. Also be aware this is a **different folder** than the one you just added for includes! +\image html zip_vsproj_8.png 10. Double check at this point that all the directories are filled in correctly. They should look generally like the ones in the screenshot below: - \image html zip_vsproj_9.png -11. Go to the general section in the same window now, and look for the drop down list labelled "C++ Language Standard". Make sure the selected option is **C++17 Standard (/std:c++17)** - \image html zip_vsproj_10.png +\image html zip_vsproj_9.png +11. Go to the general section in the same window now, and look for the drop down list labelled "C++ Language Standard". Make sure the selected option is **C++17 Standard (/std:c++17)** or later. +\image html zip_vsproj_10.png 12. Again within the same window, go to the input section, under the linker category, and add '**dpp.lib;**' to the start of the libraries to include, as shown below: - \image html zip_vsproj_11.png -13. Now you can paste some code into the editor, completely replacing the 'hello world' application that visual studio made for you. The example code here is the basic bot from the first example on this site. You should at this point also double check that the architecture you have selected (in this case x86) matches the version of the dll/lib files you downloaded from the website. This is **important** as if you mismatch them the compilation will just fail. - \image html zip_vsproj_12.png -14. Go to the build menu and choose Build Solution (A handy shortcut for this is to just press **F7**): - \image html zip_vsproj_13.png +\image html zip_vsproj_11.png +13. Now you can paste some code into the editor, completely replacing the 'hello world' application that Visual Studio made for you. The example code here is the basic bot from the first example on this site. You should at this point also double check that the architecture you have selected (in this case x86) matches the version of the dll/lib files you downloaded from the website. This is **important** as if you mismatch them the compilation will just fail. +\image html zip_vsproj_12.png +14. Go to the build menu and choose Build Solution (a handy shortcut for this is to just press **F7**): +\image html zip_vsproj_13.png 15. Observe the build output. There may be warnings, but so long as the build output ends with "1 succeeded" then the process has worked. You may now run your bot! - \image html zip_vsproj_14.png +\image html zip_vsproj_14.png ## Troubleshooting -- If you get an error that a dll is missing (e.g. `dpp.dll` or `opus.dll`) when starting your bot, then simply copy all dlls from the **bin** directory of where you extracted the DPP zip file to, into the same directory where your bot's executable is. You only need to do this once. There should be several of these dll files: `dpp.dll`, `zlib.dll`, `openssl.dll` and `libcrypto.dll` (or similarly named SSL related files), `libsodium.dll` and `opus.dll`. +- If you get an error that a DLL is missing (e.g. `dpp.dll` or `opus.dll`) when starting your bot, then simply copy all DLLs from the **bin** directory of where you extracted the D++ ZIP file to, into the same directory where your bot's executable is. You only need to do this once. There should be several of these DLL files: `dpp.dll`, `zlib.dll`, `openssl.dll` and `libcrypto.dll` (or similarly named SSL related files), `libsodium.dll` and `opus.dll`. - Please note that if you change the architecture (step 13) you must reconfigure all of steps 7 through 12 again as these configurations are specific to each architecture. This is to allow for different sets of precompiled libs, e.g. for `x86`, `x64`, etc. - You should run your bot from a command prompt. If you do not, and it exits, you will not be able to see any output as the window will immediately close. -- If you need to update the `opus.dll` or `zlib.dll` (or any other prebuilt dll) these can be obtained by requesting them to be installed via `vcpkg` then copying the dlls, libraries and headers from the vcpkg `install` folder. -- Stuck? You can find us on the [official discord server](https://discord.gg/dpp) - ask away! We don't bite! - +- If you need to update the `opus.dll` or `zlib.dll` (or any other prebuilt DLL) these can be obtained by requesting them to be installed via `vcpkg` then copying the DLLs, libraries and headers from the VCPKG `install` folder. +- Stuck? You can find us on the [official Discord server](https://discord.gg/dpp) - ask away! We don't bite! \ No newline at end of file diff --git a/docpages/install/install-xmake.md b/docpages/install/install-xmake.md index d46091cc15..5feca8fbb7 100644 --- a/docpages/install/install-xmake.md +++ b/docpages/install/install-xmake.md @@ -1,21 +1,21 @@ -\page install-xmake Installing from xmake +\page install-xmake Installing from XMake To install D++ on a project from XMake: - Ensure XMake [is correctly installed](https://xmake.io/#/guide/installation) -- Create a new xmake project if you haven't already one, using `xmake init ` +- Create a new XMake project if you haven't already one, using `xmake init ` - Update the `xmake.lua` file by adding the `dpp` package, below the minimum configuration: -~~~~~~~~~~~{.cmake} +~~~~~~~~~~~lua add_rules("mode.debug", "mode.release") add_requires("dpp") target("test-bot") - set_kind("binary") - add_files("src/*.cpp") + set_kind("binary") + add_files("src/*.cpp") - add_packages("dpp") + add_packages("dpp") ~~~~~~~~~~~ - Finally, run `xmake build` to download dependencies and build the project \ No newline at end of file diff --git a/docpages/make_a_bot/clion.md b/docpages/make_a_bot/clion.md index 6aadb74a2d..7046afe39e 100644 --- a/docpages/make_a_bot/clion.md +++ b/docpages/make_a_bot/clion.md @@ -1,25 +1,26 @@ -\page build-a-discord-bot-linux-clion Building a discord bot in Linux using CLion +\page build-a-discord-bot-linux-clion Building a Discord Bot on Linux Using CLion -This tutorial teaches you how to create a _working skeleton project you can build upon_, using the JetBrains-IDE **[CLion](https://www.jetbrains.com/clion/)**. +This tutorial teaches you how to create a _working skeleton project you can build upon_, using the JetBrains IDE **[CLion](https://www.jetbrains.com/clion/)**. -\note This tutorial will use **Ubuntu**! You might use other Distros if you prefer, but keep in mind the setup process might be different! +\note This tutorial will use **Ubuntu**! You might use other distros if you prefer, but keep in mind the setup process might be different! -Make sure you have CLion installed and works fine (run a _hello-world program_). You can [download CLion here](https://www.jetbrains.com/de-de/clion/download/). +Make sure you have CLion installed and it works fine (run a _hello-world program_). You can [download CLion here](https://www.jetbrains.com/de-de/clion/download/). -## Setup a project +## Setup a Project -Create a new project. Select C++17 as the Language standard, or C++20 if you want something more recent. +Create a new project. Select C++17 or later as the Language standard. We'll use the following file structure as a _skeleton project you can build upon_: - - your_project/ - |-- libs/ - |-- src/ - |-- main.cpp - |-- CMakeLists.txt +```puml +- your_project/ + |-- libs/ + |-- src/ + |-- main.cpp + |-- CMakeLists.txt +``` - -Create the directories in your project and move the by CLion generated _hello-world main.cpp_ in the `src/` directory. +Create the directories in your project and move the _hello-world main.cpp_ generated by CLion to the `src/` directory. In the `libs/` directory, clone D++ with: `git clone https://github.com/brainboxdotcc/DPP.git`. You can also clone [spdlog](https://github.com/gabime/spdlog) into it if you need a logger. @@ -27,15 +28,15 @@ Your project directory should look like this: \image html build-clion-project-structure.png -### Configure CMake file +### Configure CMake File Paste this CMake configuration in the `CMakeLists.txt` and adapt it according to your needs: -~~~~~~~~~~~~~~{.cmake} +~~~~~~~~~~~~~~cmake # minimum CMake version required cmake_minimum_required(VERSION 3.15) # Project name, version and description -project(discord-bot VERSION 1.0 DESCRIPTION "A discord bot") +project(discord-bot VERSION 1.0 DESCRIPTION "A Discord bot") # Add DPP as dependency add_subdirectory(libs/DPP) @@ -44,26 +45,26 @@ add_subdirectory(libs/spdlog) # if you need a logger. Don't forget to clone sour # Create an executable add_executable(${PROJECT_NAME} - src/main.cpp - # your others files... + src/main.cpp + # your other files… ) # Linking libraries target_link_libraries(${PROJECT_NAME} - dpp - spdlog # Like before, if you need spdlog + dpp + spdlog # Like before, if you need spdlog ) # Specify includes target_include_directories(${PROJECT_NAME} PRIVATE - libs/DPP/include - libs/spdlog/include # Like before, if you need spdlog + libs/DPP/include + libs/spdlog/include # Like before, if you need spdlog ) # Set C++ version set_target_properties(${PROJECT_NAME} PROPERTIES - CXX_STANDARD 17 # or 20 if you want something more recent - CXX_STANDARD_REQUIRED ON + CXX_STANDARD 17 # or 20 if you want something more recent + CXX_STANDARD_REQUIRED ON ) ~~~~~~~~~~~~~~ @@ -71,45 +72,42 @@ Then open the "File" menu and click on "Reload CMake Project" to reload the CMak \image html build-clion-reload-cmake-project.png -### Add an example program +### Add an Example Program The next step is to write the bot. Copy and paste the following \ref firstbot "example program" in the `main.cpp` and set your bot token (see \ref creating-a-bot-application): - -~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~cpp #include -const std::string BOT_TOKEN = "add your token here"; +const std::string BOT_TOKEN = "add your token here"; int main() { - dpp::cluster bot(BOT_TOKEN); - - bot.on_log(dpp::utility::cout_logger()); - - bot.on_slashcommand([](const dpp::slashcommand_t& event) { - if (event.command.get_command_name() == "ping") { - event.reply("Pong!"); - } - }); - - bot.on_ready([&bot](const dpp::ready_t& event) { - if (dpp::run_once()) { - bot.global_command_create( - dpp::slashcommand("ping", "Ping pong!", bot.me.id) - ); - } - }); - - bot.start(dpp::st_wait); + dpp::cluster bot(BOT_TOKEN); + bot.on_log(dpp::utility::cout_logger()); + + bot.on_slashcommand([](const dpp::slashcommand_t& event) { + if (event.command.get_command_name() == "ping") { + event.reply("Pong!"); + } + }); + + bot.on_ready([&bot](const dpp::ready_t& event) { + if (dpp::run_once()) { + bot.global_command_create( + dpp::slashcommand("ping", "Ping pong!", bot.me.id) + ); + } + }); + + bot.start(dpp::st_wait); + return 0; } ~~~~~~~~~~~~~~~ - Hit the green "Run" button in the top-right to run the bot. **Congratulations, you've successfully set up a bot!** ## Troubleshooting -- Stuck? You can find us on the [official discord server](https://discord.gg/dpp) - ask away! We don't bite! - +- Stuck? You can find us on the [official Discord server](https://discord.gg/dpp) - ask away! We don't bite! \ No newline at end of file diff --git a/docpages/make_a_bot/cmake.md b/docpages/make_a_bot/cmake.md index 127fd44824..972c756045 100644 --- a/docpages/make_a_bot/cmake.md +++ b/docpages/make_a_bot/cmake.md @@ -1,23 +1,25 @@ -\page buildcmake Building a Discord Bot using CMake/UNIX +\page buildcmake Building a Discord Bot Using CMake/UNIX ## 1. Toolchain -Before compiling, you will need to install `cmake` on your system. -To be sure that `cmake` is installed, you can type the following command: - $ cmake --version - cmake version 3.20.4 +Before compiling, you will need to install `cmake` on your system. To be sure that `cmake` is installed, you can type the following command: +```bash +$ cmake --version +cmake version 3.20.4 +``` ## 2. Create a CMake project In an empty directory, create the following files and directories: - - your_project/ - |-- libs/ - |-- src/ - |-- main.cpp - |-- CMakeLists.txt - +```puml +- your_project/ + |-- libs/ + |-- src/ + |-- main.cpp + |-- CMakeLists.txt +``` In the `libs/` directory, clone D++ with: `git clone https://github.com/brainboxdotcc/DPP.git` @@ -25,11 +27,11 @@ In the `libs/` directory, clone D++ with: `git clone https://github.com/brainbox Here is an example CMake configuration, adapt it according to your needs: -~~~~~~~~~~~~~~{.cmake} +~~~~~~~~~~~~~~cmake # minimum CMake version required cmake_minimum_required(VERSION 3.15) # Project name, version and description -project(discord-bot VERSION 1.0 DESCRIPTION "A discord bot") +project(discord-bot VERSION 1.0 DESCRIPTION "A Discord bot") # Add DPP as dependency add_subdirectory(libs/DPP) @@ -37,38 +39,38 @@ add_subdirectory(libs/DPP) # Create an executable add_executable(${PROJECT_NAME} - src/main.cpp - # your other files... + src/main.cpp + # your other files… ) # Linking libraries target_link_libraries(${PROJECT_NAME} - dpp - # Add any other libs you want to use here + dpp + # Add any other libs you want to use here ) # Specify includes target_include_directories(${PROJECT_NAME} PRIVATE - libs/DPP/include - # Remember to add the include directories of any other libraries too + libs/DPP/include + # Remember to add the include directories of any other libraries too ) # Set C++ version set_target_properties(${PROJECT_NAME} PROPERTIES - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED ON + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED ON ) ~~~~~~~~~~~~~~ Your project directory should look like this: - - your_project/ - |-- libs/ - |-- DPP - |-- src/ - |-- main.cpp - |-- CMakeLists.txt - - -**Have fun!** +```puml +- your_project/ + |-- libs/ + |-- DPP + |-- src/ + |-- main.cpp + |-- CMakeLists.txt +``` +**Have fun!** \ No newline at end of file diff --git a/docpages/make_a_bot/meson.md b/docpages/make_a_bot/meson.md index db307bf7f4..896fc5960b 100644 --- a/docpages/make_a_bot/meson.md +++ b/docpages/make_a_bot/meson.md @@ -1,37 +1,45 @@ -\page buildmeson Build a Discord Bot using Meson +\page buildmeson Build a Discord Bot Using Meson ## 1. Toolchain -Before compiling, you will need to install `meson` on your system. -To be sure that `meson` is installed, you can type the following command: +Before compiling, you will need to install `meson` on your system. To be sure that `meson` is installed, you can type the following command: - $ meson --version - 0.63.2 +```bash +$ meson --version +0.63.2 +``` -## 2. Create a Meson project +## 2. Create a Meson Project -In an empty directory. +In an empty directory: - - your project/ +```puml +- your project/ +``` -run the command +Run the command: - $ meson init -l cpp +```bash +meson init -l cpp +``` -## 3. Configuring your Meson project +## 3. Configuring Your Meson Project -add the following line after the `project()` line in your `meson.build` file. +Add the following line after the `project()` line in your `meson.build` file. - dpp = dependency('dpp') +```yml +dpp = dependency('dpp') +``` -add the following line in the executable section of your `meson.build` file. +Add the following line in the executable section of your `meson.build` file. - dependencies: [dpp] +```yml +dependencies: [dpp] +``` -change the `cpp_std` value in the `project()` to `c++17` +Change the `cpp_std` value in the `project()` to `c++17`. Your `meson.build` should look like this: -your meson.build should look like this. -~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~yml project('discord-bot', 'cpp', version : '0.1', default_options : ['warning_level=3', @@ -39,12 +47,10 @@ project('discord-bot', 'cpp', dpp = dependency('dpp') - exe = executable('discord', 'discord_bot.cpp', install : true, dependencies: [dpp]) test('basic', exe) - ~~~~~~~~~~~~~~ Meson automatically generates a cpp for your project. And a test suite. @@ -53,5 +59,7 @@ Meson automatically generates a cpp for your project. And a test suite. To build a meson project run - $ meson setup builddir - $ meson compile -C builddir \ No newline at end of file +```bash +meson setup builddir +meson compile -C builddir +``` \ No newline at end of file diff --git a/docpages/make_a_bot/replit.md b/docpages/make_a_bot/replit.md index e3eae1d7d0..51aeb92297 100644 --- a/docpages/make_a_bot/replit.md +++ b/docpages/make_a_bot/replit.md @@ -1,42 +1,44 @@ -\page building-a-cpp-discord-bot-in-repl Creating a Discord bot in Replit +\page building-a-cpp-discord-bot-in-repl Creating a Discord Bot in Replit -@note There is a premade repl, ready for use which was built using the steps above. If you wish to use this repl simply [visit this github repository](https://github.com/alanlichen/dpp-on-repl) and click the "Run on Replit" button. Then, follow the steps in the README file. +\note There is a premade repl ready for use which was built using the steps below. If you wish to use this repl simply [visit this GitHub repository](https://github.com/alanlichen/dpp-on-repl) and click the "Run on Replit" button. Then, follow the steps in the README file. -To build a D++ bot in a Replit instance, follow these steps. These steps are slightly more convoluted than installing D++ into a standard container as we don't have access to root in the conventional way or write access to any files outside of our home directory in a repl. This guide sidesteps the issue by locally extracting a libdpp deb file installer, and referencing the local dependencies from the command-line. +To build a D++ bot in a Replit instance, follow these steps. These steps are slightly more convoluted than installing D++ into a standard container as we don't have access to root in the conventional way or write access to any files outside of our home directory in a repl. This guide sidesteps the issue by locally extracting a `libdpp` deb file installer, and referencing the local dependencies from the command-line. -1. Use wget, or the upload button, to get the precompiled x64 release into your repl as a file, e.g. `wget -O libdpp.deb https://dl.dpp.dev/latest` +1. Use wget, or the upload button, to get the precompiled x64 release into your repl as a file, e.g. `wget -O libdpp.deb https://dl.dpp.dev/latest`. 2. Extract this deb file using `dpkg`: -``` +```bash dpkg -x libdpp.deb . ``` 3. Compile your bot, note that you should be sure to include the `pthread` library explicitly and reference the extracted dpp installation you just put into the repl: -``` +```bash g++ -o bot main.cpp -ldpp -lpthread -L./usr/lib -I./usr/include -std=c++17 ``` 4. Run your bot! Note that you will need to set `LD_PRELOAD` to reference `libdpp.so` as it will be located in `$HOME` and not `/usr/lib`: -``` +```bash LD_PRELOAD=./usr/lib/libdpp.so ./bot ``` Now that your bot is running, you have to keep it online. Replit automatically puts repls to sleep after some time, so you will need to ping a webserver. Unfortunately, Replit is sometimes limiting, and this is one of the only free workarounds to this issue. 1. Start a http server. This can be through any webserver, but as a simple solution, use python's built in http.server: -``` +```bash python3 -m http.server ``` 2. Create an `index.html` file with anything inside it for the server to serve. 3. Go to [uptimerobot.com](https://uptimerobot.com/) and create an account if you don't have one. 4. After verifying your account, click "Add New Monitor". + + For Monitor Type, select "HTTP(s)" + In Friendly Name, put the name of your bot -+ For your url, copy the url of the new website that repl is serving for you ++ For your URL, copy the URL of the new website that repl is serving for you + Select any alert contacts you want, then click "Create Monitor" + Here is an example of a possible uptimerobot configuration: \image html uptimerobot.png ## Troubleshooting -If the bot fails to start and instead you receive an error message about being banned from the Discord API, there is little to be done about this. These bans are temporary but because Replit is a shared platform, you share an IP address with many thousands of bots, some abusive and some badly written. This will happen often and is outside of the control of yourself and us. However, you can try to migitate this by typing `kill 1` in the shell. This is not guaranteed to work, and you might need to try it a few times. If it still does not work, then we recommend instead you obtain some affordable non-free hosting instead. +If the bot fails to start and instead you receive an error message about being banned from the Discord API, there is little to be done about this. These bans are temporary but because Replit is a shared platform, you share an IP address with many thousands of bots, some abusive and some badly written. This will happen often and is outside of the control of yourself and us. However, you can try to mitigate this by typing `kill 1` in the shell. This is not guaranteed to work, and you might need to try it a few times. If it still does not work, then we recommend you obtain some affordable non-free hosting instead. -If your bot continues to fall asleep even though you have a server, we advise you to double check that no errors are happening, and if the server is being pinged. If that still does not work, we again recommend you to obtain some affordable non-free hosting. +If your bot continues to fall asleep even though you have a server, we advise you to double check that no errors are happening, and if the server is being pinged. If that still does not work, we again recommend you to obtain some affordable non-free hosting. \ No newline at end of file diff --git a/docpages/make_a_bot/token.md b/docpages/make_a_bot/token.md index 9f60f408d6..be93d03b99 100644 --- a/docpages/make_a_bot/token.md +++ b/docpages/make_a_bot/token.md @@ -1,8 +1,8 @@ \page creating-a-bot-application Creating a Bot Token -Before you start coding, you need to create and register your bot in the Discord developer portal. You can then add this bot to your Discord-server. +Before you start coding, you need to create and register your bot in the Discord developer portal. You can then add this bot to your Discord server. -## Creating a new bot +## Creating a New Bot To create a new application, take the steps as follows: @@ -10,36 +10,31 @@ To create a new application, take the steps as follows: 2. Next, enter a name for the application in the pop-up and press the "Create" button. \image html create_application_confirm_popup.png In this example we named it "D++ Test Bot". -3. Move on by click the "Bot" tab in the left-hand side of the screen. Now click the "Add Bot" button on the right and confirm that you want to add the bot to your application. - +3. Move on by clicking the "Bot" tab in the left-hand side of the screen. Now click the "Add Bot" button on the right and confirm that you want to add the bot to your application. \image html create_application_add_bot.png - On the resulting screen, you’ll note a page with information regarding your new bot. You can edit your bot name, description, and avatar here if you want to. If you wish to read the message content from messages, you need to enable the message content intent in the "Privileged Gateway Intents" section. - \image html create_application_bot_overview.png - In this panel, you can get your bot token by clicking "Reset Token". A bot token looks like this: `OTAyOTMxODU1NTU1MzE3ODUw.YXlm0g.9oYCt-XHXVH_z9qAytzmVRzKWTg` \warning **Do not share this token** with anybody! If you ever somehow compromise your current bot token or see your bot in danger, you can regenerate the token in the panel. -## Adding the bot to your server +## Adding the Bot to Your Server + +Once you've created your bot in the Discord developer portal, you may wonder: -Once you've created your bot in the discord developer portal, you may wonder: > Where is my bot now, I can't see him on my server?! That's because you've created a bot application, but it's not on any server right now. So, to invite the bot to your server, you must create an invitation URL. -1. go again into the [Applications page](https://discord.com/developers/applications) and click on your bot. +1. Go again into the [Applications page](https://discord.com/developers/applications) and click on your bot. 2. Go to the "OAuth2" tab and click on the subpage "URL Generator". \image html create_application_navigate_to_url_generator.png 3. Select the `bot` scope. If your bot uses slash commands, also select `applications.commands`. You can read more about scopes and which you need for your application [here](https://discord.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes). 4. Choose the permissions required for your bot to function in the "Bot Permissions" section. 5. Copy and paste the resulting URL in your browser. Choose a server to invite the bot to, and click "Authorize". - \note For bots with elevated permissions, Discord enforces two-factor authentication on the bot owner's account when added to servers that have server-wide 2FA enabled. ## Troubleshooting -- Stuck? You can find us on the [official discord server](https://discord.gg/dpp) - ask away! We don't bite! - +- Stuck? You can find us on the [official Discord server](https://discord.gg/dpp) - ask away! We don't bite! \ No newline at end of file diff --git a/docpages/make_a_bot/windows_vs.md b/docpages/make_a_bot/windows_vs.md index af228badda..ee0544bcd7 100644 --- a/docpages/make_a_bot/windows_vs.md +++ b/docpages/make_a_bot/windows_vs.md @@ -1,20 +1,19 @@ -\page build-a-discord-bot-windows-visual-studio Building a discord bot in Windows using Visual Studio +\page build-a-discord-bot-windows-visual-studio Building a Discord Bot on Windows Using Visual Studio To create a basic bot using **Visual Studio 2019** or **Visual Studio 2022**, follow the steps below to create a *working skeleton project you can build upon*. 1. Make sure you have Visual Studio 2019 or 2022. Community, Professional or Enterprise work fine. These instructions are not for Visual Studio Code. You can [download the correct version here](https://visualstudio.microsoft.com/downloads/). Note that older versions of Visual Studio will not work as they do not support enough of the C++17 standard. 2. Clone the [template project](https://github.com/brainboxdotcc/windows-bot-template/). Be sure to clone the entire project and not just copy and paste the `.cpp` file. -3. Double click on the `MyBot.sln` file in the folder you just cloned - \image html vsproj_1.png -4. Add your bot token (see \ref creating-a-bot-application) and guild ID to the example program - \image html vsproj_2.png -5. Click "Local windows debugger" to compile and run your bot! - \image html vsproj_3.png +3. Double click on the `MyBot.sln` file in the folder you just cloned: +\image html vsproj_1.png +4. Add your bot token (see \ref creating-a-bot-application) and guild ID to the example program: +\image html vsproj_2.png +5. Click "Local Windows debugger" to compile and run your bot! +\image html vsproj_3.png 6. Observe the build output. There may be warnings, but so long as the build output ends with "1 succeeded" then the process has worked. You may now run your bot! - \image html vsproj_14.png +\image html vsproj_14.png ## Troubleshooting -- If you get an error that a dll is missing (e.g. `dpp.dll` or `opus.dll`) when starting your bot, then simply copy all dlls from the **bin** directory of where you extracted the DPP zip file to, into the same directory where your bot's executable is. You only need to do this once. There should be several of these dll files: `dpp.dll`, `zlib.dll`, `openssl.dll` and `libcrypto.dll` (or similarly named SSL related files), `libsodium.dll` and `opus.dll`. Note the template project does this for you, so you should never encounter this issue. -- Stuck? You can find us on the [official discord server](https://discord.gg/dpp) - ask away! We don't bite! - +- If you get an error that a DLL is missing (e.g. `dpp.dll` or `opus.dll`) when starting your bot, then simply copy all DLLs from the **bin** directory of where you cloned the D++ repository to, into the same directory where your bot's executable is. You only need to do this once. There should be several of these DLL files: `dpp.dll`, `zlib.dll`, `openssl.dll` and `libcrypto.dll` (or similarly named SSL related files), `libsodium.dll` and `opus.dll`. Note the template project does this for you, so you should never encounter this issue. +- Stuck? You can find us on the [official Discord server](https://discord.gg/dpp) - ask away! We don't bite! \ No newline at end of file diff --git a/docpages/make_a_bot/windows_wsl.md b/docpages/make_a_bot/windows_wsl.md index d811af9bd0..3c1427c40b 100644 --- a/docpages/make_a_bot/windows_wsl.md +++ b/docpages/make_a_bot/windows_wsl.md @@ -1,18 +1,17 @@ -\page build-a-discord-bot-windows-wsl Building a discord bot in Windows using WSL (Windows Subsystem for Linux) +\page build-a-discord-bot-windows-wsl Building a Discord Bot on Windows Using WSL (Windows Subsystem for Linux) -This tutorial teaches you how to create a lightweight environment for D++-development using **WSL** and **Visual Studio Code** +This tutorial teaches you how to create a lightweight environment for D++ development using **WSL** and **Visual Studio Code**. -This Tutorial will use WSL's default distribution, **Ubuntu**! You might use other Distros if you prefer, but keep in mind the setup process might be different! +This Tutorial will use WSL's default distribution, **Ubuntu**! You might use other distros if you prefer, but keep in mind the setup process might be different! 1. Make sure you have installed your WSL 2 environment properly using [this guide to setup up WSL](https://docs.microsoft.com/en-us/windows/wsl/install) and [this guide to connect to Visual Studio Code](https://docs.microsoft.com/en-us/windows/wsl/tutorials/wsl-vscode). -2. Now open PowerShell as an Admin and type `wsl` to start up your subsystem. If you want to set up a CMake project (recommended for production bots) now, consider continuing your path of becoming the master of all Discord bots \ref buildcmake "here", otherwise keep following this guide! -3. Go to your home directory using `cd ~` -4. Download the latest build for your Distro using `wget [url here]`. In this guide we will use the latest build for 64 bit Ubuntu: `wget -O libdpp.deb https://dl.dpp.dev/latest` -5. Finally install all required deps and the library using `sudo apt-get install libopus0 && sudo apt-get install -y libopus-dev && sudo apt-get install -y libsodium-dev && sudo dpkg -i libdpp.deb && rm libdpp.deb` +2. Now open PowerShell as Administrator and type `wsl` to start up your subsystem. If you want to set up a CMake project (recommended for production bots) now, consider continuing your path of becoming the master of all Discord bots \ref buildcmake "here", otherwise keep following this guide! +3. Go to your home directory using `cd ~`. +4. Download the latest build for your distro using `wget [url here]`. In this guide we will use the latest build for 64 bit Ubuntu: `wget -O libdpp.deb https://dl.dpp.dev/latest`. +5. Finally install all required dependencies and the library itself using `sudo apt-get install libopus0 libopus-dev libsodium-dev && sudo dpkg -i libdpp.deb && rm libdpp.deb`. 6. Congratulations, you've successfully installed all dependencies! Now comes the real fun: Setting up the environment! For this tutorial we'll use a as small as possible setup, so you might create a more advanced one for production bots. -7. Navigate to a folder of your choice using `cd your/path/here` or create a new directory using `mkdir MyBot && cd MyBot` -8. Now that you've a folder to work in type `> mybot.cxx` to create a file you can work in! -9. Now you can open this file in Visual Studio Code by pressing `CTRL+SHIFT+P` and typing `Remote-WSL: New WSL Window`. This will bring up a new window. In the new window, choose `open folder` and choose the folder you've created prior. Press OK and now you have your Folder opened as a Workspace! +7. Navigate to a directory of your choice using `cd your/path/here` or create a new directory using `mkdir MyBot && cd MyBot`. +8. Now that you've a directory to work in, type `touch mybot.cxx` to create a file you can work in! +9. Now you can open this file in Visual Studio Code by pressing `CTRL+SHIFT+P` and typing `Remote-WSL: New WSL Window`. This will bring up a new window. In the new window, choose `open folder` and choose the directory you've created prior. Press OK and now you have your Folder opened as a Workspace! 10. Add code to your CXX file and compile it by running `g++ -std=c++17 *.cxx -o bot -ldpp` in the same folder as your cxx file. -11. start your bot by typing `./bot`! - +11. Start your bot by typing `./bot`! \ No newline at end of file