diff --git a/.cspell.json b/.cspell.json index 8b263fcb2a..6c41761e10 100644 --- a/.cspell.json +++ b/.cspell.json @@ -135,7 +135,8 @@ "STDCORO", "NOMINMAX", "sku", - "skus" + "skus", + "Codecademy" ], "flagWords": [ "hte" diff --git a/.github/workflows/test-docs-examples.yml b/.github/workflows/test-docs-examples.yml index 497f517f9e..8cf9d6d394 100644 --- a/.github/workflows/test-docs-examples.yml +++ b/.github/workflows/test-docs-examples.yml @@ -35,7 +35,7 @@ jobs: submodules: recursive - name: Install apt packages - run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt-get update && sudo apt-get install -y g++-12 libsodium-dev libopus-dev zlib1g-dev libmpg123-dev liboggz-dev cmake libfmt-dev + run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt-get update && sudo apt-get install -y g++-12 libsodium-dev libopus-dev zlib1g-dev libmpg123-dev liboggz-dev cmake libfmt-dev libopusfile-dev - name: Generate CMake run: mkdir build && cd build && cmake -DDPP_NO_VCPKG=ON -DAVX_TYPE=T_fallback -DDPP_CORO=ON -DCMAKE_BUILD_TYPE=Debug .. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e0dc64c4d8..db3ab8fcfc 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. diff --git a/README.md b/README.md index 0b2fd2cc7f..05439971d3 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@

An incredibly lightweight C++ Discord library


-[![Discord](https://img.shields.io/discord/825407338755653642?style=flat)](https://discord.gg/dpp) +[![Discord](https://img.shields.io/discord/825407338755653642?style=flat)](https://discord.gg/dpp) ![Downloads](https://dl.dpp.dev/dlcount.php) -[![Codacy Badge](https://app.codacy.com/project/badge/Grade/39b054c38bba411d9b25b39524016c9e)](https://www.codacy.com/gh/brainboxdotcc/DPP/dashboard?utm_source=github.com&utm_medium=referral&utm_content=brainboxdotcc/DPP&utm_campaign=Badge_Grade) [![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/7726/badge)](https://bestpractices.coreinfrastructure.org/projects/7726) +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/39b054c38bba411d9b25b39524016c9e)](https://www.codacy.com/gh/brainboxdotcc/DPP/dashboard?utm_source=github.com&utm_medium=referral&utm_content=brainboxdotcc/DPP&utm_campaign=Badge_Grade) [![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/7726/badge)](https://bestpractices.coreinfrastructure.org/projects/7726) [![D++ CI](https://github.com/brainboxdotcc/DPP/actions/workflows/ci.yml/badge.svg)](https://github.com/brainboxdotcc/DPP/actions/workflows/ci.yml) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/brainboxdotcc/DPP/badge)](https://securityscorecards.dev/viewer/?uri=github.com/brainboxdotcc/DPP) [![AUR version](https://img.shields.io/aur/version/dpp)](https://aur.archlinux.org/packages/dpp) @@ -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,48 +45,54 @@ 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; } ``` -You can find more examples in our [example page](https://dpp.dev/md_docpages_03_example_programs.html). +You can find more examples in our [example page](https://dpp.dev/example-programs.html). ## 💻 Supported Systems ### Linux + The library runs ideally on **Linux**. ### Mac OS X and FreeBSD and OpenBSD -The library is well-functional and stable on **Mac OS X** and **FreeBSD** and **OpenBSD** too. + +The library is well-functional and stable on **Mac OS X**, **FreeBSD**, and **OpenBSD** 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 @@ -110,15 +115,13 @@ If you prefer to use Nightly Builds (This is only if you know what you are doing ## 🤝 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 the 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) @@ -129,26 +132,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+) * A supported C++ compiler from the list below ### Supported compilers + * [g++](https://gcc.gnu.org) (version 8 or higher) * [clang](https://clang.llvm.org/) (version 6 or higher) * 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) 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) +* [libopus](https://www.opus-codec.org) +* [libsodium](https://libsodium.org/) ### Included Dependencies (Packaged with the library) -* [nlohmann::json](https://github.com/nlohmann/json) + +* [JSON for Modern C++](https://json.nlohmann.me/) diff --git a/SECURITY.md b/SECURITY.md index 1092e625e3..7a0a9d2f56 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. diff --git a/docpages/01_frequently_asked_questions.md b/docpages/01_frequently_asked_questions.md index cab1e26933..8c82b46f6d 100644 --- a/docpages/01_frequently_asked_questions.md +++ b/docpages/01_frequently_asked_questions.md @@ -1,88 +1,113 @@ \page frequently-asked-questions Frequently Asked Questions (FAQ) -[TOC] +[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 **201,000 servers**, and [Sporks](https://sporks.gg) which has over **3,500 servers**. 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). 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 an 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 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. ## 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). ## 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 + 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 and \ref components2 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. ## 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. ## Does D++ require C++20 support? + No, the library only requires C++17. We have some optional features such as \ref using-coroutines "coroutines" that do require C++20, but they are disabled by default. ## 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 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 in windows, I get "D++ Debug/Release mismatch" + +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? + Depending on which Raspberry Pi version you have, you will need to download a different release binary: @@ -97,13 +122,21 @@ Depending on which Raspberry Pi version you have, you will need to download a di
## 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. ## 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". + +No. We used to support it (and still have our page about it \ref building-a-cpp-discord-bot-in-repl "which you can find here"), however, Replit does not have up-to-date packages, meaning D++ can no longer run. We've attempted to reach out to ask about this but we've had no luck. ## 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, you can enable \ref using-coroutines "coroutines" and use for example `co_await cluster->co_message_get(...)` to retrieve the result in your function. ## 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. + +## What are nightly builds? + +These are automatic builds that happen every night without any human supervision. They allow you to try the latest state of the library without having to build it yourself, but they come without any guarantees. diff --git a/docpages/02_disdppgloss.md b/docpages/02_disdppgloss.md index 773ee12a3c..28f6037b29 100644 --- a/docpages/02_disdppgloss.md +++ b/docpages/02_disdppgloss.md @@ -1,51 +1,55 @@ \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. +[TOC] -#### Glossary +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 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. + +* **Application Command**: See \ref slashcommand. -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 +* **Slashcommand**: 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 `/`. \anchor slashcommand -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/04_building_a_bot.md b/docpages/04_building_a_bot.md index 6cb0e13509..682e5abaaa 100644 --- a/docpages/04_building_a_bot.md +++ b/docpages/04_building_a_bot.md @@ -4,11 +4,10 @@ If you are wanting to build a bot using C++, you're in the right place! The fast 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 diff --git a/docpages/05_example_programs.md b/docpages/05_example_programs.md index f44b5cb95e..e864fa2025 100644 --- a/docpages/05_example_programs.md +++ b/docpages/05_example_programs.md @@ -8,4 +8,4 @@ There are example programs here for all skill levels demonstrating a great many * \subpage using-coroutines * \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 3a1f055f2f..378769c595 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 clusters-shards-guilds +* \subpage thread-model * \subpage voice-model * \subpage coding-standards -* \subpage unit-tests "Unit Tests" -* \subpage lambdas-and-locals "Ownership of local variables and safely transferring into a lambda" -* \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" +* \subpage unit-tests +* \subpage lambdas-and-locals +* \subpage governance +* \subpage roadmap +* \subpage security +* \subpage automating-with-jenkins +* \subpage separate-events diff --git a/docpages/07_deprecated_list.md b/docpages/07_deprecated_list.md index 594b53edef..1673326fe2 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/advanced_reference/automating-with-jenkins.md b/docpages/advanced_reference/automating-with-jenkins.md index cb9ccfc718..ba7f3ef980 100644 --- a/docpages/advanced_reference/automating-with-jenkins.md +++ b/docpages/advanced_reference/automating-with-jenkins.md @@ -1,31 +1,28 @@ -\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. -~~~~~~~~~~ +~~~~~~~~~~bash # 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. - mkdir build - cd build - cmake .. # Begin the CMake initialisation. - cd .. + cmake -B build fi # Commence build. @@ -34,30 +31,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. -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 +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`. diff --git a/docpages/advanced_reference/clusters_shards_and_guilds.md b/docpages/advanced_reference/clusters_shards_and_guilds.md index 13dadc5747..226b6cde4f 100644 --- a/docpages/advanced_reference/clusters_shards_and_guilds.md +++ b/docpages/advanced_reference/clusters_shards_and_guilds.md @@ -1,6 +1,6 @@ -\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" { diff --git a/docpages/advanced_reference/governance.md b/docpages/advanced_reference/governance.md index 8955f2eaaa..b633278309 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 in the Discord server) 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.* diff --git a/docpages/advanced_reference/lambdas_and_locals.md b/docpages/advanced_reference/lambdas_and_locals.md index ea41394066..ad895e28b6 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 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) { @@ -26,7 +26,7 @@ In this scenario, the outer event, `on_message_create` is your tablecloth. The l * 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.... +* 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... @@ -35,7 +35,7 @@ The situation I am trying to describe here is one of object and variable ownersh 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 affect** 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 affect** the value of `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! diff --git a/docpages/advanced_reference/roadmap.md b/docpages/advanced_reference/roadmap.md index ab966dd60b..0914ac759e 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. diff --git a/docpages/advanced_reference/security.md b/docpages/advanced_reference/security.md index 9c87e08eb7..7caefeab6a 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. diff --git a/docpages/advanced_reference/separate-events.md b/docpages/advanced_reference/separate-events.md index dc2764cbca..770ffc8862 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,7 +16,7 @@ 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 @@ -25,24 +25,24 @@ 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); + } } ~~~~~~~~~~ @@ -51,19 +51,20 @@ Now, you'll have a nice area where you can easily see the code, without scrollin 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" +#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); @@ -73,4 +74,4 @@ int main() And there we go! How tidy is that? -Now, the possibilities to this are not limited. If you wish to do this twice (as I explained at first), you can simply have another class and just copy the `bot.on_message_create` line below in the `main.cpp` file and then you can change it to reference the second class, meaning you have two message events firing in two separate classes! \ No newline at end of file +Now, the possibilities to this are not limited. If you wish to do this twice (as I explained at first), you can simply have another class and just copy the `bot.on_message_create` line below in the `main.cpp` file and then you can change it to reference the second class, meaning you have two message events firing in two separate classes! diff --git a/docpages/advanced_reference/thread_model.md b/docpages/advanced_reference/thread_model.md index 274fdde017..d34dc100a8 100644 --- a/docpages/advanced_reference/thread_model.md +++ b/docpages/advanced_reference/thread_model.md @@ -25,18 +25,18 @@ digraph "Thread Model" { "Shard 1" [style=filled, color=4] "Shard 2" "Shard 3..." - label = "Shards (Each is a thread, one per 2500 discord guilds)"; + 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 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" } diff --git a/docpages/advanced_reference/unit_tests.md b/docpages/advanced_reference/unit_tests.md index bdd2a0b61e..a4a50c9ee9 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: @@ -15,14 +15,15 @@ Before running test cases, create a test server for your test bot. You should: 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. - diff --git a/docpages/advanced_reference/voice_model.md b/docpages/advanced_reference/voice_model.md index a7b784c910..10bf1d4419 100644 --- a/docpages/advanced_reference/voice_model.md +++ b/docpages/advanced_reference/voice_model.md @@ -2,123 +2,123 @@ \dot digraph "Example Directory" { - graph [ranksep=1]; - node [colorscheme="blues9", fontname="helvetica"]; - - "Your bot" [style=filled, color=1, shape=rect] - "Discord" [style=filled, color=1, shape=rect] + graph [ranksep=1]; + node [colorscheme="blues9", fontname="helvetica"]; + + "Your bot" [style=filled, color=1, shape=rect] + "Discord" [style=filled, color=1, shape=rect] - subgraph cluster_0 { + subgraph cluster_0 { style=filled; - color=lightgrey; - node [style=filled, color=3, shape=rect] - "guild::connect_member_voice"; - "discord_client::connect_voice"; - - "guild::connect_member_voice" -> "discord_client::connect_voice"; - - label = "This is the front-end of DPP.\n'connect_voice' will now queue a JSON message."; + color=lightgrey; + node [style=filled, color=3, shape=rect] + "guild::connect_member_voice"; + "discord_client::connect_voice"; + + "guild::connect_member_voice" -> "discord_client::connect_voice"; + + label = "This is the front-end of D++.\n'connect_voice' will now queue a JSON message."; } subgraph cluster_1 { style=filled; - color=lightgrey; - node [style=filled, color=2, shape=rect] - "message_queue"; - - label = "This holds all our messages.\n'one_second_timer' reads this data"; + color=lightgrey; + node [style=filled, color=2, shape=rect] + "message_queue"; + + label = "This holds all our messages.\n'one_second_timer' reads this data"; } subgraph cluster_2 { style=filled; - color=lightgrey; - node [style=filled, color=3, shape=rect] - "discord_client::one_second_timer"; - "websocket_client::write"; - "ssl_client::write"; - - "discord_client::one_second_timer" -> "websocket_client::write"; - "websocket_client::write" -> "ssl_client::write"; - "ssl_client::write" -> "Discord"; - - label = "This is where we start sending\nwebsocket connections to Discord."; + color=lightgrey; + node [style=filled, color=3, shape=rect] + "discord_client::one_second_timer"; + "websocket_client::write"; + "ssl_client::write"; + + "discord_client::one_second_timer" -> "websocket_client::write"; + "websocket_client::write" -> "ssl_client::write"; + "ssl_client::write" -> "Discord"; + + label = "This is where we start sending\nwebsocket connections to Discord."; } subgraph cluster_3 { style=filled; - color=lightgrey; - node [style=filled, color=3, shape=rect] - "ssl_client::read_loop"; - "Response from Discord?"; - "No"; - "HTTP/1.1 204 No Content..."; - "HTTP/1.1 101 Switching Protocols"; - - "ssl_client::read_loop" -> "Response from Discord?"; - "Response from Discord?" -> "No"; - "Response from Discord?" -> "HTTP/1.1 204 No Content..."; - "Response from Discord?" -> "HTTP/1.1 101 Switching Protocols"; - "No" -> "ssl_client::read_loop"; - - "Discord" -> "HTTP/1.1 204 No Content..."; - "Discord" -> "HTTP/1.1 101 Switching Protocols"; - - label = "Now, we're waiting for a response from Discord.\nIf we receive 204, we'll start initiating voiceconn. However, if we receive 101, then we can do all the voice stuff."; + color=lightgrey; + node [style=filled, color=3, shape=rect] + "ssl_client::read_loop"; + "Response from Discord?"; + "No"; + "HTTP/1.1 204 No Content..."; + "HTTP/1.1 101 Switching Protocols"; + + "ssl_client::read_loop" -> "Response from Discord?"; + "Response from Discord?" -> "No"; + "Response from Discord?" -> "HTTP/1.1 204 No Content..."; + "Response from Discord?" -> "HTTP/1.1 101 Switching Protocols"; + "No" -> "ssl_client::read_loop"; + + "Discord" -> "HTTP/1.1 204 No Content..."; + "Discord" -> "HTTP/1.1 101 Switching Protocols"; + + label = "Now, we're waiting for a response from Discord.\nIf we receive 204, we'll start initiating voiceconn. However, if we receive 101, then we can do all the voice stuff."; } subgraph cluster_4 { - style=filled; - color=lightgrey; - node [style=filled, color=3, shape=rect] - "voice_state_update::handle"; - "voice_server_update::handle"; - - "HTTP/1.1 204 No Content..." -> "voice_state_update::handle"; - "HTTP/1.1 204 No Content..." -> "voice_server_update::handle"; - - label = "These events can fire in any order. Discord picks whatever it likes."; + style=filled; + color=lightgrey; + node [style=filled, color=3, shape=rect] + "voice_state_update::handle"; + "voice_server_update::handle"; + + "HTTP/1.1 204 No Content..." -> "voice_state_update::handle"; + "HTTP/1.1 204 No Content..." -> "voice_server_update::handle"; + + label = "These events can fire in any order. Discord picks whatever it likes."; } subgraph cluster_5 { style=filled; - color=lightgrey; - node [style=filled, color=3, shape=rect] - "voiceconn::connect"; - "new discord_voice_client" - "websocket_client::connect" - "discord_voice_client::run" - "discord_voice_client::thread_run" - - "voiceconn::connect" -> "new discord_voice_client"; - "new discord_voice_client" -> "websocket_client::connect"; - "websocket_client::connect" -> "websocket_client::write"; + color=lightgrey; + node [style=filled, color=3, shape=rect] + "voiceconn::connect"; + "new discord_voice_client" + "websocket_client::connect" + "discord_voice_client::run" + "discord_voice_client::thread_run" + + "voiceconn::connect" -> "new discord_voice_client"; + "new discord_voice_client" -> "websocket_client::connect"; + "websocket_client::connect" -> "websocket_client::write"; - "voiceconn::connect" -> "discord_voice_client::run" [label="Once websocket_client has finished"]; - "discord_voice_client::run" -> "discord_voice_client::thread_run"; - "discord_voice_client::thread_run" -> "ssl_client::read_loop"; - - label = "Voice initalisation.\nThis will only fire when 'voice_server_update' AND 'voice_state_update' has fired.\nIf everything goes well, Discord should send back '101 Switching Protocals'."; + "voiceconn::connect" -> "discord_voice_client::run" [label="Once websocket_client has finished"]; + "discord_voice_client::run" -> "discord_voice_client::thread_run"; + "discord_voice_client::thread_run" -> "ssl_client::read_loop"; + + label = "Voice initalisation.\nThis will only fire when 'voice_server_update' AND 'voice_state_update' has fired.\nIf everything goes well, Discord should send back '101 Switching Protocals'."; } subgraph cluster_6 { style=filled; - color=lightgrey; - node [style=filled, color=3, shape=rect] - "discord_voice_client::handle_frame"; - - "HTTP/1.1 101 Switching Protocols" -> "discord_voice_client::handle_frame"; - - label = "Do the voice stuff."; + color=lightgrey; + node [style=filled, color=3, shape=rect] + "discord_voice_client::handle_frame"; + + "HTTP/1.1 101 Switching Protocols" -> "discord_voice_client::handle_frame"; + + label = "Do the voice stuff."; } - "Your bot" -> "guild::connect_member_voice"; - - "discord_client::connect_voice" -> "message_queue"; - - "message_queue" -> "discord_client::one_second_timer"; - "discord_client::one_second_timer" -> "message_queue"; - - "voice_state_update::handle" -> "voiceconn::connect"; - "voice_server_update::handle" -> "voiceconn::connect"; + "Your bot" -> "guild::connect_member_voice"; + + "discord_client::connect_voice" -> "message_queue"; + + "message_queue" -> "discord_client::one_second_timer"; + "discord_client::one_second_timer" -> "message_queue"; + + "voice_state_update::handle" -> "voiceconn::connect"; + "voice_server_update::handle" -> "voiceconn::connect"; } \enddot diff --git a/docpages/building/02_build.md b/docpages/building/02_build.md index b679e151b5..3d1d6cf870 100644 --- a/docpages/building/02_build.md +++ b/docpages/building/02_build.md @@ -1,11 +1,11 @@ -\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 * \subpage buildopenbsd -@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. diff --git a/docpages/building/linux.md b/docpages/building/linux.md index a9e9701a56..9abad1ce41 100644 --- a/docpages/building/linux.md +++ b/docpages/building/linux.md @@ -4,37 +4,45 @@ ## 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 \include{doc} install_prebuilt_footer.dox **Have fun!** - - diff --git a/docpages/building/osx.md b/docpages/building/osx.md index f9f7aa78a6..a54a25b4c6 100644 --- a/docpages/building/osx.md +++ b/docpages/building/osx.md @@ -1,53 +1,65 @@ \page buildosx Building on OSX ## 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 an [installation guide 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 \include{doc} install_prebuilt_footer.dox **Have fun!** - diff --git a/docpages/building/windows.md b/docpages/building/windows.md index 20643eff4c..166565fe1a 100644 --- a/docpages/building/windows.md +++ b/docpages/building/windows.md @@ -4,26 +4,27 @@ 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 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 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 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`. +**Have fun!** diff --git a/docpages/example_code/CMakeLists.txt b/docpages/example_code/CMakeLists.txt index 2f127da942..87c7713f2b 100644 --- a/docpages/example_code/CMakeLists.txt +++ b/docpages/example_code/CMakeLists.txt @@ -41,5 +41,6 @@ foreach (example ${example_list}) get_filename_component(examplename ${example} NAME) message(STATUS "Found example '${Esc}[1;34m${examplename}${Esc}[m'") add_executable(${examplename}_out ${example}) - target_link_libraries(${examplename}_out dl dpp mpg123 oggz) + target_link_libraries(${examplename}_out dl dpp mpg123 oggz ogg opusfile opus) + include_directories(/usr/include/opus) endforeach(example) diff --git a/docpages/example_code/oggopus.cpp b/docpages/example_code/oggopus.cpp index 6782f59cef..5c5d3e8952 100644 --- a/docpages/example_code/oggopus.cpp +++ b/docpages/example_code/oggopus.cpp @@ -1,13 +1,13 @@ #include #include #include - #include #include #include -#include +#include +#include -int main() { +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. * @@ -15,7 +15,6 @@ int main() { * 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()); @@ -25,6 +24,7 @@ int main() { /* 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); @@ -37,6 +37,7 @@ int main() { /* Tell the user we joined their channel. */ event.reply("Joined your channel!"); } else if (event.command.get_command_name() == "play") { + /* Get the voice channel the bot is in, in this current guild. */ dpp::voiceconn* v = event.from->get_voice(event.command.guild_id); @@ -46,51 +47,109 @@ int main() { return; } - // load the audio file with oggz - OGGZ *track_og = oggz_open("/path/to/opus.ogg", OGGZ_READ); + ogg_sync_state oy; + ogg_stream_state os; + ogg_page og; + ogg_packet op; + OpusHead header; + char *buffer; - /* If there was an issue reading the file, tell the user and stop */ - if (!track_og) { - fprintf(stderr, "Error opening file\n"); - event.reply("There was an issue opening the file!"); - return; + FILE *fd; + + fd = fopen("/path/to/opus.ogg", "rb"); + + fseek(fd, 0L, SEEK_END); + size_t sz = ftell(fd); + rewind(fd); + + ogg_sync_init(&oy); + + buffer = ogg_sync_buffer(&oy, sz); + fread(buffer, 1, sz, fd); + + ogg_sync_wrote(&oy, sz); + + /** + * We must first verify that the stream is indeed ogg opus + * by reading the header and parsing it + */ + if (ogg_sync_pageout(&oy, &og) != 1) { + fprintf(stderr,"Does not appear to be ogg stream.\n"); + exit(1); + } + + ogg_stream_init(&os, ogg_page_serialno(&og)); + + if (ogg_stream_pagein(&os,&og) < 0) { + fprintf(stderr,"Error reading initial page of ogg stream.\n"); + exit(1); + } + + if (ogg_stream_packetout(&os,&op) != 1) { + fprintf(stderr,"Error reading header packet of ogg stream.\n"); + exit(1); + } + + /* We must ensure that the ogg stream actually contains opus data */ + if (!(op.bytes > 8 && !memcmp("OpusHead", op.packet, 8))) { + fprintf(stderr,"Not an ogg opus stream.\n"); + exit(1); + } + + /* Parse the header to get stream info */ + int err = opus_head_parse(&header, op.packet, op.bytes); + if (err) { + fprintf(stderr,"Not a ogg opus stream\n"); + exit(1); + } + + /* Now we ensure the encoding is correct for Discord */ + if (header.channel_count != 2 && header.input_sample_rate != 48000) { + fprintf(stderr,"Wrong encoding for Discord, must be 48000Hz sample rate with 2 channels.\n"); + exit(1); } - // set read callback, this callback will be called on packets with the serialno, - // -1 means every packet will be handled with this callback - oggz_set_read_callback( - track_og, -1, - [](OGGZ *oggz, oggz_packet *packet, long serialno, - void *user_data) { - dpp::voiceconn *voiceconn = (dpp::voiceconn *)user_data; - - // send the audio - voiceconn->voiceclient->send_audio_opus(packet->op.packet, - packet->op.bytes); - - // make sure to always return 0 here, read more on oggz documentation - return 0; - }, - // this will be the value of void *user_data - (void *)v - ); - - // read loop - while (v && v->voiceclient && !v->voiceclient->terminating) { - // you can tweak this to whatever. Here I use BUFSIZ, defined in - // stdio.h as 8192 - static const constexpr long CHUNK_READ = BUFSIZ * 2; - - const long read_bytes = oggz_read(track_og, CHUNK_READ); - - // break on eof - if (!read_bytes) { - break; + /* Now loop though all the pages and send the packets to the vc */ + while (ogg_sync_pageout(&oy, &og) == 1) { + ogg_stream_init(&os, ogg_page_serialno(&og)); + + if(ogg_stream_pagein(&os,&og)<0) { + fprintf(stderr,"Error reading page of Ogg bitstream data.\n"); + exit(1); + } + + while (ogg_stream_packetout(&os,&op) != 0) { + + /* Read remaining headers */ + if (op.bytes > 8 && !memcmp("OpusHead", op.packet, 8)) { + int err = opus_head_parse(&header, op.packet, op.bytes); + if (err) { + fprintf(stderr,"Not a ogg opus stream\n"); + exit(1); + } + + if (header.channel_count != 2 && header.input_sample_rate != 48000) { + fprintf(stderr,"Wrong encoding for Discord, must be 48000Hz sample rate with 2 channels.\n"); + exit(1); + } + + continue; + } + + /* Skip the opus tags */ + if (op.bytes > 8 && !memcmp("OpusTags", op.packet, 8)) + continue; + + /* Send the audio */ + int samples = opus_packet_get_samples_per_frame(op.packet, 48000); + + v->voiceclient->send_audio_opus(op.packet, op.bytes, samples / 48); } } - // don't forget to free the memory - oggz_close(track_og); + /* Cleanup */ + ogg_stream_clear(&os); + ogg_sync_clear(&oy); event.reply("Finished playing the audio file!"); } @@ -108,6 +167,6 @@ int main() { /* Start bot */ bot.start(dpp::st_wait); - + return 0; } diff --git a/docpages/example_code/oggopus2.cpp b/docpages/example_code/oggopus2.cpp new file mode 100644 index 0000000000..46956a553c --- /dev/null +++ b/docpages/example_code/oggopus2.cpp @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include +#include +#include + +int main() { + /* Load an ogg opus file into memory. + * The bot expects opus packets to be 2 channel stereo, 48000Hz. + * + * 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()); + + /* The event is fired when someone issues your commands */ + bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) { + + /* Check which command they ran */ + if (event.command.get_command_name() == "join") { + /* Get the guild */ + dpp::guild* g = dpp::find_guild(event.command.guild_id); + + /* Attempt to connect to a voice channel, returns false if we fail to connect. */ + if (!g->connect_member_voice(event.command.get_issuing_user().id)) { + event.reply("You don't seem to be in a voice channel!"); + return; + } + + /* Tell the user we joined their channel. */ + event.reply("Joined your channel!"); + } else if (event.command.get_command_name() == "play") { + /* Get the voice channel the bot is in, in this current guild. */ + dpp::voiceconn* v = event.from->get_voice(event.command.guild_id); + + /* If the voice channel was invalid, or there is an issue with it, then tell the user. */ + if (!v || !v->voiceclient || !v->voiceclient->is_ready()) { + event.reply("There was an issue with getting the voice channel. Make sure I'm in a voice channel!"); + return; + } + + /* load the audio file with oggz */ + OGGZ *track_og = oggz_open("/path/to/opus.ogg", OGGZ_READ); + + /* If there was an issue reading the file, tell the user and stop */ + if (!track_og) { + fprintf(stderr, "Error opening file\n"); + event.reply("There was an issue opening the file!"); + return; + } + + /* set read callback, this callback will be called on packets with the serialno, + * -1 means every packet will be handled with this callback. + */ + oggz_set_read_callback( + track_og, -1, + [](OGGZ *oggz, oggz_packet *packet, long serialno, + void *user_data) { + dpp::voiceconn *voiceconn = (dpp::voiceconn *)user_data; + + /* send the audio */ + voiceconn->voiceclient->send_audio_opus(packet->op.packet, + packet->op.bytes); + + /* make sure to always return 0 here, read more on oggz documentation */ + return 0; + }, + /* this will be the value of void *user_data */ + (void *)v + ); + + // read loop + while (v && v->voiceclient && !v->voiceclient->terminating) { + /* you can tweak this to whatever. Here I use BUFSIZ, defined in + * stdio.h as 8192. + */ + static const constexpr long CHUNK_READ = BUFSIZ * 2; + + const long read_bytes = oggz_read(track_og, CHUNK_READ); + + /* break on eof */ + if (!read_bytes) { + break; + } + } + + /* Don't forget to free the memory */ + oggz_close(track_og); + + event.reply("Finished playing the audio file!"); + } + }); + + bot.on_ready([&bot](const dpp::ready_t & event) { + if (dpp::run_once()) { + /* Create a new command. */ + dpp::slashcommand joincommand("join", "Joins your voice channel.", bot.me.id); + dpp::slashcommand playcommand("play", "Plays an ogg file.", bot.me.id); + + bot.global_bulk_command_create({ joincommand, playcommand }); + } + }); + + /* Start bot */ + bot.start(dpp::st_wait); + + return 0; +} diff --git a/docpages/example_programs/interactions_and_components.md b/docpages/example_programs/interactions_and_components.md index 8316dffef8..0112f192bb 100644 --- a/docpages/example_programs/interactions_and_components.md +++ b/docpages/example_programs/interactions_and_components.md @@ -2,9 +2,9 @@ Interactions are a unified way provided by Discord to handle \ref slashcommands "slash commands" and \ref components-menu "component interactions", such as \ref components "clicking a button". Slash commands are much better than message commands as they are not rate limited as much, meaning your bot can handle a lot more at once. They also contain a lot of data about a command, for example by making a command take a user as a parameter, \ref resolved-objects "the entire user object will be contained in the interaction" so you do not have to fetch it yourself, avoiding even more rate limits! -* \subpage slashcommands-menu "Slash Commands" -* \subpage user-only-messages "Ephemeral replies ('Only you can see this' replies)" +* \subpage slashcommands-menu +* \subpage user-only-messages * \subpage resolved-objects * \subpage components-menu -* \subpage modal-dialog-interactions "Modals" -* \subpage context-menu "Context Menus" +* \subpage modal-dialog-interactions +* \subpage context-menu diff --git a/docpages/example_programs/interactions_and_components/components-menu.md b/docpages/example_programs/interactions_and_components/components-menu.md index 2c58e530c8..8dcf115593 100644 --- a/docpages/example_programs/interactions_and_components/components-menu.md +++ b/docpages/example_programs/interactions_and_components/components-menu.md @@ -1,4 +1,4 @@ -\page components-menu Message components +\page components-menu Message Components Components are anything that can be attached to a message or a \ref modal-dialog-interactions "modal" and interacted with, for example buttons and select menus. Due to being \ref interactions-and-components "interactions", they benefit from a low rate limit and are much more efficient than the old ways of using reactions for this purpose. diff --git a/docpages/example_programs/interactions_and_components/components/components.md b/docpages/example_programs/interactions_and_components/components/components.md index dfadf95004..5052b853d7 100644 --- a/docpages/example_programs/interactions_and_components/components/components.md +++ b/docpages/example_programs/interactions_and_components/components/components.md @@ -1,11 +1,9 @@ -\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. \include{cpp} components.cpp When the feature is functioning, the code below will produce buttons on the reply message like in the image below: \image html button.png - diff --git a/docpages/example_programs/interactions_and_components/components/components2.md b/docpages/example_programs/interactions_and_components/components/components2.md index 5d306ac47c..742a8d3862 100644 --- a/docpages/example_programs/interactions_and_components/components/components2.md +++ b/docpages/example_programs/interactions_and_components/components/components2.md @@ -1,10 +1,9 @@ -\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. \include{cpp} components2.cpp This code will send a different message for correct and incorrect answers. \image html button_2.png - diff --git a/docpages/example_programs/interactions_and_components/components/components3.md b/docpages/example_programs/interactions_and_components/components/components3.md index cc4412141e..91d8f44933 100644 --- a/docpages/example_programs/interactions_and_components/components/components3.md +++ b/docpages/example_programs/interactions_and_components/components/components3.md @@ -1,4 +1,4 @@ -\page components3 Using select menu components +\page components3 Using Select Menu Components This tutorial will cover creating two types of select menus: - A generic select menu with just text @@ -8,7 +8,9 @@ This first example demonstrates creating a select menu, receiving select menu cl \include{cpp} components3.cpp -This second example demonstrates creating a role select menu that is auto-populated by discord, and allowing people to select two options! +This second example demonstrates: +- Creating a role select menu that is auto-populated by Discord +- Allowing users to select two options! \note This type of select menu, along with other types (these types being: user, role, mentionable, and channel), always auto-fill. You never need to define the data in these types of select menus. All select menu types allow you to select multiple options. diff --git a/docpages/example_programs/interactions_and_components/components/default_select_value.md b/docpages/example_programs/interactions_and_components/components/default_select_value.md index 7c39979fcc..248c6eecac 100644 --- a/docpages/example_programs/interactions_and_components/components/default_select_value.md +++ b/docpages/example_programs/interactions_and_components/components/default_select_value.md @@ -1,4 +1,4 @@ -\page default_select_value Setting default values on select menus. +\page default_select_value Setting Default Values on Select Menus. This tutorial will cover how to set the default value for a select menu (that isn't a text select menu)! diff --git a/docpages/example_programs/interactions_and_components/modal_dialog_interactions.md b/docpages/example_programs/interactions_and_components/modal_dialog_interactions.md index bb63048202..652eee5a50 100644 --- a/docpages/example_programs/interactions_and_components/modal_dialog_interactions.md +++ b/docpages/example_programs/interactions_and_components/modal_dialog_interactions.md @@ -1,4 +1,4 @@ -\page modal-dialog-interactions Modal Dialog Interactions +\page modal-dialog-interactions Modals 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. diff --git a/docpages/example_programs/interactions_and_components/slashcommands-menu.md b/docpages/example_programs/interactions_and_components/slashcommands-menu.md index 16a7baf4f6..c1b8aedccb 100644 --- a/docpages/example_programs/interactions_and_components/slashcommands-menu.md +++ b/docpages/example_programs/interactions_and_components/slashcommands-menu.md @@ -1,6 +1,6 @@ \page slashcommands-menu Slash commands -Here you will find examples on how to use slash commands, subcommands, and different types or parameters. +Here, you will find examples on how to use slash commands, subcommands, and different types or parameters. * \subpage slashcommands "Using Slash Commands" * \subpage clearing_slashcommands diff --git a/docpages/example_programs/interactions_and_components/slashcommands/autocomplete.md b/docpages/example_programs/interactions_and_components/slashcommands/autocomplete.md index 6ee9230ce6..df94212828 100644 --- a/docpages/example_programs/interactions_and_components/slashcommands/autocomplete.md +++ b/docpages/example_programs/interactions_and_components/slashcommands/autocomplete.md @@ -1,4 +1,4 @@ -\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: diff --git a/docpages/example_programs/interactions_and_components/slashcommands/clearing_slashcommands.md b/docpages/example_programs/interactions_and_components/slashcommands/clearing_slashcommands.md index aa15e53aab..9869cc4141 100644 --- a/docpages/example_programs/interactions_and_components/slashcommands/clearing_slashcommands.md +++ b/docpages/example_programs/interactions_and_components/slashcommands/clearing_slashcommands.md @@ -1,4 +1,4 @@ -\page clearing_slashcommands Clearing registered commands +\page clearing_slashcommands Clearing Registered Commands After a while of creating commands, you may start to wonder "hm, how can I clear these?". Well, this tutorial covers it! All you have to do is simply call dpp::cluster::global_bulk_command_delete or dpp::cluster::guild_bulk_command_delete. diff --git a/docpages/example_programs/interactions_and_components/slashcommands/commandhandler.md b/docpages/example_programs/interactions_and_components/slashcommands/commandhandler.md index 69b84caf6b..e617d6adaf 100644 --- a/docpages/example_programs/interactions_and_components/slashcommands/commandhandler.md +++ b/docpages/example_programs/interactions_and_components/slashcommands/commandhandler.md @@ -1,4 +1,4 @@ -\page commandhandler Using a command handler object +\page commandhandler Using a Command Handler Object 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 diff --git a/docpages/example_programs/interactions_and_components/slashcommands/slashcommands.md b/docpages/example_programs/interactions_and_components/slashcommands/slashcommands.md index 1f549b7d6c..2fb4fba5be 100644 --- a/docpages/example_programs/interactions_and_components/slashcommands/slashcommands.md +++ b/docpages/example_programs/interactions_and_components/slashcommands/slashcommands.md @@ -4,9 +4,9 @@ Slash commands and interactions are a newer feature of Discord which allow a bot 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 dpp::cluster::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. diff --git a/docpages/example_programs/interactions_and_components/slashcommands/subcommands.md b/docpages/example_programs/interactions_and_components/slashcommands/subcommands.md index 68755bd682..08d36fa602 100644 --- a/docpages/example_programs/interactions_and_components/slashcommands/subcommands.md +++ b/docpages/example_programs/interactions_and_components/slashcommands/subcommands.md @@ -1,4 +1,4 @@ -\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. diff --git a/docpages/example_programs/interactions_and_components/slashcommands/upload_parameter.md b/docpages/example_programs/interactions_and_components/slashcommands/upload_parameter.md index d73e878835..80f0ef6790 100644 --- a/docpages/example_programs/interactions_and_components/slashcommands/upload_parameter.md +++ b/docpages/example_programs/interactions_and_components/slashcommands/upload_parameter.md @@ -1,7 +1,7 @@ -\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 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 7576efc0d1..dbea215616 100644 --- a/docpages/example_programs/interactions_and_components/user-only-messages.md +++ b/docpages/example_programs/interactions_and_components/user-only-messages.md @@ -1,6 +1,6 @@ -\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! diff --git a/docpages/example_programs/misc.md b/docpages/example_programs/misc.md index 3ff56d64a7..c7ba9cd0f2 100644 --- a/docpages/example_programs/misc.md +++ b/docpages/example_programs/misc.md @@ -2,12 +2,12 @@ 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 making_a_http_request +* \subpage spdlog * \subpage editing-channels-and-messages * \subpage making_threads -* \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 caching-messages +* \subpage collecting-reactions +* \subpage cpp-eval-command-discord +* \subpage checking-member-permissions * \subpage setting_status diff --git a/docpages/example_programs/misc/cache_messages.md b/docpages/example_programs/misc/cache_messages.md index 25c9782724..ede4256194 100644 --- a/docpages/example_programs/misc/cache_messages.md +++ b/docpages/example_programs/misc/cache_messages.md @@ -4,8 +4,6 @@ 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. \include{cpp} cache_messages.cpp diff --git a/docpages/example_programs/misc/checking-member-permissions.md b/docpages/example_programs/misc/checking-member-permissions.md index b10bdab43e..364234f7ad 100644 --- a/docpages/example_programs/misc/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,7 +45,7 @@ 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; } @@ -79,14 +73,13 @@ 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; } diff --git a/docpages/example_programs/misc/collect_reactions.md b/docpages/example_programs/misc/collect_reactions.md index cbd671e5fa..b1967182cf 100644 --- a/docpages/example_programs/misc/collect_reactions.md +++ b/docpages/example_programs/misc/collect_reactions.md @@ -1,8 +1,8 @@ \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. +In the example below, we will use it to collect all reactions on a message. \include{cpp} collect_reactions.cpp diff --git a/docpages/example_programs/misc/eval.md b/docpages/example_programs/misc/eval.md index 4eb4972eb7..ec026214e3 100644 --- a/docpages/example_programs/misc/eval.md +++ b/docpages/example_programs/misc/eval.md @@ -1,45 +1,42 @@ -\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. \include{cpp} eval.h -#### eval.cpp +### eval.cpp This is the main body of the example program. \include{cpp} eval.cpp -### Compilation +## Compilation To compile this program you must link against `libdl`. It is also critically important to include the `-rdynamic` flag. For example: @@ -47,7 +44,7 @@ To compile this program you must link against `libdl`. It is also critically imp g++ -std=c++17 -rdynamic -oeval eval.cpp -ldpp -ldl ``` -### Example usage +## Example usage \image html eval_example.png diff --git a/docpages/example_programs/misc/http_request.md b/docpages/example_programs/misc/http_request.md index 523a781fda..39572856ed 100644 --- a/docpages/example_programs/misc/http_request.md +++ b/docpages/example_programs/misc/http_request.md @@ -1,4 +1,4 @@ -\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: diff --git a/docpages/example_programs/misc/making_threads.md b/docpages/example_programs/misc/making_threads.md index c207cbf91c..c34dfab88c 100644 --- a/docpages/example_programs/misc/making_threads.md +++ b/docpages/example_programs/misc/making_threads.md @@ -1,4 +1,4 @@ -\page making_threads Creating and interacting with threads +\page making_threads Creating and Interacting with Threads A new feature added to Discord recently is `Threads`, these allow you to break off a message into a different "channel", without creating a whole new channel. There are also other types of "thread channels", one example being a `forums channel`. This type of channel only contains threads, meaning you can't send messages in it so if you want to make one of them, be careful about trying to send a message in it! diff --git a/docpages/example_programs/misc/setting_status.md b/docpages/example_programs/misc/setting_status.md index 189eed85d3..2ef25a5e2b 100644 --- a/docpages/example_programs/misc/setting_status.md +++ b/docpages/example_programs/misc/setting_status.md @@ -1,4 +1,4 @@ -\page setting_status Setting the bot's status +\page setting_status Setting the Bot's Status A bot status is pretty cool, and it'd be cooler if you knew how to do it! This tutorial will cover how to set the bot status to say `Playing games!`, as well as covering how to set the status to the amount of guilds every two minutes. diff --git a/docpages/example_programs/misc/spdlog.md b/docpages/example_programs/misc/spdlog.md index 9edeb7a226..45af0f2ae9 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"; diff --git a/docpages/example_programs/music_and_audio.md b/docpages/example_programs/music_and_audio.md index 5c222df106..942964b701 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 diff --git a/docpages/example_programs/music_and_audio/join_voice.md b/docpages/example_programs/music_and_audio/join_voice.md index cfbf3d0f97..919896d38b 100644 --- a/docpages/example_programs/music_and_audio/join_voice.md +++ b/docpages/example_programs/music_and_audio/join_voice.md @@ -1,4 +1,4 @@ -\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. diff --git a/docpages/example_programs/music_and_audio/mp3.md b/docpages/example_programs/music_and_audio/mp3.md index ee7db3212d..b316a0cd68 100644 --- a/docpages/example_programs/music_and_audio/mp3.md +++ b/docpages/example_programs/music_and_audio/mp3.md @@ -1,4 +1,4 @@ -\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: @@ -6,5 +6,8 @@ To stream MP3 files via D++ you need to link an additional dependency to your bo 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 +``` +\include{doc} install_prebuilt_footer.dox diff --git a/docpages/example_programs/music_and_audio/oggopus.md b/docpages/example_programs/music_and_audio/oggopus.md index c41113dd54..c72996c3da 100644 --- a/docpages/example_programs/music_and_audio/oggopus.md +++ b/docpages/example_programs/music_and_audio/oggopus.md @@ -2,191 +2,13 @@ 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} -#include -#include -#include - -#include -#include -#include -#include -#include - -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. - * - * 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()); - - /* The event is fired when someone issues your commands */ - bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) { - - /* Check which command they ran */ - if (event.command.get_command_name() == "join") { - - /* Get the guild */ - dpp::guild* g = dpp::find_guild(event.command.guild_id); - - /* Attempt to connect to a voice channel, returns false if we fail to connect. */ - if (!g->connect_member_voice(event.command.get_issuing_user().id)) { - event.reply("You don't seem to be in a voice channel!"); - return; - } - - /* Tell the user we joined their channel. */ - event.reply("Joined your channel!"); - } else if (event.command.get_command_name() == "play") { - - /* Get the voice channel the bot is in, in this current guild. */ - dpp::voiceconn* v = event.from->get_voice(event.channel.guild_id); - - /* If the voice channel was invalid, or there is an issue with it, then tell the user. */ - if (!v || !v->voiceclient || !v->voiceclient->is_ready()) { - event.reply("There was an issue with getting the voice channel. Make sure I'm in a voice channel!"); - return; - } - - ogg_sync_state oy; - ogg_stream_state os; - ogg_page og; - ogg_packet op; - OpusHead header; - char *buffer; - - FILE *fd; - - fd = fopen("/path/to/opus.ogg", "rb"); - - fseek(fd, 0L, SEEK_END); - size_t sz = ftell(fd); - rewind(fd); - - ogg_sync_init(&oy); - - int eos = 0; - int i; - - buffer = ogg_sync_buffer(&oy, sz); - fread(buffer, 1, sz, fd); - - ogg_sync_wrote(&oy, sz); - - /** - * We must first verify that the stream is indeed ogg opus - * by reading the header and parsing it - */ - if (ogg_sync_pageout(&oy, &og) != 1) { - fprintf(stderr,"Does not appear to be ogg stream.\n"); - exit(1); - } - - ogg_stream_init(&os, ogg_page_serialno(&og)); - - if (ogg_stream_pagein(&os,&og) < 0) { - fprintf(stderr,"Error reading initial page of ogg stream.\n"); - exit(1); - } - - if (ogg_stream_packetout(&os,&op) != 1) { - fprintf(stderr,"Error reading header packet of ogg stream.\n"); - exit(1); - } - - /* We must ensure that the ogg stream actually contains opus data */ - if (!(op.bytes > 8 && !memcmp("OpusHead", op.packet, 8))) { - fprintf(stderr,"Not an ogg opus stream.\n"); - exit(1); - } - - /* Parse the header to get stream info */ - int err = opus_head_parse(&header, op.packet, op.bytes); - if (err) { - fprintf(stderr,"Not a ogg opus stream\n"); - exit(1); - } - - /* Now we ensure the encoding is correct for Discord */ - if (header.channel_count != 2 && header.input_sample_rate != 48000) { - fprintf(stderr,"Wrong encoding for Discord, must be 48000Hz sample rate with 2 channels.\n"); - exit(1); - } - - /* Now loop though all the pages and send the packets to the vc */ - while (ogg_sync_pageout(&oy, &og) == 1) { - ogg_stream_init(&os, ogg_page_serialno(&og)); - - if(ogg_stream_pagein(&os,&og)<0) { - fprintf(stderr,"Error reading page of Ogg bitstream data.\n"); - exit(1); - } - - while (ogg_stream_packetout(&os,&op) != 0) { - - /* Read remaining headers */ - if (op.bytes > 8 && !memcmp("OpusHead", op.packet, 8)) { - int err = opus_head_parse(&header, op.packet, op.bytes); - if (err) { - fprintf(stderr,"Not a ogg opus stream\n"); - exit(1); - } - - if (header.channel_count != 2 && header.input_sample_rate != 48000) { - fprintf(stderr,"Wrong encoding for Discord, must be 48000Hz sample rate with 2 channels.\n"); - exit(1); - } - - continue; - } - - /* Skip the opus tags */ - if (op.bytes > 8 && !memcmp("OpusTags", op.packet, 8)) - continue; - - /* Send the audio */ - int samples = opus_packet_get_samples_per_frame(op.packet, 48000); - - v->voiceclient->send_audio_opus(op.packet, op.bytes, samples / 48); - } - } - - /* Cleanup */ - ogg_stream_clear(&os); - ogg_sync_clear(&oy); - - event.reply("Finished playing the audio file!"); - } - }); - - bot.on_ready([&bot](const dpp::ready_t & event) { - if (dpp::run_once()) { - - /* Create a new command. */ - dpp::slashcommand joincommand("join", "Joins your voice channel.", bot.me.id); - - dpp::slashcommand playcommand("play", "Plays an ogg file.", bot.me.id); - - bot.global_bulk_command_create({joincommand, playcommand}); - } - }); - - /* Start bot */ - bot.start(dpp::st_wait); - - return 0; -} -~~~~~~~~~~~~~~~~~~~~~~~~~ +\include{cpp} oggopus.cpp 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 @@ -194,8 +16,10 @@ 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/). -\include{cpp} oggopus.cpp +\include{cpp} oggopus2.cpp 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 022680d82c..ce113890c1 100644 --- a/docpages/example_programs/music_and_audio/record_user.md +++ b/docpages/example_programs/music_and_audio/record_user.md @@ -1,7 +1,7 @@ -\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. +DPP 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. +\note Voice receiving by bots is not officially supported by the Discord API. We cannot guarantee that this feature will work in the future. \include{cpp} record_user.cpp diff --git a/docpages/example_programs/music_and_audio/soundboard.md b/docpages/example_programs/music_and_audio/soundboard.md index 52818f6cab..98ea563161 100644 --- a/docpages/example_programs/music_and_audio/soundboard.md +++ b/docpages/example_programs/music_and_audio/soundboard.md @@ -1,5 +1,5 @@ \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 . \include{cpp} soundboard.cpp \ No newline at end of file diff --git a/docpages/example_programs/the_basics.md b/docpages/example_programs/the_basics.md index be54d97478..9bf2e060d1 100644 --- a/docpages/example_programs/the_basics.md +++ b/docpages/example_programs/the_basics.md @@ -2,11 +2,11 @@ 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 firstbot +* \subpage embed-message * \subpage private-messaging -* \subpage attach-file "Attaching a file" -* \subpage webhooks "Webhooks" -* \subpage callback-functions "Using Callback Functions" +* \subpage attach-file +* \subpage webhooks +* \subpage callback-functions * \subpage using-cache -* \subpage detecting-messages "Listening to messages" +* \subpage detecting-messages diff --git a/docpages/example_programs/the_basics/attachments.md b/docpages/example_programs/the_basics/attachments.md index 1a3668ae18..2d115943cd 100644 --- a/docpages/example_programs/the_basics/attachments.md +++ b/docpages/example_programs/the_basics/attachments.md @@ -1,20 +1,16 @@ -\page attach-file Attaching a file to a message +\page attach-file Attaching a File to a Message -Attached files must be locally stored. +To attach a local file to an message, you can use dpp::utility::read_file. It's a helper function from D++ that allows you to read the file's content and sent it to discord. -To attach a file to a message, you can upload a local image. - -D++ has this helper function to read a file: dpp::utility::read_file. - -An example program: +An example of this: \include{cpp} attachments1.cpp -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 URL aren't possible. But there's a workaround for this! You can download the file and then attach it to the message. -To make requests, D++ also has a helper function: dpp::cluster::request. +Amazingly, D++ also has a function for this! You can use dpp::cluster::request to make HTTP requests, allowing you to go ahead and pull the content from a URL. -The following example program shows how to request a file and attach it to a message. +The following example program shows how to request a file and attach it to a message: \include{cpp} attachments2.cpp diff --git a/docpages/example_programs/the_basics/firstbot.md b/docpages/example_programs/the_basics/firstbot.md index 76037907c5..c0b4296a49 100644 --- a/docpages/example_programs/the_basics/firstbot.md +++ b/docpages/example_programs/the_basics/firstbot.md @@ -17,12 +17,11 @@ The two programs can be seen side by side below: - -~~~~~~~~~~~~~~~{.js} +~~~~~~~~~~~~~~~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: [] }); @@ -42,24 +41,22 @@ bot.once('ready', async () => { }); }); - 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 `! \include{cpp} firstbot1.cpp -### 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. @@ -67,21 +64,19 @@ You can instantiate this class as shown below. Remember to put your bot token in \include{cpp} firstbot2.cpp -### 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). \include{cpp} firstbot3.cpp -### 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: \include{cpp} firstbot4.cpp -### 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!`: @@ -89,7 +84,7 @@ Attaching to an event is a good start, but to make a bot you should actually put Let's break down the code in the `on_slashcommand` event so that we can discuss what it is doing: -~~~~~~~~~~~~~~~~~~~~~~~{.cpp} +~~~~~~~~~~~~~~~~~~~~~~~cpp bot.on_slashcommand([](const dpp::slashcommand_t& event) { if (event.command.get_command_name() == "ping") { event.reply("Pong!"); @@ -101,27 +96,29 @@ This code is simply comparing the command name `event.command.get_command_name() 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. \include{cpp} firstbot6.cpp -### 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 using the D++ library! diff --git a/docpages/install/install-arch-aur.md b/docpages/install/install-arch-aur.md index 041216e129..2e76432ae0 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,7 +23,7 @@ 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 ``` diff --git a/docpages/install/install-linux-deb.md b/docpages/install/install-linux-deb.md index 6ffb75da67..8751b83fee 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,7 +16,7 @@ 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 ``` diff --git a/docpages/install/install-linux-rpm.md b/docpages/install/install-linux-rpm.md index a5faea8350..1b2a739482 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,8 @@ 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 +``` + +\include{doc} install_prebuilt_footer.dox diff --git a/docpages/install/install-vcpkg.md b/docpages/install/install-vcpkg.md index 8ffcb00d78..80717d578e 100644 --- a/docpages/install/install-vcpkg.md +++ b/docpages/install/install-vcpkg.md @@ -11,11 +11,14 @@ To install D++ on a system with VCPKG: - VCPKG will install the library, and dependencies, for you! Once completed, you will receive a message, indicating that dpp successfully installed! - Use `vcpkg list dpp` to check that the package is installed, as so: + ```cmd c:\vcpkg>vcpkg list dpp 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) diff --git a/docpages/install/install-windows-clion-vcpkg.md b/docpages/install/install-windows-clion-vcpkg.md index 66a65a4f5b..1a1ea9a94f 100644 --- a/docpages/install/install-windows-clion-vcpkg.md +++ b/docpages/install/install-windows-clion-vcpkg.md @@ -1,36 +1,38 @@ -\page install-windows-clion-vcpkg Installing from vcpkg for CLion +\page install-windows-clion-vcpkg Installing D++ for CLion via VCPKG (Windows) -To add D++ to a CLion project, you need obtain the library through vcpkg and then configure your CLion project and `CMakeLists.txt`. +\warning This page is for **Windows only**. If you want to use CLion on Linux, look to use \ref build-a-discord-bot-linux-clion "this page". Like always with windows, we highly recommends you use the [pre-made Visual Studio template](https://github.com/brainboxdotcc/windows-bot-template/) -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. +To add D++ to a CLion project, you need 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). +2. Run `vcpkg install dpp:x64-windows`. +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. - ``` +```cmd +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 +-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) - ``` +```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 your 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..e55254bca6 100644 --- a/docpages/install/install-windows-vs-zip.md +++ b/docpages/install/install-windows-vs-zip.md @@ -2,41 +2,55 @@ 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 + +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 +\image html zip_vsproj_2.png + +4. Name your bot project. In this example, we'll use 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 +\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_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. diff --git a/docpages/install/install-xmake.md b/docpages/install/install-xmake.md index d46091cc15..f89398dec0 100644 --- a/docpages/install/install-xmake.md +++ b/docpages/install/install-xmake.md @@ -1,12 +1,12 @@ -\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")