Compare commits
19 Commits
50454b8f74
...
main
Author | SHA1 | Date | |
---|---|---|---|
14d98194b3 | |||
6ef969edb6 | |||
8dda053dcf | |||
3c4aa768ec | |||
28253e423c | |||
09abd6c116 | |||
ba2ad34d6e | |||
4e33e07188 | |||
7f147bb58c | |||
f662317bdb | |||
efa80c4c87 | |||
7a3d59e03e | |||
d37dd56496 | |||
90483c9dcd | |||
1450dd4621 | |||
01c8e9d03b | |||
ceaf2a0c2d | |||
fcab736436 | |||
3822b689f0 |
@@ -1,24 +1,31 @@
|
||||
# Minimum CMake version required, we'll just use the latest version.
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
# Project name, version and description
|
||||
project(TheBartender VERSION 1.0)
|
||||
project(TheBartender VERSION 0.3)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
file(COPY assets DESTINATION ${CMAKE_BINARY_DIR})
|
||||
|
||||
# Create an executable
|
||||
add_executable(${PROJECT_NAME} src/Base/Entry.cpp src/Commands.cpp)
|
||||
add_executable(${PROJECT_NAME} src/Base/Entry.cpp src/Commands.cpp
|
||||
src/Utility/Utility.cpp)
|
||||
|
||||
# Find our pre-installed DPP package (using FindDPP.cmake).
|
||||
find_package(DPP REQUIRED)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
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.
|
||||
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.
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${DPP_INCLUDE_DIR}
|
||||
${SQLITE3_INCLUDE_DIR})
|
||||
target_include_directories(
|
||||
${PROJECT_NAME} PRIVATE ${DPP_INCLUDE_DIR} ${SQLITE3_INCLUDE_DIR}
|
||||
${CAIRO_INCLUDE_DIR} ${WEBP_INCLUDE_DIR})
|
||||
|
||||
# Set C++ version
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 20
|
||||
|
BIN
assets/report_bumper.png
Normal file
BIN
assets/report_bumper.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
@@ -1,12 +1,46 @@
|
||||
// Bot info
|
||||
#define BOT_NAME "The Bartender Bot"
|
||||
#define BOT_VERSION "v0.3"
|
||||
|
||||
#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"
|
||||
@@ -30,7 +64,9 @@
|
||||
"## " BOT_NAME " " BOT_VERSION \
|
||||
"\n-> Written by <@!607952795794145281>.\n-> Source code " \
|
||||
"https://git.thenight.club/cat/BartenderBot.\n-> Made with " \
|
||||
"[D++](<https://dpp.dev/>) and tears."
|
||||
"[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
|
||||
|
@@ -1,8 +1,9 @@
|
||||
#include "../../settings.hpp"
|
||||
#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>
|
||||
@@ -32,6 +33,16 @@ int main(int argc, char **argv) {
|
||||
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);
|
||||
|
@@ -1,12 +1,13 @@
|
||||
#include "../settings.hpp"
|
||||
#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(const dpp::slashcommand_t &event, dpp::cluster &bot)>>
|
||||
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);
|
||||
@@ -14,27 +15,40 @@ void deleteCommands(const dpp::ready_t &event, dpp::cluster &bot) {
|
||||
|
||||
void createCommands(const dpp::ready_t &event, dpp::cluster &bot) {
|
||||
bot.global_command_create(
|
||||
dpp::slashcommand("ping", COMMAND_PING_DESCRIPTION, bot.me.id));
|
||||
dpp::slashcommand(COMMAND_PING, COMMAND_PING_DESCRIPTION, bot.me.id));
|
||||
|
||||
bot.guild_command_create(
|
||||
dpp::slashcommand("about", COMMAND_ABOUT_DESCRIPTION, bot.me.id), GUILD);
|
||||
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)),
|
||||
|
||||
// Money related stuff
|
||||
bot.guild_command_create(
|
||||
dpp::slashcommand("balance", COMMAND_BALANCE_DESCRIPTION, bot.me.id)
|
||||
// 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)),
|
||||
GUILD);
|
||||
bot.guild_command_create(
|
||||
dpp::slashcommand("bal", COMMAND_BALANCE_DESCRIPTION, bot.me.id)
|
||||
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)),
|
||||
GUILD);
|
||||
|
||||
bot.guild_command_create(
|
||||
dpp::slashcommand("pay", COMMAND_PAY_DESCRIPTION, bot.me.id)
|
||||
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))
|
||||
@@ -42,33 +56,20 @@ void createCommands(const dpp::ready_t &event, dpp::cluster &bot) {
|
||||
dpp::command_option_type::co_integer, "amount",
|
||||
COMMAND_PAY_ARGS_AMOUNT_DESCRIPTION, true)
|
||||
.set_min_value(1)),
|
||||
GUILD);
|
||||
|
||||
bot.guild_command_create(
|
||||
dpp::slashcommand("print_money", COMMAND_PRINT_DESCRIPTION, bot.me.id)
|
||||
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)),
|
||||
GUILD);
|
||||
|
||||
bot.guild_command_create(
|
||||
dpp::slashcommand("burn_money", COMMAND_BURN_DESCRIPTION, bot.me.id)
|
||||
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)),
|
||||
GUILD);
|
||||
|
||||
bot.guild_command_create(
|
||||
dpp::slashcommand("money_leaderboard",
|
||||
dpp::slashcommand(COMMAND_MONEY_LEADERBOARD,
|
||||
COMMAND_MONEY_LEADERBOARD_DESCRIPTION, bot.me.id),
|
||||
GUILD);
|
||||
};
|
||||
|
||||
bot.guild_command_create(
|
||||
dpp::slashcommand("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)),
|
||||
GUILD);
|
||||
bot.guild_bulk_command_create(guildCommands, GUILD);
|
||||
}
|
||||
|
@@ -1,17 +1,24 @@
|
||||
// Unity Build
|
||||
#include "Commands/GenerativeCommands.cpp"
|
||||
#include "Commands/MoneyCommands.cpp"
|
||||
#include "Commands/OtherCommands.cpp"
|
||||
|
||||
// Component Responses
|
||||
#include "Commands/Components/GenerativeComponents.cpp"
|
||||
|
||||
// Registry
|
||||
std::unordered_map<
|
||||
std::string,
|
||||
std::function<void(const dpp::slashcommand_t &event, dpp::cluster &bot)>>
|
||||
Commands{{"ping", commandPing},
|
||||
{"about", commandAbout},
|
||||
{"balance", commandBalance},
|
||||
{"bal", commandBalance},
|
||||
{"pay", commandPay},
|
||||
{"print_money", commandPrintMoney},
|
||||
{"burn_money", commandBurnMoney},
|
||||
{"money_leaderboard", commandMoneyLeaderboard},
|
||||
{"get_pfp", commandGetPFP}};
|
||||
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}};
|
||||
|
53
src/Commands/Components/GenerativeComponents.cpp
Normal file
53
src/Commands/Components/GenerativeComponents.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#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); }
|
61
src/Commands/GenerativeCommands.cpp
Normal file
61
src/Commands/GenerativeCommands.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
#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,9 +0,0 @@
|
||||
#include <dpp/snowflake.h>
|
||||
|
||||
// Helper methods
|
||||
inline void increaseFromUsersBalance(const dpp::snowflake userid,
|
||||
std::uint64_t amount);
|
||||
inline bool deductFromUsersBalance(const dpp::snowflake userid,
|
||||
std::uint64_t amount);
|
||||
inline std::string getUserBalance(const dpp::snowflake userid);
|
||||
inline void addUserToDatabase(const dpp::snowflake userid);
|
@@ -1,6 +1,6 @@
|
||||
#include "../../settings.hpp" // This is where language is imported
|
||||
#include "../Base/SQL.hpp"
|
||||
#include "InlineDefinitions.hpp"
|
||||
#include "../Common.hpp"
|
||||
#include "TransactionMethods.hpp"
|
||||
|
||||
#include <dpp/appcommand.h>
|
||||
#include <dpp/cluster.h>
|
||||
@@ -34,12 +34,13 @@ void commandPay(const dpp::slashcommand_t &event, dpp::cluster &bot) {
|
||||
std::get<dpp::snowflake>(event.get_parameter("recipient")).str();
|
||||
std::uint64_t amount = std::get<std::int64_t>(event.get_parameter("amount"));
|
||||
|
||||
// See if we can deduct the payment first
|
||||
if (!deductFromUsersBalance(event.command.get_issuing_user().id, 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);
|
||||
@@ -68,12 +69,13 @@ void commandBurnMoney(const dpp::slashcommand_t &event, dpp::cluster &bot) {
|
||||
}
|
||||
std::uint64_t amount = std::get<std::int64_t>(event.get_parameter("amount"));
|
||||
|
||||
// Insufficient in balance
|
||||
if (!deductFromUsersBalance(ADMIN_ID, 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)));
|
||||
}
|
||||
@@ -112,30 +114,28 @@ void commandMoneyLeaderboard(const dpp::slashcommand_t &event,
|
||||
}
|
||||
|
||||
///
|
||||
/// HELPER INLINE METHODS
|
||||
/// Transaction Methods
|
||||
///
|
||||
|
||||
inline void increaseFromUsersBalance(const dpp::snowflake userid,
|
||||
std::uint64_t amount) {
|
||||
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());
|
||||
}
|
||||
|
||||
inline bool deductFromUsersBalance(const dpp::snowflake userid,
|
||||
std::uint64_t amount) {
|
||||
void deductFromUsersBalance(const dpp::snowflake userid, std::uint64_t amount) {
|
||||
std::uint64_t balance = std::stoll(getUserBalance(userid));
|
||||
if (balance < amount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
execSQL("UPDATE MONEY SET CASH=" + std::to_string(balance - amount) +
|
||||
" WHERE UID=" + userid.str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline std::string getUserBalance(const dpp::snowflake userid) {
|
||||
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);
|
||||
|
||||
@@ -150,6 +150,6 @@ inline std::string getUserBalance(const dpp::snowflake userid) {
|
||||
return balance.substr(begining, balance.find(';') - begining);
|
||||
}
|
||||
|
||||
inline void addUserToDatabase(const dpp::snowflake userid) {
|
||||
void addUserToDatabase(const dpp::snowflake userid) {
|
||||
execSQL("INSERT INTO MONEY (UID) VALUES (" + userid.str() + ");");
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#include "../../settings.hpp"
|
||||
#include "../Common.hpp"
|
||||
#include <dpp/dispatcher.h>
|
||||
#include <dpp/dpp.h>
|
||||
#include <dpp/guild.h>
|
||||
@@ -23,6 +23,7 @@ void commandGetPFP(const dpp::slashcommand_t &event, dpp::cluster &bot) {
|
||||
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);
|
||||
|
10
src/Commands/TransactionMethods.hpp
Normal file
10
src/Commands/TransactionMethods.hpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#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);
|
23
src/Common.hpp
Normal file
23
src/Common.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#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"
|
85
src/Utility/CairoGenerate.cpp
Normal file
85
src/Utility/CairoGenerate.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#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;
|
||||
}
|
99
src/Utility/CairoTools.cpp
Normal file
99
src/Utility/CairoTools.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
#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;
|
||||
}
|
32
src/Utility/CairoTools.hpp
Normal file
32
src/Utility/CairoTools.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#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;
|
3
src/Utility/Utility.cpp
Normal file
3
src/Utility/Utility.cpp
Normal file
@@ -0,0 +1,3 @@
|
||||
// Unity Build
|
||||
#include "CairoGenerate.cpp"
|
||||
#include "CairoTools.cpp"
|
Reference in New Issue
Block a user