Skip to content
This repository has been archived by the owner on Sep 16, 2024. It is now read-only.

Commit

Permalink
Initial bot stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
OFFTKP committed Dec 17, 2023
1 parent d5beda8 commit 7f8a580
Show file tree
Hide file tree
Showing 11 changed files with 642 additions and 15 deletions.
3 changes: 2 additions & 1 deletion .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ BraceWrapping:
AfterNamespace: true
AfterStruct: true
AfterUnion: true
BeforeElse: true
BeforeElse: true
WhitespaceSensitiveMacros: ['EM_ASM', 'EM_JS', 'EM_ASM_', 'EM_JS_']
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ option(USE_LUA "Use lua for script support" ON)

add_subdirectory(vendored/fmt)
add_subdirectory(vendored/argparse)
add_subdirectory(vendored/DPP)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down Expand Up @@ -51,19 +52,26 @@ set(HYDRA_QT_FILES
vendored/argparse/argparse.c
)

set(HYDRA_BOT_FILES
discord/bot.cxx
vendored/gifenc.c
)

set(HYDRA_INCLUDE_DIRECTORIES
${HYDRA_INCLUDE_DIRECTORIES}
include
core/include
vendored
vendored/fmt/include
qt/
discord/
man/
)

qt_add_executable(hydra
MANUAL_FINALIZATION
${HYDRA_QT_FILES}
${HYDRA_BOT_FILES}
)

if(WIN32)
Expand All @@ -87,6 +95,7 @@ target_link_libraries(hydra PRIVATE
${LUA_LIBRARIES}
OpenSSL::SSL
fmt::fmt
dpp
)
target_include_directories(hydra PRIVATE ${HYDRA_INCLUDE_DIRECTORIES})
target_compile_definitions(hydra PRIVATE HYDRA_VERSION="${PROJECT_VERSION}")
Expand Down
198 changes: 198 additions & 0 deletions discord/bot.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
#include "commands.hxx"
#include "corewrapper.hxx"
#include "hydra/core.hxx"
#include "message.h"
#include "unicode_emoji.h"
#include <compatibility.hxx>
#include <dpp.h>
#include <filesystem>
#include <settings.hxx>
#include <string>

constexpr uint32_t operator""_hash(const char* str, size_t)
{
return hydra::str_hash(str);
}

namespace fs = std::filesystem;

std::shared_ptr<hydra::EmulatorWrapper> emulator;

int bot_main()
{
std::string token = Settings::Get("bot_token");

if (token.empty())
{
token = std::string(std::getenv("BOT_TOKEN"));
Settings::Set("bot_token", token);
}

if (token.empty())
{
std::cerr << "No bot token found. Please set the BOT_TOKEN environment variable."
<< std::endl;
return 1;
}

std::string core_path = Settings::Get("core_path");

if (core_path.empty())
{
core_path = std::string(std::getenv("CORE_PATH"));
Settings::Set("core_path", core_path);
}

if (core_path.empty())
{
std::cerr << "No core path found. Please set the CORE_PATH environment variable."
<< std::endl;
return 1;
}

emulator = hydra::EmulatorFactory::Create(fs::path(core_path) / "libAlber.so");

dpp::cluster bot(token);

bot.on_log(dpp::utility::cout_logger());

bot.on_ready([&bot](const dpp::ready_t& event) {
if (dpp::run_once<struct register_bot_commands>())
{
std::cout << "Registering commands" << std::endl;
bot.global_bulk_command_create(
Commands::Get(bot.me.id), [](const dpp::confirmation_callback_t& callback) {
if (callback.is_error())
{
std::cout << "Failed to register commands: " << callback.http_info.body
<< std::endl;
}
else
{
std::cout << "Successfully registered commands" << std::endl;
}
});
}
});

bot.on_slashcommand([](const dpp::slashcommand_t& event) {
switch (hydra::str_hash(event.command.get_command_name().c_str()))
{
case "ping"_hash:
{
event.reply("Pong!");
break;
}
case "status"_hash:
{
dpp::embed embed =
dpp::embed()
.set_title(emulator->GetInfo(hydra::InfoType::CoreName))
.set_url(emulator->GetInfo(hydra::InfoType::Website))
.set_description(emulator->GetInfo(hydra::InfoType::Description))
.set_author(emulator->GetInfo(hydra::InfoType::Author),
"https://github.com/hydra-emu/hydra", "attachment://icon.png")
.set_thumbnail("attachment://icon.png");
dpp::message msg = dpp::message(event.command.channel_id, embed);
if (emulator->GetIcon().size() > 0)
{
msg.add_file(
"icon.png",
std::string(emulator->GetIcon().begin(), emulator->GetIcon().end()),
"image/png");
}
event.reply(msg);
break;
}
case "screen"_hash:
{
dpp::message msg(event.command.channel_id, "");
msg.add_component(dpp::component()
.add_component(dpp::component()
.set_label("L")
.set_type(dpp::cot_button)
.set_style(dpp::cos_secondary)
.set_id("l_button"))
.add_component(dpp::component()
.set_label("")
.set_type(dpp::cot_button)
.set_style(dpp::cos_primary)
.set_id("up_button"))
.add_component(dpp::component()
.set_label("R")
.set_type(dpp::cot_button)
.set_style(dpp::cos_secondary)
.set_id("r_button"))
.add_component(dpp::component()
.set_label("A")
.set_type(dpp::cot_button)
.set_style(dpp::cos_success)
.set_id("a_button"))
.add_component(dpp::component()
.set_label("X")
.set_type(dpp::cot_button)
.set_style(dpp::cos_secondary)
.set_id("x_button")))
.add_component(dpp::component()
.add_component(dpp::component()
.set_label("")
.set_type(dpp::cot_button)
.set_style(dpp::cos_primary)
.set_id("left_button"))
.add_component(dpp::component()
.set_label("")
.set_type(dpp::cot_button)
.set_style(dpp::cos_primary)
.set_id("down_button"))
.add_component(dpp::component()
.set_label("")
.set_type(dpp::cot_button)
.set_style(dpp::cos_primary)
.set_id("right_button"))
.add_component(dpp::component()
.set_label("Y")
.set_type(dpp::cot_button)
.set_style(dpp::cos_secondary)
.set_id("y_button"))
.add_component(dpp::component()
.set_label("B")
.set_type(dpp::cot_button)
.set_style(dpp::cos_danger)
.set_id("b_button")))
.add_component(dpp::component()
.add_component(dpp::component()
.set_label("👆")
.set_type(dpp::cot_button)
.set_style(dpp::cos_secondary)
.set_id("touch_button"))
.add_component(dpp::component()
.set_label("\u200b")
.set_type(dpp::cot_button)
.set_style(dpp::cos_secondary)
.set_id("spacer2")
.set_disabled(true))
.add_component(dpp::component()
.set_label("\u200b")
.set_type(dpp::cot_button)
.set_style(dpp::cos_secondary)
.set_id("spacer1")
.set_disabled(true))
.add_component(dpp::component()
.set_label("")
.set_type(dpp::cot_button)
.set_style(dpp::cos_secondary)
.set_id("start_button"))
.add_component(dpp::component()
.set_label("")
.set_type(dpp::cot_button)
.set_style(dpp::cos_secondary)
.set_id("select_button")));
event.reply(msg);
break;
}
}
});

bot.start(dpp::st_wait);
return 0;
}
3 changes: 3 additions & 0 deletions discord/bot.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

