1
0
Fork 0
mirror of https://gitlab.com/niansa/SomeBot.git synced 2025-03-06 20:48:26 +01:00
SomeBot/modules/custom.cpp
2023-10-06 22:53:39 +02:00

619 lines
36 KiB
C++

#include "../bot.hpp"
#include <string>
#include <string_view>
#include <exception>
#include <thread>
#include <memory>
#include <ctime>
#include <lua.h>
#include <lualib.h>
#include <Luau/Compiler.h>
#include <LuaBridge/LuaBridge.h>
#include <LuaBridge/Vector.h>
#include <LuaBridge/Map.h>
class LuaExecution {
std::unique_ptr<lua_State, void (*)(lua_State*)> state;
static int assertionHandler(const char* expr, const char* file, int line, const char* function) {
printf("%s<%s>(%d): ASSERTION FAILED: %s\n", file, function, line, expr);
return 1;
}
struct BaseContext {
dpp::snowflake guild_id;
Bot *bot;
} baseContext;
struct Context : public BaseContext {
const dpp::message *msg;
};
public:
LuaExecution(Bot *bot, dpp::snowflake guild_id) : state(luaL_newstate(), lua_close), baseContext{guild_id, bot} {
// Set assertion handler
Luau::assertHandler() = assertionHandler;
// Get state
auto state = this->state.get();
// Enable exceptions
luabridge::LuaException::enableExceptions(state);
// Load initial libraries
luaL_openlibs(state);
// Do bindings
using namespace dpp;
luabridge::getGlobalNamespace(state)
.beginClass<Context>("Context")
.addProperty("guild_id", &Context::guild_id, false)
.addProperty("message", &Context::msg, true)
.endClass()
.beginClass<snowflake>("Snowflake")
.addConstructor<void (const uint64_t&), void (const std::string&)>()
.addProperty("integer", &snowflake::operator uint64_t)
.addProperty("string", +[] (const snowflake *o) -> std::string { return std::to_string(*o); })
.addProperty("creation_time", &snowflake::get_creation_time)
.addProperty("worker_id", &snowflake::get_worker_id)
.addProperty("process_id", &snowflake::get_process_id)
.addProperty("increment", &snowflake::get_increment)
.endClass()
.beginClass<message>("Message")
.addProperty("id", &message::id, false)
.addProperty("channel_id", &message::channel_id, true)
.addProperty("guild_id", &message::guild_id, false)
.addProperty("author", &message::author, true)
.addProperty("member", &message::member, true)
.addProperty("content", &message::content, true)
.addProperty("components", &message::components, true)
.addProperty("sent", &message::sent, true)
.addProperty("edited", &message::edited, true)
.addProperty("mentions", &message::mentions, true)
.addProperty("mention_roles", &message::mention_roles, true)
.addProperty("mention_channels", &message::mention_channels, true)
.addProperty("attachments", &message::attachments, true)
.addProperty("embeds", &message::embeds, true)
.addProperty("reactions", &message::reactions, true)
.addProperty("nonce", &message::nonce, true)
.addProperty("webhook_id", &message::webhook_id, true)
.addProperty("stickers", &message::stickers, true)
.addProperty("file_name", &message::filename, true)
.addProperty("file_content", &message::filecontent, true)
.addProperty("reference", &message::message_reference, true)
.addProperty("interaction", &message::interaction, true)
.addProperty("allowed_mentions", &message::allowed_mentions, true)
.addProperty("type", &message::type, true)
.addProperty("flags", &message::flags, true)
.addProperty("pinned", &message::pinned, true)
.addProperty("tts", &message::tts, true)
.addProperty("mention_everyone", &message::mention_everyone, true)
.addProperty("is_crossposted", &message::is_crossposted)
.addProperty("is_crosspost", &message::is_crosspost)
.addProperty("suppress_embeds", &message::suppress_embeds)
.addProperty("is_source_message_deleted", &message::is_source_message_deleted)
.addProperty("is_urgent", &message::is_urgent)
.addProperty("has_thread", &message::has_thread)
.addProperty("is_ephemeral", &message::is_ephemeral)
.addProperty("is_loading", &message::is_loading)
.addProperty("is_thread_mention_failed", &message::is_thread_mention_failed)
.addProperty("is_dm", &message::is_dm)
.addFunction("add_component", &message::add_component)
.addFunction("add_embed", &message::add_embed)
.addFunction("send", [cluster = &baseContext.bot->cluster] (const message *o) -> std::optional<dpp::message> {
try {
return cluster->message_create_sync(*o);
} catch (...) {
return {};
}
})
.endClass()
.beginClass<message::message_ref>("MessageRef")
.addProperty("message_id", &message::message_ref::message_id, true)
.addProperty("channel_id", &message::message_ref::channel_id, true)
.addProperty("guild_id", &message::message_ref::guild_id, false)
.addProperty("fail_if_not_exists", &message::message_ref::fail_if_not_exists, true)
.endClass()
.beginClass<message::message_interaction_struct>("MessageInteraction")
.addProperty("id", &message::message_interaction_struct::id, false)
.addProperty("type", &message::message_interaction_struct::type, true)
.addProperty("name", &message::message_interaction_struct::name, true)
.addProperty("user", &message::message_interaction_struct::usr, true)
.endClass()
.beginClass<message::allowed_ref>("MessageAllowedRef")
.addProperty("parse_users", &message::allowed_ref::parse_users, true)
.addProperty("parse_everyone", &message::allowed_ref::parse_everyone, true)
.addProperty("parse_roles", &message::allowed_ref::parse_roles, true)
.addProperty("replied_user", &message::allowed_ref::replied_user, true)
.addProperty("users", &message::allowed_ref::users, true)
.addProperty("roles", &message::allowed_ref::roles, true)
.endClass()
.beginClass<embed>("Embed")
.addProperty("title", &embed::title, true)
.addProperty("type", &embed::type, true)
.addProperty("description", &embed::description, true)
.addProperty("url", &embed::url, true)
.addProperty("timestamp", &embed::timestamp, true)
.addProperty("color", &embed::color, true)
.addProperty("footer", &embed::footer, true)
.addProperty("image", &embed::image, true)
.addProperty("thumbnail", &embed::thumbnail, true)
.addProperty("video", &embed::video, true)
.addProperty("provider", &embed::provider, true)
.addProperty("author", &embed::author, true)
.addProperty("fields", &embed::fields, true)
.endClass()
.beginClass<embed_footer>("EmbedFooter")
.addProperty("text", &embed_footer::text, true)
.addProperty("icon_url", &embed_footer::icon_url, true)
.addProperty("proxy_url", &embed_footer::proxy_url, true)
.endClass()
.beginClass<embed_image>("EmbedImage")
.addProperty("url", &embed_image::url, true)
.addProperty("proxy_url", &embed_image::proxy_url, true)
.addProperty("height", &embed_image::height, false)
.addProperty("width", &embed_image::width, false)
.endClass()
.beginClass<embed_provider>("EmbedProvider")
.addProperty("name", &embed_provider::name, true)
.addProperty("url", &embed_provider::url, true)
.endClass()
.beginClass<embed_author>("EmbedAuthor")
.addProperty("name", &embed_author::name, true)
.addProperty("url", &embed_author::url, true)
.addProperty("icon_url", &embed_author::icon_url, true)
.addProperty("proxy_icon_url", &embed_author::proxy_icon_url, true)
.endClass()
.beginClass<embed_field>("EmbedField")
.addProperty("name", &embed_field::name, true)
.addProperty("value", &embed_field::value, true)
.addProperty("is_inline", &embed_field::is_inline, true)
.endClass()
.beginClass<reaction>("Reaction")
.addProperty("count", &reaction::count, false)
.addProperty("me", &reaction::me, true)
.addProperty("emoji_id", &reaction::emoji_id, true)
.addProperty("emoji_name", &reaction::emoji_name, true)
.endClass()
.beginClass<attachment>("Attachment")
.addProperty("id", &attachment::id, false)
.addProperty("size", &attachment::size, false)
.addProperty("filename", &attachment::filename, true)
.addProperty("description", &attachment::description, true)
.addProperty("url", &attachment::url, false)
.addProperty("proxy_url", &attachment::proxy_url, false)
.addProperty("width", &attachment::width, false)
.addProperty("height", &attachment::height, false)
.addProperty("content_type", &attachment::content_type, false)
.addProperty("ephemeral", &attachment::ephemeral, true)
.addProperty("owner", &attachment::owner, false)
.endClass()
.beginClass<sticker>("Sticker")
.addProperty("id", &sticker::id, false)
.addProperty("pack_id", &sticker::pack_id, true)
.addProperty("name", &sticker::name, true)
.addProperty("description", &sticker::description, true)
.addProperty("tags", &sticker::tags, true)
.addProperty("asset", &sticker::asset, true)
.addProperty("type", &sticker::type, true)
.addProperty("format_type", &sticker::format_type, true)
.addProperty("available", &sticker::available, true)
.addProperty("guild_id", &sticker::guild_id, false)
.addProperty("sticker_user", &sticker::sticker_user, false)
.addProperty("sort_value", &sticker::sort_value, true)
.addProperty("file_name", &sticker::filename, true)
.addProperty("file_content", &sticker::filecontent, true)
.addFunction("get_url", &sticker::get_url)
.endClass()
.beginClass<sticker_pack>("StickerPack")
.addProperty("id", &sticker_pack::id, false)
.addProperty("stickers", &sticker_pack::stickers, true)
.addProperty("name", &sticker_pack::name, true)
.addProperty("description", &sticker_pack::description, true)
.addProperty("sku_id", &sticker_pack::sku_id, true)
.addProperty("cover_sticker_id", &sticker_pack::cover_sticker_id, true)
.addProperty("banner_asset_id", &sticker_pack::banner_asset_id, true)
.endClass()
.beginClass<channel>("Channel")
.addProperty("id", &channel::id, false)
.addProperty("name", &channel::name, true)
.addProperty("topic", &channel::topic, true)
.addProperty("rtc_region", &channel::rtc_region, true)
.addProperty("recipients", &channel::recipients, true)
.addProperty("permission_overwrites", &channel::permission_overwrites, true)
.addProperty("available_tags", &channel::available_tags, true)
.addProperty("icon", &channel::icon, true)
.addProperty("icon_url", +[] (const channel *o) { return o->get_icon_url(); })
.addProperty("owner_id", &channel::owner_id, true)
.addProperty("parent_id", &channel::parent_id, true)
.addProperty("guild_id", &channel::guild_id, false)
.addProperty("last_message_id", &channel::last_message_id, true)
.addProperty("last_pin_timestamp", &channel::last_pin_timestamp, true)
.addProperty("permissions", &channel::permissions, true)
.addProperty("position", &channel::position, true)
.addProperty("bitrate", &channel::bitrate, true)
.addProperty("rate_limit_per_user", &channel::rate_limit_per_user, true)
.addProperty("default_thread_rate_limit_per_user", &channel::default_thread_rate_limit_per_user, true)
.addProperty("default_auto_archive_duration", &channel::default_auto_archive_duration, true)
.addProperty("default_sort_order", &channel::default_sort_order, true)
.addProperty("flags", &channel::flags, true)
.addProperty("type", +[] (const channel* o) { return o->get_type(); }, +[] (channel* o, channel_type v) { o->set_type(v); })
.addProperty("is_nsfw", +[] (const channel* o) { return o->is_nsfw(); }, +[] (channel* o, channel_type v) { o->set_nsfw(v); })
.addProperty("is_locked_permissions", +[] (const channel* o) { return o->is_locked_permissions(); }, +[] (channel* o, channel_type v) { o->set_lock_permissions(v); })
.addProperty("is_text_channel", &channel::is_text_channel)
.addProperty("is_dm", &channel::is_dm)
.addProperty("is_voice_channel", &channel::is_voice_channel)
.addProperty("is_group_dm", &channel::is_group_dm)
.addProperty("is_category", &channel::is_category)
.addProperty("is_forum", &channel::is_forum)
.addProperty("is_news_channel", &channel::is_news_channel)
.addProperty("is_store_channel", &channel::is_store_channel)
.addProperty("is_stage_channel", &channel::is_stage_channel)
.addProperty("is_video_auto", &channel::is_video_auto)
.addProperty("is_video_720p", &channel::is_video_720p)
.addProperty("is_pinned_thread", &channel::is_pinned_thread)
.addProperty("is_tag_required", &channel::is_tag_required)
.addProperty("mention", &channel::get_mention)
.addFunction("add_flag", &channel::add_flag)
.addFunction("remove_flag", &channel::remove_flag)
.addFunction("add_permission_overwrite", &channel::add_permission_overwrite)
.addFunction("get_user_permissions", luabridge::overload<const user*>(&channel::get_user_permissions))
.addFunction("get_member_permissions", luabridge::overload<const guild_member&>(&channel::get_user_permissions))
.addFunction("get_icon_url", &channel::get_icon_url)
.addFunction("get_members", &channel::get_members)
.addFunction("get_voice_members", &channel::get_voice_members)
.addFunction("create", [cluster = &baseContext.bot->cluster] (const channel *o) -> std::optional<dpp::channel> {
try {
return cluster->channel_create_sync(*o);
} catch (...) {
return {};
}
})
.addFunction("edit", [cluster = &baseContext.bot->cluster] (const channel *o) -> std::optional<dpp::channel> {
try {
return cluster->channel_edit_sync(*o);
} catch (...) {
return {};
}
})
.endClass()
.beginClass<user>("User")
.addProperty("id", &user::id, false)
.addProperty("username", &user::username, true)
.addProperty("avatar", &user::avatar, true)
.addProperty("avatar_url", +[] (const user *o) { return o->get_avatar_url(); })
.addProperty("flags", &user::flags, true)
.addProperty("discriminator", &user::discriminator, true)
.addProperty("mention", &user::get_mention)
.addProperty("is_bot", &user::is_bot)
.addProperty("is_mfa_enabled", &user::is_mfa_enabled)
.addProperty("has_nitro_full", &user::has_nitro_full)
.addProperty("has_nitro_classic", &user::has_nitro_classic)
.addProperty("has_nitro_basic", &user::has_nitro_basic)
.addProperty("is_discord_employee", &user::is_discord_employee)
.addProperty("is_partnered_owner", &user::is_partnered_owner)
.addProperty("has_hypesquad_events", &user::has_hypesquad_events)
.addProperty("is_bughunter_1", &user::is_bughunter_1)
.addProperty("is_house_bravery", &user::is_house_bravery)
.addProperty("is_house_brilliance", &user::is_house_brilliance)
.addProperty("is_house_balance", &user::is_house_balance)
.addProperty("is_early_supporter", &user::is_early_supporter)
.addProperty("is_team_user", &user::is_team_user)
.addProperty("is_bughunter_2", &user::is_bughunter_2)
.addProperty("is_verified_bot", &user::is_verified_bot)
.addProperty("is_verified_bot_dev", &user::is_verified_bot_dev)
.addProperty("is_certified_moderator", &user::is_certified_moderator)
.addProperty("is_bot_http_interactions", &user::is_bot_http_interactions)
.addProperty("has_animated_icon", &user::has_animated_icon)
.addProperty("formatted_username", &user::format_username)
.addFunction("get_avatar_url", &user::get_avatar_url)
.addFunction("kick", [guild_id = baseContext.guild_id, cluster = &baseContext.bot->cluster] (const user *o) -> bool {
try {
cluster->guild_member_kick_sync(o->id, guild_id);
return true;
} catch (...) {
return false;
}
})
.addFunction("ban", [guild_id = baseContext.guild_id, cluster = &baseContext.bot->cluster] (const user *o, unsigned delete_message_settings) -> bool {
try {
cluster->guild_ban_add_sync(guild_id, o->id, delete_message_settings);
return true;
} catch (...) {
return false;
}
})
.endClass()
.beginClass<guild_member>("Member")
.addProperty("nickname", &guild_member::get_nickname)
.addProperty("roles", &guild_member::get_roles)
.addProperty("guild_id", &guild_member::guild_id, false)
.addProperty("user_id", &guild_member::user_id, false)
.addProperty("avatar", &guild_member::avatar, false)
.addProperty("avatar_url", +[] (const guild_member *o) { return o->get_avatar_url(); })
.addProperty("communication_disabled_until", &guild_member::communication_disabled_until, false)
.addProperty("joined_at", &guild_member::joined_at, false)
.addProperty("premium_since", &guild_member::premium_since, false)
.addProperty("is_communication_disabled", &guild_member::is_communication_disabled)
.addProperty("is_muted", +[] (const guild_member* o) { return o->is_muted(); }, +[] (guild_member* o, bool v) { o->set_mute(v); })
.addProperty("is_deaf", +[] (const guild_member* o) { return o->is_deaf(); }, +[] (guild_member* o, bool v) { o->set_deaf(v); })
.addProperty("is_pending", &guild_member::is_pending)
.addProperty("has_animated_guild_avatar", &guild_member::has_animated_guild_avatar)
.addProperty("user", &guild_member::get_user)
.addFunction("get_avatar_url", &guild_member::get_avatar_url)
.addFunction("mention", &guild_member::get_mention)
.addFunction("kick", [guild_id = baseContext.guild_id, cluster = &baseContext.bot->cluster] (const guild_member *o) -> bool {
try {
cluster->guild_member_kick_sync(o->user_id, guild_id);
return true;
} catch (...) {
return false;
}
})
.addFunction("ban", [guild_id = baseContext.guild_id, cluster = &baseContext.bot->cluster] (const guild_member *o, unsigned delete_message_settings) -> bool {
try {
cluster->guild_ban_add_sync(guild_id, o->user_id, delete_message_settings);
return true;
} catch (...) {
return false;
}
})
.addFunction("edit", [cluster = &baseContext.bot->cluster] (const guild_member *o) -> std::optional<guild_member> {
try {
return cluster->guild_edit_member_sync(*o);
} catch (...) {
return {};
}
})
.endClass()
.beginClass<guild>("Guild")
.addProperty("id", &guild::id, false)
.addProperty("name", &guild::name, true)
.addProperty("vanity_url_code", &guild::vanity_url_code, true)
.addProperty("roles", &guild::roles, false)
.addProperty("channels", &guild::channels, false)
.addProperty("threads", &guild::threads, false)
.addProperty("emojis", &guild::emojis, false)
.addProperty("voice_members", &guild::voice_members, false)
.addProperty("members", &guild::members, false)
.addProperty("welcome_screen", &guild::welcome_screen, true)
.addProperty("icon", &guild::icon, true)
.addProperty("splash", &guild::splash, true)
.addProperty("discovery_splash", &guild::discovery_splash, true)
.addProperty("banner", &guild::banner, true)
.addProperty("owner_id", &guild::owner_id, true)
.addProperty("afk_channel_id", &guild::afk_channel_id, true)
.addProperty("application_id", &guild::application_id, true)
.addProperty("system_channel_id", &guild::system_channel_id, true)
.addProperty("rules_channel_id", &guild::rules_channel_id, true)
.addProperty("public_updates_channel_id", &guild::public_updates_channel_id, true)
.addProperty("widget_channel_id", &guild::widget_channel_id, true)
.addProperty("member_count", &guild::member_count, false)
.addProperty("flags", &guild::flags, false)
.addProperty("max_presences", &guild::max_presences, false)
.addProperty("max_members", &guild::max_members, false)
.addProperty("shard_id", &guild::shard_id, false)
.addProperty("premium_subscription_count", &guild::premium_subscription_count, false)
.addProperty("afk_timeout", &guild::afk_timeout, true)
.addProperty("max_video_channel_users", &guild::max_video_channel_users, false)
.addProperty("default_message_notifications", &guild::default_message_notifications, true)
.addProperty("premium_tier", &guild::premium_tier, false)
.addProperty("verification_level", &guild::verification_level, false)
.addProperty("explicit_content_filter", &guild::explicit_content_filter, true)
.addProperty("mfa_level", &guild::mfa_level, true)
.addProperty("nsfw_level", &guild::nsfw_level, true)
.addProperty("flags_extra", &guild::flags_extra, false)
.addProperty("discovery_splash_url", +[] (const guild *o) { return o->get_discovery_splash_url(); })
.addProperty("icon_url", +[] (const guild *o) { return o->get_icon_url(); })
.addProperty("splash_url", +[] (const guild *o) { return o->get_splash_url(); })
.addProperty("banner_url", +[] (const guild *o) { return o->get_banner_url(); })
.addProperty("is_large", &guild::is_large)
.addProperty("is_unavailable", &guild::is_unavailable)
.addProperty("is_widget_enabled", &guild::widget_enabled)
.addProperty("has_invite_splash", &guild::has_invite_splash)
.addProperty("has_vip_regions", &guild::has_vip_regions)
.addProperty("has_vanity_url", &guild::has_vanity_url)
.addProperty("is_verified", &guild::is_verified)
.addProperty("is_partnered", &guild::is_partnered)
.addProperty("is_community", &guild::is_community)
.addProperty("has_news", &guild::has_news)
.addProperty("is_discoverable", &guild::is_discoverable)
.addProperty("is_featureable", &guild::is_featureable)
.addProperty("has_animated_banner", &guild::has_animated_banner)
.addProperty("has_auto_moderation", &guild::has_auto_moderation)
.addProperty("has_support_server", &guild::has_support_server)
.addProperty("has_animated_icon", &guild::has_animated_icon)
.addProperty("has_banner", &guild::has_banner)
.addProperty("is_welcome_screen_enabled", &guild::is_welcome_screen_enabled)
.addProperty("has_member_verification_gate", &guild::has_member_verification_gate)
.addProperty("is_preview_enabled", &guild::is_preview_enabled)
.addProperty("has_animated_icon_hash", &guild::has_animated_icon_hash)
.addProperty("has_animated_banner_hash", &guild::has_animated_banner_hash)
.addProperty("has_monetization_enabled", &guild::has_monetization_enabled)
.addProperty("has_more_stickers", &guild::has_more_stickers)
.addProperty("has_role_icons", &guild::has_role_icons)
.addProperty("has_seven_day_thread_archive", &guild::has_seven_day_thread_archive)
.addProperty("has_three_day_thread_archive", &guild::has_three_day_thread_archive)
.addProperty("has_ticketed_events", &guild::has_ticketed_events)
.addProperty("has_channel_banners", &guild::has_channel_banners)
.addProperty("has_premium_progress_bar_enabled", &guild::has_premium_progress_bar_enabled)
.addProperty("has_invites_disabled", &guild::has_invites_disabled)
.addFunction("get_base_user_permissions", luabridge::overload<const user*>(&guild::base_permissions))
.addFunction("get_base_member_permissions", luabridge::overload<const guild_member &>(&guild::base_permissions))
.addFunction("get_permission_overwrites", luabridge::overload<const guild_member &, const channel &>(&guild::permission_overwrites))
.addFunction("kick", [guild_id = baseContext.guild_id, cluster = &baseContext.bot->cluster] (const guild *, snowflake user_id) -> bool {
try {
cluster->guild_member_kick_sync(user_id, guild_id);
return true;
} catch (...) {
return false;
}
})
.addFunction("ban", [guild_id = baseContext.guild_id, cluster = &baseContext.bot->cluster] (const guild *, snowflake user_id, unsigned delete_message_settings) -> bool {
try {
cluster->guild_ban_add_sync(guild_id, user_id, delete_message_settings);
return true;
} catch (...) {
return false;
}
})
.addFunction("edit", [cluster = &baseContext.bot->cluster] (const guild *o) -> std::optional<guild> {
try {
return cluster->guild_edit_sync(*o);
} catch (...) {
return {};
}
})
.endClass()
.beginClass<utility::iconhash>("IconHash")
.addProperty("first", &utility::iconhash::first, true)
.addProperty("second", &utility::iconhash::second, true)
.addProperty("string", &utility::iconhash::to_string, &utility::iconhash::set)
.endClass()
.beginClass<permission>("Permission")
.addProperty("integer", &permission::operator uint64_t)
.addFunction("has", &permission::has<uint64_t>)
.addFunction("add", &permission::add<uint64_t>)
.addFunction("set", &permission::set<uint64_t>)
.addFunction("remove", &permission::remove<uint64_t>)
.endClass()
.addFunction("fetch_guild", [guild_id = baseContext.guild_id, cluster = &baseContext.bot->cluster] () -> std::optional<dpp::guild> {
try {
return cluster->guild_get_sync(guild_id);
} catch (...) {
return {};
}
})
.addFunction("fetch_channel", [guild_id = baseContext.guild_id, cluster = &baseContext.bot->cluster] (const dpp::snowflake id) -> std::optional<dpp::channel> {
try {
auto channel = cluster->channel_get_sync(id);
if (channel.guild_id != guild_id) {
return {};
}
return channel;
} catch (...) {
return {};
}
})
.addFunction("fetch_user", [cluster = &baseContext.bot->cluster] (const dpp::snowflake id) -> std::optional<dpp::user> {
try {
return cluster->user_get_sync(id);
} catch (...) {
return {};
}
})
.addFunction("fetch_member", [guild_id = baseContext.guild_id, cluster = &baseContext.bot->cluster] (const dpp::snowflake user_id) -> std::optional<dpp::guild_member> {
try {
return cluster->guild_get_member_sync(guild_id, user_id);
} catch (...) {
return {};
}
})
.addFunction("fetch_message", [guild_id = baseContext.guild_id, cluster = &baseContext.bot->cluster] (const dpp::snowflake id, const dpp::snowflake channel_id) -> std::optional<dpp::message> {
try {
auto msg = cluster->message_get_sync(id, channel_id);
if (msg.guild_id != guild_id) {
return {};
}
return msg;
} catch (...) {
return {};
}
});
}
std::string execute(const std::string& source, const dpp::message *msg) noexcept {
// Get state
auto state = this->state.get();
// We need bytecode
std::string bytecode = Luau::compile(source, Luau::CompileOptions());
// We can then load that bytecode
if (luau_load(state, "code.lua", bytecode.data(), bytecode.size(), 0) != 0) {
size_t len;
const char* msg = lua_tolstring(state, -1, &len);
std::string error(msg, len);
lua_pop(state, 1);
return error;
}
// ... and start executing
int status = lua_resume(state, NULL, 0);
// Check status
if (status != 0) {
// Error!
std::string error;
// Get error string
if (status == LUA_YIELD) {
error = "Thread yielded unexpectedly";
} else if (const char* str = lua_tostring(state, -1)) {
error = str;
}
// Append backtrace
error += "\nStack backtrace:\n";
error += lua_debugtrace(state);
// Clean up and return
lua_pop(state, 1);
return error;
}
// Now, we call into the code
luabridge::LuaRef on_call = luabridge::getGlobal(state, "on_call");
if (!on_call.isCallable()) {
return "'on_call' is not callable";
}
try {
luabridge::LuaResult result = on_call(Context{baseContext, msg});
} catch (const luabridge::LuaException& e) {
return e.what();
}
// Finally, everything seems alright
return {};
}
};
class Custom {
Bot *bot;
public:
Custom(Bot *_bot) : bot(_bot) {
bot->add_messagecommand(Bot::MessageCommand({"Evaluate"}, "Evaluiere Lua code"), [&](const dpp::message_context_menu_t& event) {
// Check that user has the correct permissions
if (!event.command.get_guild().base_permissions(event.command.member).has(dpp::permissions::p_administrator)) {
event.reply(dpp::message("Du musst Administrator sein, um dieses Kommando zu verwenden.").set_flags(dpp::message_flags::m_ephemeral));
return;
}
// Continue in new thread...
std::thread([this, event] () {
// Construct lua execution
LuaExecution exec(bot, event.command.guild_id);
// Get code to execute
const auto& msg = event.get_message();
const auto& code = msg.content;
// Start execution
auto error = exec.execute(code, &msg);
// Report outcome
if (error.empty()) {
event.reply("Success.");
} else {
event.reply("Error:\n```lua\n"+error+"\n```");
}
}).detach();
});
}
};
BOT_ADD_MODULE(Custom);