Compare commits
1 Commits
main
...
cf5372e530
Author | SHA1 | Date | |
---|---|---|---|
cf5372e530 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -48,4 +48,3 @@ CMakeUserPresets.json
|
|||||||
|
|
||||||
build/
|
build/
|
||||||
.cache/
|
.cache/
|
||||||
settings.hpp
|
|
||||||
|
@@ -1,31 +1,24 @@
|
|||||||
# Minimum CMake version required, we'll just use the latest version.
|
# Minimum CMake version required, we'll just use the latest version.
|
||||||
cmake_minimum_required(VERSION 3.22)
|
cmake_minimum_required(VERSION 3.22)
|
||||||
# Project name, version and description
|
# Project name, version and description
|
||||||
project(TheBartender VERSION 0.3)
|
project(TheBartender VERSION 1.0)
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||||
file(COPY assets DESTINATION ${CMAKE_BINARY_DIR})
|
|
||||||
|
|
||||||
# Create an executable
|
# Create an executable
|
||||||
add_executable(${PROJECT_NAME} src/Base/Entry.cpp src/Commands.cpp
|
add_executable(${PROJECT_NAME} src/main.cpp src/Commands.cpp)
|
||||||
src/Utility/Utility.cpp)
|
|
||||||
|
|
||||||
# Find our pre-installed DPP package (using FindDPP.cmake).
|
# Find our pre-installed DPP package (using FindDPP.cmake).
|
||||||
find_package(DPP REQUIRED)
|
find_package(DPP REQUIRED)
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(SQLITE3 REQUIRED sqlite3)
|
pkg_check_modules(SQLITE3 REQUIRED sqlite3)
|
||||||
pkg_check_modules(CAIRO REQUIRED cairo)
|
|
||||||
pkg_check_modules(STB REQUIRED stb)
|
|
||||||
pkg_check_modules(WEBP REQUIRED libwebp)
|
|
||||||
|
|
||||||
# Link the pre-installed DPP package.
|
# Link the pre-installed DPP package.
|
||||||
target_link_libraries(${PROJECT_NAME} ${DPP_LIBRARIES} ${SQLITE3_LIBRARIES}
|
target_link_libraries(${PROJECT_NAME} ${DPP_LIBRARIES} ${SQLITE3_LIBRARIES})
|
||||||
${CAIRO_LIBRARIES} ${WEBP_LIBRARIES})
|
|
||||||
|
|
||||||
# Include the DPP directories.
|
# Include the DPP directories.
|
||||||
target_include_directories(
|
target_include_directories(${PROJECT_NAME} PRIVATE ${DPP_INCLUDE_DIR}
|
||||||
${PROJECT_NAME} PRIVATE ${DPP_INCLUDE_DIR} ${SQLITE3_INCLUDE_DIR}
|
${SQLITE3_INCLUDE_DIR})
|
||||||
${CAIRO_INCLUDE_DIR} ${WEBP_INCLUDE_DIR})
|
|
||||||
|
|
||||||
# Set C++ version
|
# Set C++ version
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 20
|
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 20
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
@@ -1,118 +0,0 @@
|
|||||||
// Bot info
|
|
||||||
#define BOT_NAME "The Bartender Bot"
|
|
||||||
#define BOT_VERSION "v0.4-1"
|
|
||||||
#define CURRENCY_NAME "Night Coin"
|
|
||||||
|
|
||||||
// Buttons
|
|
||||||
#define BUTTON_ACCEPT "Confirm"
|
|
||||||
#define BUTTON_CANCEL "Cancel"
|
|
||||||
|
|
||||||
// Misc
|
|
||||||
#define REQUEST_CANCELLED "Your request has been cancelled. " RESPONSE_NO_CHARGE
|
|
||||||
#define RESPONSE_NO_CHARGE "You were not charged for this request."
|
|
||||||
|
|
||||||
///
|
|
||||||
/// COMMANDS
|
|
||||||
///
|
|
||||||
|
|
||||||
// Command ping
|
|
||||||
#define COMMAND_PING_DESCRIPTION "Ping-pong test"
|
|
||||||
|
|
||||||
// Command generate_report
|
|
||||||
#define COMMAND_GENERATE_REPORT_DESCRIPTION "Generate a fake news report"
|
|
||||||
#define COMMAND_GENERATE_REPORT_ARGS_IMAGE_DESCRIPTION \
|
|
||||||
"Upload a background image to use (Only supports PNG, JPEG, and WEBP files)"
|
|
||||||
#define COMMAND_GENERATE_REPORT_ARGS_HEADLINE_DESCRIPTION \
|
|
||||||
"What is the headline?"
|
|
||||||
|
|
||||||
#define COMMAND_GENERATE_REPORT_FAIL_NOT_SUPPORTED(filetype) \
|
|
||||||
"File type: " + filetype + \
|
|
||||||
" is not supported. Only PNG, JPEG, and WEBP are allowed!"
|
|
||||||
#define COMMAND_GENERATE_REPORT_FAIL_IMAGE_DOWNLOAD \
|
|
||||||
"Failed to download the background image! Aborting." RESPONSE_NO_CHARGE
|
|
||||||
#define COMMAND_GENERATE_REPORT_FAIL_IMAGE_LOAD \
|
|
||||||
"Failed to load the background image! Aborting." RESPONSE_NO_CHARGE
|
|
||||||
#define COMMAND_GENERATE_REPORT_FAIL_INSUFFICIENT_BALANCE(amount) \
|
|
||||||
"You do not have " + amount + " " CURRENCY_NAME "(s) to afford this."
|
|
||||||
#define COMMAND_GENERATE_REPORT_CONFIRMATION_QUESTION(price, imageURL, \
|
|
||||||
imageMIME, headline) \
|
|
||||||
"This image generation will cost you " + price + \
|
|
||||||
" " CURRENCY_NAME \
|
|
||||||
"(s). Are you sure you want to continue?\nHeadline: " + \
|
|
||||||
headline + "\n[" + imageMIME + "](" + imageURL + ")"
|
|
||||||
|
|
||||||
// Command get_pfp
|
|
||||||
#define COMMAND_GET_PFP_DESCRIPTION \
|
|
||||||
"Get someone elses profile picture as an image"
|
|
||||||
#define COMMAND_GET_PFP_ARGS_USER \
|
|
||||||
"Whose profile picture do you want to get(it can be of your own)"
|
|
||||||
#define COMMAND_GET_PFP_FAIL_NOT_A_MEMBER(userid) \
|
|
||||||
"<@" + userid + \
|
|
||||||
"> is not a member.\nYou can only get profile picture of " \
|
|
||||||
"guild/server members!"
|
|
||||||
#define COMMAND_GET_PFP_RETURN_ONLY_PFP(userid, pfplink) \
|
|
||||||
"<@" + userid + ">'s [discord profile picture](" + pfplink + ")"
|
|
||||||
|
|
||||||
#define COMMAND_GET_PFP_RETURN_SERVER_AND_DISCORD_PFP(userid, discordpfp, \
|
|
||||||
guildpfp) \
|
|
||||||
"<@" + userid + ">'s [discord profile picture](" + discordpfp + \
|
|
||||||
") and their [server profile picture](" + guildpfp + ")"
|
|
||||||
|
|
||||||
// Command about
|
|
||||||
#define COMMAND_ABOUT_DESCRIPTION "Info about the bot"
|
|
||||||
#define COMMAND_ABOUT_RESPONSE \
|
|
||||||
"## " BOT_NAME " " BOT_VERSION \
|
|
||||||
"\n-> Written by <@!607952795794145281>.\n-> Source code " \
|
|
||||||
"https://git.thenight.club/cat/BartenderBot.\n-> Made with " \
|
|
||||||
"[D++](<https://dpp.dev/>), [cairo](<https://www.cairographics.org/>), " \
|
|
||||||
"[stb](<https://github.com/nothings/stb>), " \
|
|
||||||
"[libwebp](<https://chromium.googlesource.com/webm/libwebp>), and tears."
|
|
||||||
|
|
||||||
// Command balance/bal
|
|
||||||
#define COMMAND_BALANCE_DESCRIPTION "See someone's balance of " CURRENCY_NAME
|
|
||||||
#define COMMAND_BALANCE_USER_DESCRIPTION \
|
|
||||||
"Leave this blank if you want to see your own balance"
|
|
||||||
#define COMMAND_BALANCE_SELF_RESPONSE(balance) \
|
|
||||||
"You currently have " + balance + " " CURRENCY_NAME "(s)"
|
|
||||||
#define COMMAND_BALANCE_SOMEONE_ELSE_RESPONSE(person, balance) \
|
|
||||||
"<@!" + person + "> currently has " + balance + " " CURRENCY_NAME "(s)"
|
|
||||||
|
|
||||||
// Command pay
|
|
||||||
#define COMMAND_PAY_DESCRIPTION "Send someone some amount of " CURRENCY_NAME "s"
|
|
||||||
#define COMMAND_PAY_ARGS_USER_DESCRIPTION "Who do you want to pay"
|
|
||||||
#define COMMAND_PAY_ARGS_AMOUNT_DESCRIPTION "How much do you want to pay"
|
|
||||||
#define COMMAND_PAY_FAIL_INSUFFICIENT_AMOUNT(recipient, amount) \
|
|
||||||
"You do not have the balance to send <@!" + recipient + "> " + amount + \
|
|
||||||
" " CURRENCY_NAME "(s)!"
|
|
||||||
#define COMMAND_PAY_SUCCESS(recipient, amount) \
|
|
||||||
"Successfully sent <@!" + recipient + "> " + amount + " " CURRENCY_NAME "(s)!"
|
|
||||||
|
|
||||||
// Command print_money
|
|
||||||
#define COMMAND_PRINT_DESCRIPTION "Allows the admin to print money on-demand"
|
|
||||||
#define COMMAND_PRINT_ARGS_AMOUNT_DESCRIPTION "How much are we printing boss?"
|
|
||||||
#define COMMAND_PRINT_FAIL_NO_PRIVILIEGE(recipient) \
|
|
||||||
"Only <@!" + recipient + "> can print money!"
|
|
||||||
#define COMMAND_PRINT_SUCCESS(recipient, amount) \
|
|
||||||
"Successfully printed " + amount + " " CURRENCY_NAME "(s) to <@!" + \
|
|
||||||
recipient + "> !"
|
|
||||||
|
|
||||||
// Command burn_money
|
|
||||||
#define COMMAND_BURN_DESCRIPTION \
|
|
||||||
"Allows the admin to burn money, burn baby burn!"
|
|
||||||
#define COMMAND_BURN_ARGS_AMOUNT_DESCRIPTION "How much are we burning?"
|
|
||||||
#define COMMAND_BURN_FAIL_NO_PRIVILIEGE(recipient) \
|
|
||||||
"Only <@!" + recipient + "> can burn money!"
|
|
||||||
#define COMMAND_BURN_FAIL_INSUFFICIENT_AMOUNT(amount) \
|
|
||||||
"You do not have" + amount + " " CURRENCY_NAME "(s) to burn!"
|
|
||||||
#define COMMAND_BURN_SUCCESS(recipient, amount) \
|
|
||||||
"Successfully burned " + amount + " " CURRENCY_NAME "(s) to <@!" + \
|
|
||||||
recipient + "> !"
|
|
||||||
|
|
||||||
// Command money_leaderboard
|
|
||||||
#define COMMAND_MONEY_LEADERBOARD_DESCRIPTION \
|
|
||||||
"See who are the wealthiest members of the server, and who are... less " \
|
|
||||||
"fortunate."
|
|
||||||
#define COMMAND_MONEY_LEADERBOARD_TEXT \
|
|
||||||
"## Here are the top 15 most wealthiest people in the server.\n-# Note: if " \
|
|
||||||
"you don't see yourself here it is either due to never interacting with " \
|
|
||||||
"the bot, or having too low of a balance.\n"
|
|
@@ -1,11 +0,0 @@
|
|||||||
#define TOKEN "Your bot token here"
|
|
||||||
|
|
||||||
// Guild id here
|
|
||||||
#define GUILD 0
|
|
||||||
|
|
||||||
// Whoever is going to be admin. Their ID here
|
|
||||||
#define ADMIN_ID 0
|
|
||||||
|
|
||||||
// Replace locale_en with any available one
|
|
||||||
#include "languages/locale_en.hpp"
|
|
||||||
|
|
@@ -1,56 +0,0 @@
|
|||||||
#include "../CommandManagement.cpp"
|
|
||||||
#include "../Common.hpp"
|
|
||||||
#include "../Databases.hpp"
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <dpp/appcommand.h>
|
|
||||||
#include <dpp/cluster.h>
|
|
||||||
#include <dpp/dispatcher.h>
|
|
||||||
#include <dpp/dpp.h>
|
|
||||||
#include <dpp/intents.h>
|
|
||||||
#include <dpp/misc-enum.h>
|
|
||||||
#include <dpp/once.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
// SQL database set up
|
|
||||||
makeDatabases();
|
|
||||||
|
|
||||||
// Bot setup bullshit
|
|
||||||
// Fucking intents man I hate this dumbcell app
|
|
||||||
dpp::cluster bot(TOKEN, dpp::i_unverified_default_intents |
|
|
||||||
dpp::i_privileged_intents);
|
|
||||||
|
|
||||||
// Neat utility
|
|
||||||
bot.on_log(dpp::utility::cout_logger());
|
|
||||||
|
|
||||||
bot.on_slashcommand([&bot](const dpp::slashcommand_t &event) {
|
|
||||||
auto command = Commands.find(event.command.get_command_name());
|
|
||||||
if (command != Commands.end()) {
|
|
||||||
command->second(event, bot);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
event.reply("Could not find that command :(");
|
|
||||||
});
|
|
||||||
|
|
||||||
bot.on_button_click([&bot](const dpp::button_click_t &event) {
|
|
||||||
event.reply(dpp::ir_deferred_update_message, "processing");
|
|
||||||
|
|
||||||
auto component = Components.find(event.custom_id);
|
|
||||||
if (component != Components.end()) {
|
|
||||||
component->second(event, bot);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
bot.on_ready([&bot](const dpp::ready_t &event) {
|
|
||||||
if (dpp::run_once<struct register_bot_commands>()) {
|
|
||||||
createCommands(event, bot);
|
|
||||||
}
|
|
||||||
if (dpp::run_once<struct clear_bot_commands>()) {
|
|
||||||
deleteCommands(event, bot);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
bot.start(dpp::st_wait);
|
|
||||||
}
|
|
@@ -1,30 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <sqlite3.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
inline sqlite3 *database;
|
|
||||||
|
|
||||||
// Its invoked per returned row/record
|
|
||||||
// typeCount is each column
|
|
||||||
//
|
|
||||||
// Results come out as KEY:VALUE;
|
|
||||||
static int callback(void *output, int typeCount, char **value, char **key) {
|
|
||||||
std::string *out = static_cast<std::string *>(output);
|
|
||||||
for (int x = 0; x < typeCount; x++) {
|
|
||||||
*out += std::string(key[x]) + ":" + std::string(value[x]) + ";";
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void execSQL(std::string sql, std::string *result = nullptr) {
|
|
||||||
int errorCode = 0;
|
|
||||||
errorCode = sqlite3_exec(database, sql.c_str(), callback, result, NULL);
|
|
||||||
if (errorCode == 19) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errorCode) {
|
|
||||||
std::cerr << sqlite3_errmsg(database) << "!\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,75 +0,0 @@
|
|||||||
#include "Common.hpp"
|
|
||||||
#include <dpp/appcommand.h>
|
|
||||||
#include <dpp/cluster.h>
|
|
||||||
#include <dpp/dispatcher.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
extern std::unordered_map<std::string, std::function<void(COMMAND_ARGS)>>
|
|
||||||
Commands;
|
|
||||||
extern std::unordered_map<std::string, std::function<void(COMPONENT_ARGS)>>
|
|
||||||
Components;
|
|
||||||
|
|
||||||
void deleteCommands(const dpp::ready_t &event, dpp::cluster &bot) {
|
|
||||||
// bot.guild_bulk_command_delete(GUILD);
|
|
||||||
}
|
|
||||||
|
|
||||||
void createCommands(const dpp::ready_t &event, dpp::cluster &bot) {
|
|
||||||
bot.global_command_create(
|
|
||||||
dpp::slashcommand(COMMAND_PING, COMMAND_PING_DESCRIPTION, bot.me.id));
|
|
||||||
|
|
||||||
std::vector<dpp::slashcommand> guildCommands{
|
|
||||||
// Other commands
|
|
||||||
dpp::slashcommand(COMMAND_ABOUT, COMMAND_ABOUT_DESCRIPTION, bot.me.id),
|
|
||||||
dpp::slashcommand(COMMAND_GET_PFP, COMMAND_GET_PFP_DESCRIPTION, bot.me.id)
|
|
||||||
.add_option(dpp::command_option(dpp::command_option_type::co_user,
|
|
||||||
"user", COMMAND_GET_PFP_ARGS_USER,
|
|
||||||
true)),
|
|
||||||
|
|
||||||
// Generative commands
|
|
||||||
dpp::slashcommand(COMMAND_GENERATE_REPORT,
|
|
||||||
COMMAND_GENERATE_REPORT_DESCRIPTION, bot.me.id)
|
|
||||||
.add_option(dpp::command_option(
|
|
||||||
dpp::command_option_type::co_attachment, "image",
|
|
||||||
COMMAND_GENERATE_REPORT_ARGS_IMAGE_DESCRIPTION, true))
|
|
||||||
.add_option(dpp::command_option(
|
|
||||||
dpp::command_option_type::co_string, "headline",
|
|
||||||
COMMAND_GENERATE_REPORT_ARGS_HEADLINE_DESCRIPTION,
|
|
||||||
true)
|
|
||||||
.set_min_length(3)
|
|
||||||
.set_max_length(70)),
|
|
||||||
|
|
||||||
// Money related commands
|
|
||||||
dpp::slashcommand(COMMAND_BALANCE, COMMAND_BALANCE_DESCRIPTION, bot.me.id)
|
|
||||||
.add_option(dpp::command_option(dpp::command_option_type::co_user,
|
|
||||||
"user",
|
|
||||||
COMMAND_BALANCE_USER_DESCRIPTION)),
|
|
||||||
dpp::slashcommand(COMMAND_BALANCE_SHORT, COMMAND_BALANCE_DESCRIPTION,
|
|
||||||
bot.me.id)
|
|
||||||
.add_option(dpp::command_option(dpp::command_option_type::co_user,
|
|
||||||
"user",
|
|
||||||
COMMAND_BALANCE_USER_DESCRIPTION)),
|
|
||||||
dpp::slashcommand(COMMAND_PAY, COMMAND_PAY_DESCRIPTION, bot.me.id)
|
|
||||||
.add_option(dpp::command_option(
|
|
||||||
dpp::command_option_type::co_user, "recipient",
|
|
||||||
COMMAND_PAY_ARGS_USER_DESCRIPTION, true))
|
|
||||||
.add_option(dpp::command_option(
|
|
||||||
dpp::command_option_type::co_integer, "amount",
|
|
||||||
COMMAND_PAY_ARGS_AMOUNT_DESCRIPTION, true)
|
|
||||||
.set_min_value(1)),
|
|
||||||
dpp::slashcommand(COMMAND_PRINT_MONEY, COMMAND_PRINT_DESCRIPTION,
|
|
||||||
bot.me.id)
|
|
||||||
.add_option(dpp::command_option(
|
|
||||||
dpp::command_option_type::co_integer, "amount",
|
|
||||||
COMMAND_PRINT_ARGS_AMOUNT_DESCRIPTION, true)
|
|
||||||
.set_min_value(1)),
|
|
||||||
dpp::slashcommand(COMMAND_BURN_MONEY, COMMAND_BURN_DESCRIPTION, bot.me.id)
|
|
||||||
.add_option(dpp::command_option(
|
|
||||||
dpp::command_option_type::co_integer, "amount",
|
|
||||||
COMMAND_BURN_ARGS_AMOUNT_DESCRIPTION, true)
|
|
||||||
.set_min_value(1)),
|
|
||||||
dpp::slashcommand(COMMAND_MONEY_LEADERBOARD,
|
|
||||||
COMMAND_MONEY_LEADERBOARD_DESCRIPTION, bot.me.id),
|
|
||||||
};
|
|
||||||
|
|
||||||
bot.guild_bulk_command_create(guildCommands, GUILD);
|
|
||||||
}
|
|
@@ -1,24 +1,3 @@
|
|||||||
// Unity Build
|
#include "Commands.hpp"
|
||||||
#include "Commands/GenerativeCommands.cpp"
|
|
||||||
#include "Commands/MoneyCommands.cpp"
|
|
||||||
#include "Commands/OtherCommands.cpp"
|
|
||||||
|
|
||||||
// Component Responses
|
void commandPing(const dpp::slashcommand_t &event) { event.reply("Pong"); }
|
||||||
#include "Commands/Components/GenerativeComponents.cpp"
|
|
||||||
|
|
||||||
// Registry
|
|
||||||
std::unordered_map<std::string, std::function<void(COMMAND_ARGS)>> Commands{
|
|
||||||
{COMMAND_PING, commandPing},
|
|
||||||
{COMMAND_ABOUT, commandAbout},
|
|
||||||
{COMMAND_BALANCE, commandBalance},
|
|
||||||
{COMMAND_BALANCE_SHORT, commandBalance},
|
|
||||||
{COMMAND_PAY, commandPay},
|
|
||||||
{COMMAND_PRINT_MONEY, commandPrintMoney},
|
|
||||||
{COMMAND_BURN_MONEY, commandBurnMoney},
|
|
||||||
{COMMAND_MONEY_LEADERBOARD, commandMoneyLeaderboard},
|
|
||||||
{COMMAND_GET_PFP, commandGetPFP},
|
|
||||||
{COMMAND_GENERATE_REPORT, commandGenerateReport}};
|
|
||||||
|
|
||||||
std::unordered_map<std::string, std::function<void(COMPONENT_ARGS)>> Components{
|
|
||||||
{COMPONENT_COMMAND_CANCEL, componentCancel},
|
|
||||||
{COMPONENT_GENERATE_REPORT_CONFIRM, componentGenerateReport}};
|
|
||||||
|
6
src/Commands.hpp
Normal file
6
src/Commands.hpp
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include <dpp/dispatcher.h>
|
||||||
|
void commandPing(const dpp::slashcommand_t &event);
|
||||||
|
|
||||||
|
inline std::unordered_map<std::string,
|
||||||
|
std::function<void(const dpp::slashcommand_t &event)>>
|
||||||
|
Commands{{"ping", commandPing}};
|
@@ -1,53 +0,0 @@
|
|||||||
#include "../../Common.hpp"
|
|
||||||
#include "../../Utility/CairoTools.hpp"
|
|
||||||
|
|
||||||
#include <dpp/cluster.h>
|
|
||||||
#include <dpp/dispatcher.h>
|
|
||||||
#include <dpp/misc-enum.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
void componentGenerateReport(COMPONENT_ARGS) {
|
|
||||||
std::string content = event.command.get_context_message().content;
|
|
||||||
|
|
||||||
// Find headline
|
|
||||||
size_t start = content.find(": ") + 2;
|
|
||||||
std::string headline =
|
|
||||||
content.substr(start, content.find("\n[", start) - start);
|
|
||||||
|
|
||||||
// Find image MIME
|
|
||||||
start = content.find("[") + 1;
|
|
||||||
std::string imageType =
|
|
||||||
content.substr(start, content.find("]", start) - start);
|
|
||||||
|
|
||||||
// Find image link
|
|
||||||
start = content.find("](") + 2;
|
|
||||||
std::string url = content.substr(start, content.find(")", start) - start);
|
|
||||||
|
|
||||||
// Handler
|
|
||||||
auto fileType = supportedImageFileTypes.find(imageType);
|
|
||||||
bot.request(url, dpp::http_method::m_get,
|
|
||||||
[event, &bot, headline,
|
|
||||||
fileType](const dpp::http_request_completion_t &result) {
|
|
||||||
// We might not be able to download it
|
|
||||||
if (result.status != 200) {
|
|
||||||
event.edit_response(
|
|
||||||
COMMAND_GENERATE_REPORT_FAIL_IMAGE_DOWNLOAD);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Its possible that file is corrupted
|
|
||||||
auto imageAsSurface = fileType->second(result.body);
|
|
||||||
if (imageAsSurface == nullptr) {
|
|
||||||
event.edit_response(COMMAND_GENERATE_REPORT_FAIL_IMAGE_LOAD);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string responseData =
|
|
||||||
GenerateReportImage(imageAsSurface, headline);
|
|
||||||
dpp::message response(event.command.channel_id, "");
|
|
||||||
response.add_file("report.png", responseData);
|
|
||||||
event.edit_response(response);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void componentCancel(COMPONENT_ARGS) { event.edit_response(REQUEST_CANCELLED); }
|
|
@@ -1,61 +0,0 @@
|
|||||||
#include "../Common.hpp"
|
|
||||||
#include "../Utility/CairoTools.hpp"
|
|
||||||
#include "TransactionMethods.hpp"
|
|
||||||
|
|
||||||
#include <dpp/dispatcher.h>
|
|
||||||
#include <dpp/dpp.h>
|
|
||||||
#include <dpp/guild.h>
|
|
||||||
#include <dpp/snowflake.h>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
void commandGenerateReport(const dpp::slashcommand_t &event,
|
|
||||||
dpp::cluster &bot) {
|
|
||||||
event.thinking();
|
|
||||||
auto issuer = event.command.get_issuing_user().id;
|
|
||||||
// Insufficient balance
|
|
||||||
if (!checkFromUsersBalance(issuer, COMMAND_GENERATE_REPORT_COST)) {
|
|
||||||
event.edit_response(COMMAND_GENERATE_REPORT_FAIL_INSUFFICIENT_BALANCE(
|
|
||||||
std::to_string(COMMAND_GENERATE_REPORT_COST)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
deductFromUsersBalance(issuer, COMMAND_GENERATE_REPORT_COST);
|
|
||||||
|
|
||||||
// Start processing
|
|
||||||
dpp::snowflake fileId =
|
|
||||||
std::get<dpp::snowflake>(event.get_parameter("image"));
|
|
||||||
dpp::attachment file = event.command.get_resolved_attachment(fileId);
|
|
||||||
auto fileType = supportedImageFileTypes.find(file.content_type);
|
|
||||||
|
|
||||||
if (fileType != supportedImageFileTypes.end()) {
|
|
||||||
// Don't forget that its only funny if it is all in upper case
|
|
||||||
std::string headline =
|
|
||||||
std::get<std::string>(event.get_parameter("headline"));
|
|
||||||
// Never seen this method before but looks awesome
|
|
||||||
std::transform(headline.begin(), headline.end(), headline.data(),
|
|
||||||
::toupper);
|
|
||||||
|
|
||||||
dpp::message confirmRequest(
|
|
||||||
event.command.channel_id,
|
|
||||||
COMMAND_GENERATE_REPORT_CONFIRMATION_QUESTION(
|
|
||||||
std::to_string(COMMAND_GENERATE_REPORT_COST), file.url,
|
|
||||||
fileType->first, headline));
|
|
||||||
|
|
||||||
confirmRequest.add_component(
|
|
||||||
dpp::component()
|
|
||||||
.add_component(dpp::component()
|
|
||||||
.set_label(BUTTON_ACCEPT)
|
|
||||||
.set_type(dpp::cot_button)
|
|
||||||
.set_style(dpp::component_style::cos_success)
|
|
||||||
.set_id(COMPONENT_GENERATE_REPORT_CONFIRM))
|
|
||||||
.add_component(dpp::component()
|
|
||||||
.set_label(BUTTON_CANCEL)
|
|
||||||
.set_type(dpp::cot_button)
|
|
||||||
.set_style(dpp::component_style::cos_danger)
|
|
||||||
.set_id(COMPONENT_COMMAND_CANCEL)));
|
|
||||||
event.edit_response(confirmRequest);
|
|
||||||
} else {
|
|
||||||
event.edit_response(
|
|
||||||
COMMAND_GENERATE_REPORT_FAIL_NOT_SUPPORTED(file.content_type));
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,155 +0,0 @@
|
|||||||
#include "../Base/SQL.hpp"
|
|
||||||
#include "../Common.hpp"
|
|
||||||
#include "TransactionMethods.hpp"
|
|
||||||
|
|
||||||
#include <dpp/appcommand.h>
|
|
||||||
#include <dpp/cluster.h>
|
|
||||||
#include <dpp/dispatcher.h>
|
|
||||||
#include <dpp/snowflake.h>
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <sstream>
|
|
||||||
#include <string>
|
|
||||||
#include <variant>
|
|
||||||
|
|
||||||
// Actual commands
|
|
||||||
void commandBalance(const dpp::slashcommand_t &event, dpp::cluster &bot) {
|
|
||||||
std::string person, balance;
|
|
||||||
dpp::command_value id = event.get_parameter("user");
|
|
||||||
|
|
||||||
// Weirdest thing ever
|
|
||||||
if (std::holds_alternative<std::monostate>(id)) {
|
|
||||||
balance = getUserBalance(event.command.get_issuing_user().id);
|
|
||||||
event.reply(COMMAND_BALANCE_SELF_RESPONSE(balance));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
person = std::get<dpp::snowflake>(id).str();
|
|
||||||
balance = getUserBalance(person);
|
|
||||||
event.reply(COMMAND_BALANCE_SOMEONE_ELSE_RESPONSE(person, balance));
|
|
||||||
}
|
|
||||||
|
|
||||||
void commandPay(const dpp::slashcommand_t &event, dpp::cluster &bot) {
|
|
||||||
std::string recipient =
|
|
||||||
std::get<dpp::snowflake>(event.get_parameter("recipient")).str();
|
|
||||||
std::uint64_t amount = std::get<std::int64_t>(event.get_parameter("amount"));
|
|
||||||
|
|
||||||
// Insufficient balance
|
|
||||||
if (!checkFromUsersBalance(ADMIN_ID, amount)) {
|
|
||||||
event.reply(COMMAND_PAY_FAIL_INSUFFICIENT_AMOUNT(recipient,
|
|
||||||
std::to_string(amount)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
deductFromUsersBalance(ADMIN_ID, amount);
|
|
||||||
|
|
||||||
// Lets pay them
|
|
||||||
increaseFromUsersBalance(recipient, amount);
|
|
||||||
event.reply(COMMAND_PAY_SUCCESS(recipient, std::to_string(amount)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void commandPrintMoney(const dpp::slashcommand_t &event, dpp::cluster &bot) {
|
|
||||||
std::int64_t userid = event.command.get_issuing_user().id;
|
|
||||||
|
|
||||||
if (ADMIN_ID != userid) {
|
|
||||||
event.reply(COMMAND_PRINT_FAIL_NO_PRIVILIEGE(std::to_string(ADMIN_ID)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::uint64_t amount = std::get<std::int64_t>(event.get_parameter("amount"));
|
|
||||||
increaseFromUsersBalance(ADMIN_ID, amount);
|
|
||||||
event.reply(
|
|
||||||
COMMAND_PRINT_SUCCESS(std::to_string(ADMIN_ID), std::to_string(amount)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void commandBurnMoney(const dpp::slashcommand_t &event, dpp::cluster &bot) {
|
|
||||||
std::int64_t userid = event.command.get_issuing_user().id;
|
|
||||||
|
|
||||||
if (ADMIN_ID != userid) {
|
|
||||||
event.reply(COMMAND_BURN_FAIL_NO_PRIVILIEGE(std::to_string(ADMIN_ID)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::uint64_t amount = std::get<std::int64_t>(event.get_parameter("amount"));
|
|
||||||
|
|
||||||
// Insufficient balance
|
|
||||||
if (!checkFromUsersBalance(ADMIN_ID, amount)) {
|
|
||||||
event.reply(COMMAND_BURN_FAIL_INSUFFICIENT_AMOUNT(std::to_string(amount)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
deductFromUsersBalance(ADMIN_ID, amount);
|
|
||||||
event.reply(
|
|
||||||
COMMAND_BURN_SUCCESS(std::to_string(ADMIN_ID), std::to_string(amount)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void commandMoneyLeaderboard(const dpp::slashcommand_t &event,
|
|
||||||
dpp::cluster &bot) {
|
|
||||||
std::string result;
|
|
||||||
std::stringstream replyStream;
|
|
||||||
execSQL("SELECT * FROM MONEY ORDER BY CASH DESC LIMIT 15;", &result);
|
|
||||||
|
|
||||||
replyStream << COMMAND_MONEY_LEADERBOARD_TEXT;
|
|
||||||
|
|
||||||
// AI code starts here
|
|
||||||
std::stringstream ss(result);
|
|
||||||
std::string token;
|
|
||||||
uint8_t rank = 1;
|
|
||||||
|
|
||||||
while (std::getline(ss, token, ';')) {
|
|
||||||
if (token.find("UID:") == 0) {
|
|
||||||
std::string uid = token.substr(4); // Remove "UID:"
|
|
||||||
|
|
||||||
// Get the next token (CASH)
|
|
||||||
if (std::getline(ss, token, ';')) {
|
|
||||||
std::string cash = token.substr(5); // Remove "CASH:"
|
|
||||||
replyStream << std::to_string(rank) << ". <@!" << uid << "> - " << cash
|
|
||||||
<< " " << CURRENCY_NAME << "(s)"
|
|
||||||
<< "\n";
|
|
||||||
rank++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// AI code ends here
|
|
||||||
// I hate parsing strings, thank you AI
|
|
||||||
|
|
||||||
event.reply(replyStream.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Transaction Methods
|
|
||||||
///
|
|
||||||
|
|
||||||
void increaseFromUsersBalance(const dpp::snowflake userid,
|
|
||||||
std::uint64_t amount) {
|
|
||||||
std::uint64_t balance = std::stoll(getUserBalance(userid));
|
|
||||||
execSQL("UPDATE MONEY SET CASH=" + std::to_string(balance + amount) +
|
|
||||||
" WHERE UID=" + userid.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void deductFromUsersBalance(const dpp::snowflake userid, std::uint64_t amount) {
|
|
||||||
std::uint64_t balance = std::stoll(getUserBalance(userid));
|
|
||||||
execSQL("UPDATE MONEY SET CASH=" + std::to_string(balance - amount) +
|
|
||||||
" WHERE UID=" + userid.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool checkFromUsersBalance(const dpp::snowflake userid, std::uint64_t amount) {
|
|
||||||
std::uint64_t balance = std::stoll(getUserBalance(userid));
|
|
||||||
return balance >= amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getUserBalance(const dpp::snowflake userid) {
|
|
||||||
std::string balance;
|
|
||||||
execSQL("SELECT CASH FROM MONEY WHERE UID=" + userid.str(), &balance);
|
|
||||||
|
|
||||||
if (balance.empty()) {
|
|
||||||
addUserToDatabase(userid);
|
|
||||||
execSQL("SELECT CASH FROM MONEY WHERE UID=" + userid.str(),
|
|
||||||
&balance); // We are rerunning it cus if the default starting cash
|
|
||||||
// changes I might forget to change it here
|
|
||||||
}
|
|
||||||
std::uint8_t begining = balance.find(':') + 1;
|
|
||||||
|
|
||||||
return balance.substr(begining, balance.find(';') - begining);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addUserToDatabase(const dpp::snowflake userid) {
|
|
||||||
execSQL("INSERT INTO MONEY (UID) VALUES (" + userid.str() + ");");
|
|
||||||
}
|
|
@@ -1,36 +0,0 @@
|
|||||||
#include "../Common.hpp"
|
|
||||||
#include <dpp/dispatcher.h>
|
|
||||||
#include <dpp/dpp.h>
|
|
||||||
#include <dpp/guild.h>
|
|
||||||
#include <dpp/snowflake.h>
|
|
||||||
#include <dpp/user.h>
|
|
||||||
|
|
||||||
#define DPP_AVATAR_GET_ARGS 1024, dpp::i_png, true
|
|
||||||
|
|
||||||
// event.command.get_guild() to get guild
|
|
||||||
|
|
||||||
void commandPing(const dpp::slashcommand_t &event, dpp::cluster &bot) {
|
|
||||||
event.reply("Pong");
|
|
||||||
}
|
|
||||||
void commandAbout(const dpp::slashcommand_t &event, dpp::cluster &bot) {
|
|
||||||
event.reply(COMMAND_ABOUT_RESPONSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void commandGetPFP(const dpp::slashcommand_t &event, dpp::cluster &bot) {
|
|
||||||
dpp::snowflake userID = std::get<dpp::snowflake>(event.get_parameter("user"));
|
|
||||||
dpp::guild_member member = event.command.get_resolved_member(userID);
|
|
||||||
if (member.user_id == 0) {
|
|
||||||
event.reply(COMMAND_GET_PFP_FAIL_NOT_A_MEMBER(userID.str()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string memberUrl = member.get_avatar_url(DPP_AVATAR_GET_ARGS),
|
|
||||||
discordUrl =
|
|
||||||
member.get_user()->get_avatar_url(DPP_AVATAR_GET_ARGS);
|
|
||||||
if (memberUrl.empty()) {
|
|
||||||
event.reply(COMMAND_GET_PFP_RETURN_ONLY_PFP(userID.str(), discordUrl));
|
|
||||||
} else {
|
|
||||||
event.reply(COMMAND_GET_PFP_RETURN_SERVER_AND_DISCORD_PFP(
|
|
||||||
userID.str(), discordUrl, memberUrl));
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,10 +0,0 @@
|
|||||||
#include <dpp/snowflake.h>
|
|
||||||
|
|
||||||
// Helper methods
|
|
||||||
void increaseFromUsersBalance(const dpp::snowflake userid,
|
|
||||||
std::uint64_t amount);
|
|
||||||
void deductFromUsersBalance(const dpp::snowflake userid, std::uint64_t amount);
|
|
||||||
bool checkFromUsersBalance(const dpp::snowflake userid, std::uint64_t amount);
|
|
||||||
std::string getUserBalance(const dpp::snowflake userid);
|
|
||||||
|
|
||||||
void addUserToDatabase(const dpp::snowflake userid);
|
|
@@ -1,23 +0,0 @@
|
|||||||
#include "../settings.hpp"
|
|
||||||
|
|
||||||
#define COMMAND_ARGS const dpp::slashcommand_t &event, dpp::cluster &bot
|
|
||||||
#define COMPONENT_ARGS const dpp::button_click_t &event, dpp::cluster &bot
|
|
||||||
|
|
||||||
// Costs of commands
|
|
||||||
#define COMMAND_GENERATE_REPORT_COST 2
|
|
||||||
|
|
||||||
// Command names
|
|
||||||
#define COMMAND_PING "ping"
|
|
||||||
#define COMMAND_GENERATE_REPORT "generate_report"
|
|
||||||
#define COMMAND_GET_PFP "get_pfp"
|
|
||||||
#define COMMAND_ABOUT "about"
|
|
||||||
#define COMMAND_BALANCE "balance"
|
|
||||||
#define COMMAND_BALANCE_SHORT "bal"
|
|
||||||
#define COMMAND_PAY "pay"
|
|
||||||
#define COMMAND_PRINT_MONEY "print_money"
|
|
||||||
#define COMMAND_BURN_MONEY "burn_money"
|
|
||||||
#define COMMAND_MONEY_LEADERBOARD "money_leaderboard"
|
|
||||||
|
|
||||||
// Component names
|
|
||||||
#define COMPONENT_GENERATE_REPORT_CONFIRM "generate_report_confirm"
|
|
||||||
#define COMPONENT_COMMAND_CANCEL "cancel"
|
|
@@ -1,10 +0,0 @@
|
|||||||
#include "Base/SQL.hpp"
|
|
||||||
|
|
||||||
#define MAKE_DATABASE "CREATE TABLE IF NOT EXISTS "
|
|
||||||
#define DATABASE_MONEY \
|
|
||||||
"MONEY(UID INT PRIMARY KEY NOT NULL, CASH INT NOT NULL DEFAULT 100)"
|
|
||||||
|
|
||||||
inline void makeDatabases() {
|
|
||||||
sqlite3_open("bot.db", &database);
|
|
||||||
execSQL(MAKE_DATABASE DATABASE_MONEY);
|
|
||||||
}
|
|
27
src/SQL.hpp
Normal file
27
src/SQL.hpp
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
inline sqlite3 *database;
|
||||||
|
|
||||||
|
// Its invoked per returned row/record
|
||||||
|
// typeCount is each column
|
||||||
|
static int callback(void *deadWeight, int typeCount, char **value, char **key) {
|
||||||
|
for (int x = 0; x < typeCount; x++) {
|
||||||
|
std::cout << key[x] << " " << value[x] << "\n";
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void execSQL(std::string sql) {
|
||||||
|
int errorCode = 0;
|
||||||
|
errorCode = sqlite3_exec(database, sql.c_str(), callback, 0, NULL);
|
||||||
|
if (errorCode == 19) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorCode) {
|
||||||
|
std::cerr << sqlite3_errmsg(database) << " exiting!\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,85 +0,0 @@
|
|||||||
#include "CairoTools.hpp"
|
|
||||||
#include <cairo/cairo.h>
|
|
||||||
#include <cctype>
|
|
||||||
|
|
||||||
std::string GenerateReportImage(cairo_surface_t *background,
|
|
||||||
std::string headline) {
|
|
||||||
cairo_surface_t *surface = cairo_image_surface_create(
|
|
||||||
CAIRO_FORMAT_ARGB32, REPORT_WIDTH, REPORT_HEIGHT);
|
|
||||||
|
|
||||||
cairo_t *ctx = cairo_create(surface);
|
|
||||||
cairo_set_source_rgb(ctx, CAIRO_BLACK);
|
|
||||||
cairo_paint(ctx);
|
|
||||||
|
|
||||||
// Background Image
|
|
||||||
cairo_save(ctx);
|
|
||||||
int imgW = cairo_image_surface_get_width(background),
|
|
||||||
imgH = cairo_image_surface_get_height(background);
|
|
||||||
|
|
||||||
cairo_scale(ctx, (double)REPORT_WIDTH / imgW,
|
|
||||||
(double)(REPORT_HEIGHT - REPORT_HEIGHT_OFFSET) / imgH);
|
|
||||||
cairo_set_source_surface(ctx, background, 0, 0);
|
|
||||||
cairo_paint(ctx);
|
|
||||||
cairo_restore(ctx);
|
|
||||||
|
|
||||||
// Gradient
|
|
||||||
cairo_pattern_t *gradient =
|
|
||||||
cairo_pattern_create_linear(0, 0, 0, REPORT_HEIGHT);
|
|
||||||
cairo_pattern_add_color_stop_rgba(gradient, 0.85, CAIRO_BLACK, 1.0);
|
|
||||||
cairo_pattern_add_color_stop_rgba(gradient, 0.0, CAIRO_BLACK, 0.0);
|
|
||||||
cairo_rectangle(ctx, 0, 0, REPORT_WIDTH, REPORT_HEIGHT);
|
|
||||||
cairo_set_source(ctx, gradient);
|
|
||||||
cairo_fill(ctx);
|
|
||||||
|
|
||||||
// Bumper
|
|
||||||
cairo_save(ctx);
|
|
||||||
static cairo_surface_t *bumper =
|
|
||||||
cairo_image_surface_create_from_png(REPORT_RESOURCE_BUMPER_PATH);
|
|
||||||
|
|
||||||
imgW = cairo_image_surface_get_width(bumper);
|
|
||||||
imgH = cairo_image_surface_get_height(bumper);
|
|
||||||
|
|
||||||
cairo_scale(ctx, (double)REPORT_WIDTH / imgW, 1.5);
|
|
||||||
cairo_set_source_surface(ctx, bumper, 0, REPORT_HEIGHT - (imgH * 7.1));
|
|
||||||
cairo_paint(ctx);
|
|
||||||
cairo_restore(ctx);
|
|
||||||
|
|
||||||
// Text
|
|
||||||
cairo_select_font_face(ctx, "Steelfish", CAIRO_FONT_SLANT_NORMAL,
|
|
||||||
CAIRO_FONT_WEIGHT_BOLD);
|
|
||||||
cairo_set_font_size(ctx, REPORT_TEXT_FONT_SIZE);
|
|
||||||
|
|
||||||
// Iteration 3
|
|
||||||
std::stringstream text(headline + " ");
|
|
||||||
|
|
||||||
std::string output, part;
|
|
||||||
std::vector<std::string> outputList;
|
|
||||||
while (text.tellp() == std::streampos(0)) {
|
|
||||||
std::getline(text, part, ' ');
|
|
||||||
if (output.length() + part.length() < REPORT_TEXT_LENGTH) {
|
|
||||||
output += part + ' ';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
outputList.push_back(output);
|
|
||||||
output = part + ' ';
|
|
||||||
}
|
|
||||||
outputList.push_back(output);
|
|
||||||
|
|
||||||
// Display Text
|
|
||||||
int lineCount = 0;
|
|
||||||
for (std::string line : outputList) {
|
|
||||||
cairo_move_to(ctx, REPORT_TEXT_START_X,
|
|
||||||
REPORT_HEIGHT -
|
|
||||||
(REPORT_TEXT_JUMP_Y * (outputList.size() - lineCount++)));
|
|
||||||
cairo_set_source_rgb(ctx, CAIRO_QUARTZ);
|
|
||||||
cairo_show_text(ctx, line.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string data;
|
|
||||||
cairo_surface_write_to_png_stream(surface, cairoOutputAsPNGStream, &data);
|
|
||||||
|
|
||||||
// Ugh cleanup
|
|
||||||
cairo_surface_destroy(surface);
|
|
||||||
cairo_destroy(ctx);
|
|
||||||
return data;
|
|
||||||
}
|
|
@@ -1,99 +0,0 @@
|
|||||||
#include "CairoTools.hpp"
|
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
|
||||||
#include <stb/stb_image.h>
|
|
||||||
|
|
||||||
#include <webp/decode.h>
|
|
||||||
#include <webp/types.h>
|
|
||||||
|
|
||||||
std::unordered_map<std::string,
|
|
||||||
std::function<cairo_surface_t *(const std::string &)>>
|
|
||||||
supportedImageFileTypes{{"image/png", pngToCairoSurface},
|
|
||||||
{"image/jpeg", jpegToCairoSurface},
|
|
||||||
{"image/webp", webpToCairoSurface}};
|
|
||||||
|
|
||||||
cairo_status_t cairoReadPNGdata(void *closure, unsigned char *data,
|
|
||||||
unsigned int length) {
|
|
||||||
std::string *imageData = static_cast<std::string *>(closure);
|
|
||||||
static size_t offset = 0;
|
|
||||||
|
|
||||||
if (offset + length > imageData->size()) {
|
|
||||||
return CAIRO_STATUS_READ_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(data, imageData->data() + offset, length);
|
|
||||||
offset += length;
|
|
||||||
return CAIRO_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
cairo_status_t cairoOutputAsPNGStream(void *closure, const unsigned char *data,
|
|
||||||
unsigned int length) {
|
|
||||||
std::string *output = static_cast<std::string *>(closure);
|
|
||||||
output->append(reinterpret_cast<const char *>(data), length);
|
|
||||||
return CAIRO_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
cairo_surface_t *pngToCairoSurface(const std::string &data) {
|
|
||||||
return cairo_image_surface_create_from_png_stream(
|
|
||||||
cairoReadPNGdata, const_cast<std::string *>(&data));
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// JPEG and WEBP
|
|
||||||
///
|
|
||||||
|
|
||||||
inline cairo_surface_t *swizzleToBGRA(unsigned char *data, int width,
|
|
||||||
int height, bool isjpeg = true) {
|
|
||||||
// AI code start - Reviewed, looks solid
|
|
||||||
cairo_surface_t *surface =
|
|
||||||
cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
|
|
||||||
unsigned char *surface_data = cairo_image_surface_get_data(surface);
|
|
||||||
int stride = cairo_image_surface_get_stride(surface);
|
|
||||||
|
|
||||||
// Convert RGB to BGRA
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
unsigned char *src =
|
|
||||||
data + (y * width + x) * (isjpeg ? 3 : 4); // Swizzling
|
|
||||||
unsigned char *dst = surface_data + y * stride + x * 4; // Still swizzling
|
|
||||||
dst[0] = src[2]; // B
|
|
||||||
dst[1] = src[1]; // G
|
|
||||||
dst[2] = src[0]; // R
|
|
||||||
dst[3] = src[3]; // A
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cairo_surface_mark_dirty(surface);
|
|
||||||
// AI code end
|
|
||||||
return surface;
|
|
||||||
}
|
|
||||||
|
|
||||||
cairo_surface_t *jpegToCairoSurface(const std::string &data) {
|
|
||||||
int width, height, channels;
|
|
||||||
unsigned char *imgData = stbi_load_from_memory(
|
|
||||||
reinterpret_cast<const unsigned char *>(data.data()), data.size(), &width,
|
|
||||||
&height, &channels, 3 // Channel count
|
|
||||||
);
|
|
||||||
|
|
||||||
if (imgData == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto image = swizzleToBGRA(imgData, width, height);
|
|
||||||
stbi_image_free(imgData);
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
cairo_surface_t *webpToCairoSurface(const std::string &data) {
|
|
||||||
int width, height;
|
|
||||||
unsigned char *imgData =
|
|
||||||
WebPDecodeRGBA(reinterpret_cast<const uint8_t *>(data.data()),
|
|
||||||
data.size(), &width, &height);
|
|
||||||
|
|
||||||
if (imgData == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto image = swizzleToBGRA(imgData, width, height, false);
|
|
||||||
WebPFree(imgData);
|
|
||||||
return image;
|
|
||||||
}
|
|
@@ -1,32 +0,0 @@
|
|||||||
#include <cairo/cairo.h>
|
|
||||||
#include <dpp/dpp.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#define REPORT_WIDTH 1000
|
|
||||||
#define REPORT_HEIGHT 1200
|
|
||||||
#define REPORT_HEIGHT_OFFSET 200
|
|
||||||
#define REPORT_TEXT_START_X 40
|
|
||||||
#define REPORT_TEXT_JUMP_Y 125
|
|
||||||
#define REPORT_TEXT_FONT_SIZE 120.0
|
|
||||||
#define REPORT_TEXT_LENGTH 26
|
|
||||||
#define REPORT_RESOURCE_BUMPER_PATH "./assets/report_bumper.png"
|
|
||||||
#define CAIRO_QUARTZ 0.87, 0.87, 0.87
|
|
||||||
#define CAIRO_BLACK 0.0, 0.0, 0.0
|
|
||||||
|
|
||||||
std::string GenerateReportImage(cairo_surface_t *background,
|
|
||||||
std::string headline);
|
|
||||||
|
|
||||||
// File type management
|
|
||||||
cairo_status_t cairoReadPNGdata(void *closure, unsigned char *data,
|
|
||||||
unsigned int length);
|
|
||||||
|
|
||||||
cairo_status_t cairoOutputAsPNGStream(void *closure, const unsigned char *data,
|
|
||||||
unsigned int length);
|
|
||||||
|
|
||||||
cairo_surface_t *pngToCairoSurface(const std::string &data);
|
|
||||||
cairo_surface_t *jpegToCairoSurface(const std::string &data);
|
|
||||||
cairo_surface_t *webpToCairoSurface(const std::string &data);
|
|
||||||
|
|
||||||
extern std::unordered_map<std::string,
|
|
||||||
std::function<cairo_surface_t *(const std::string &)>>
|
|
||||||
supportedImageFileTypes;
|
|
@@ -1,3 +0,0 @@
|
|||||||
// Unity Build
|
|
||||||
#include "CairoGenerate.cpp"
|
|
||||||
#include "CairoTools.cpp"
|
|
2
src/local_en.hpp
Normal file
2
src/local_en.hpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define CURRENCY_NAME "The Night Coin"
|
||||||
|
#define COMMAND_BALANCE_DESCRIPTION "See your balance of " CURRENCY_NAME
|
53
src/main.cpp
Normal file
53
src/main.cpp
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#include "../token.h"
|
||||||
|
#include "Commands.hpp"
|
||||||
|
#include "SQL.hpp"
|
||||||
|
#include "local_en.hpp"
|
||||||
|
|
||||||
|
#include <dpp/cluster.h>
|
||||||
|
#include <dpp/dispatcher.h>
|
||||||
|
#include <dpp/dpp.h>
|
||||||
|
#include <dpp/once.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
// SQL database set up
|
||||||
|
sqlite3_open("discordServer.db", &database);
|
||||||
|
|
||||||
|
// Fuck dude capitalism 😔😔😔
|
||||||
|
execSQL("CREATE TABLE IF NOT EXISTS MONEY("
|
||||||
|
"UID INT PRIMARY KEY NOT NULL,"
|
||||||
|
"Cash INT NOT NULL DEFAULT 0)");
|
||||||
|
|
||||||
|
// Bot setup bullshit
|
||||||
|
dpp::cluster bot(TOKEN);
|
||||||
|
|
||||||
|
// Neat utility
|
||||||
|
bot.on_log(dpp::utility::cout_logger());
|
||||||
|
|
||||||
|
bot.on_slashcommand([](const dpp::slashcommand_t &event) {
|
||||||
|
auto command = Commands.find(event.command.get_command_name());
|
||||||
|
if (command != Commands.end()) {
|
||||||
|
command->second(event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
event.reply("Could not find that command :(");
|
||||||
|
});
|
||||||
|
|
||||||
|
bot.on_ready([&bot](const dpp::ready_t &event) {
|
||||||
|
if (dpp::run_once<struct register_bot_commands>()) {
|
||||||
|
bot.global_command_create(
|
||||||
|
dpp::slashcommand("ping", "Ping-pong test", bot.me.id));
|
||||||
|
bot.guild_command_create(
|
||||||
|
dpp::slashcommand("balance", COMMAND_BALANCE_DESCRIPTION, bot.me.id),
|
||||||
|
GUILD);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dpp::run_once<struct clear_bot_commands>()) {
|
||||||
|
// bot.global_command_delete(1395839332220408051);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove dpp::st_wait if you want it to return execution
|
||||||
|
// (so like async I assume?)
|
||||||
|
bot.start(dpp::st_wait);
|
||||||
|
}
|
Reference in New Issue
Block a user