int bot_main();
16 changes: 16 additions & 0 deletions discord/commands.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include <dpp.h>
#include <vector>

struct Commands
{
static const std::vector<dpp::slashcommand>& Get(uint64_t appid)
{
static std::vector<dpp::slashcommand> commands = {
dpp::slashcommand("ping", "Ping the bot", appid),
dpp::slashcommand("status", "Print the emulator status", appid),
dpp::slashcommand("screen", "Show the game screen", appid)};
return commands;
}
};
46 changes: 45 additions & 1 deletion include/corewrapper.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "ELFIO/elfio/elfio.hpp"
#endif
#include "scopeguard.hxx"
#include "stb_image_write.h"
#include <filesystem>
#include <hydra/core.hxx>

Expand Down Expand Up @@ -140,6 +141,11 @@ namespace hydra
void EnableCheat(uint32_t handle);
void DisableCheat(uint32_t handle);

const std::vector<uint8_t>& GetIcon()
{
return icon_;
}

private:
dynlib_handle_t handle;
void (*destroy_function)(IBase*);
Expand All @@ -153,6 +159,7 @@ namespace hydra
void save_cheats();

std::vector<CheatMetadata> cheats_;
std::vector<uint8_t> icon_;

EmulatorWrapper(const EmulatorWrapper&) = delete;
friend struct EmulatorFactory;
Expand Down Expand Up @@ -197,8 +204,45 @@ namespace hydra
return nullptr;
}

return std::shared_ptr<EmulatorWrapper>(
auto emulator = std::shared_ptr<EmulatorWrapper>(
new EmulatorWrapper(create_emu_p(), handle, destroy_emu_p, get_info_p));

if (get_info_p(hydra::InfoType::IconData) != nullptr &&
get_info_p(hydra::InfoType::IconWidth) != nullptr &&
get_info_p(hydra::InfoType::IconHeight) != nullptr)
{
int width = std::atoi(get_info_p(hydra::InfoType::IconWidth));
int height = std::atoi(get_info_p(hydra::InfoType::IconHeight));

if (width <= 0 || height <= 0)
{
printf("Invalid icon size %dx%d\n", width, height);
return nullptr;
}

std::vector<uint8_t> temp = std::vector<uint8_t>(width * height * 4);
memcpy(temp.data(), get_info_p(hydra::InfoType::IconData), temp.size());

for (size_t i = 0; i < temp.size(); i += 4)
{
uint8_t r = temp[i + 0];
uint8_t g = temp[i + 1];
uint8_t b = temp[i + 2];
uint8_t a = temp[i + 3];
temp[i + 0] = a;
temp[i + 1] = b;
temp[i + 2] = g;
temp[i + 3] = r;
}

int size;
void* data = stbi_write_png_to_mem(temp.data(), 0, width, height, 4, &size);
emulator->icon_.resize(size);
memcpy(emulator->icon_.data(), data, size);
free(data);
}

return emulator;
}

static std::shared_ptr<EmulatorWrapper> Create(const std::filesystem::path& path)
Expand Down
Loading

0 comments on commit 7f8a580

Please sign in to comment.