From b62341284fe128daeb80d1b24f98a54ee692bb47 Mon Sep 17 00:00:00 2001 From: Grinch_ Date: Thu, 10 Mar 2022 04:23:08 +0600 Subject: [PATCH] Add discord rpc support --- .vscode/settings.json | 3 +- depend/discord/achievement_manager.cpp | 98 +++ depend/discord/achievement_manager.h | 34 + depend/discord/activity_manager.cpp | 177 +++++ depend/discord/activity_manager.h | 42 ++ depend/discord/application_manager.cpp | 78 ++ depend/discord/application_manager.h | 30 + depend/discord/core.cpp | 182 +++++ depend/discord/core.h | 64 ++ depend/discord/discord.h | 16 + depend/discord/event.h | 59 ++ depend/discord/ffi.h | 942 ++++++++++++++++++++++++ depend/discord/image_manager.cpp | 57 ++ depend/discord/image_manager.h | 28 + depend/discord/lobby_manager.cpp | 547 ++++++++++++++ depend/discord/lobby_manager.h | 88 +++ depend/discord/network_manager.cpp | 103 +++ depend/discord/network_manager.h | 63 ++ depend/discord/overlay_manager.cpp | 112 +++ depend/discord/overlay_manager.h | 33 + depend/discord/relationship_manager.cpp | 90 +++ depend/discord/relationship_manager.h | 32 + depend/discord/storage_manager.cpp | 158 ++++ depend/discord/storage_manager.h | 46 ++ depend/discord/store_manager.cpp | 160 ++++ depend/discord/store_manager.h | 38 + depend/discord/types.cpp | 769 +++++++++++++++++++ depend/discord/types.h | 491 ++++++++++++ depend/discord/user_manager.cpp | 80 ++ depend/discord/user_manager.h | 31 + depend/discord/voice_manager.cpp | 124 ++++ depend/discord/voice_manager.h | 37 + depend/lib/discord_game_sdk.lib | Bin 0 -> 2358 bytes resource/common/locale/English.json | 11 + src/cheatmenu.cpp | 5 + src/cheatmenu.h | 1 + src/dllmain.cpp | 4 +- src/game.cpp | 2 +- src/menu.cpp | 26 +- src/menu.h | 1 + src/player.cpp | 2 +- src/rpc.cpp | 123 ++++ src/rpc.h | 18 + src/version.h | 2 +- tools/premake5.lua | 72 +- 45 files changed, 5028 insertions(+), 51 deletions(-) create mode 100644 depend/discord/achievement_manager.cpp create mode 100644 depend/discord/achievement_manager.h create mode 100644 depend/discord/activity_manager.cpp create mode 100644 depend/discord/activity_manager.h create mode 100644 depend/discord/application_manager.cpp create mode 100644 depend/discord/application_manager.h create mode 100644 depend/discord/core.cpp create mode 100644 depend/discord/core.h create mode 100644 depend/discord/discord.h create mode 100644 depend/discord/event.h create mode 100644 depend/discord/ffi.h create mode 100644 depend/discord/image_manager.cpp create mode 100644 depend/discord/image_manager.h create mode 100644 depend/discord/lobby_manager.cpp create mode 100644 depend/discord/lobby_manager.h create mode 100644 depend/discord/network_manager.cpp create mode 100644 depend/discord/network_manager.h create mode 100644 depend/discord/overlay_manager.cpp create mode 100644 depend/discord/overlay_manager.h create mode 100644 depend/discord/relationship_manager.cpp create mode 100644 depend/discord/relationship_manager.h create mode 100644 depend/discord/storage_manager.cpp create mode 100644 depend/discord/storage_manager.h create mode 100644 depend/discord/store_manager.cpp create mode 100644 depend/discord/store_manager.h create mode 100644 depend/discord/types.cpp create mode 100644 depend/discord/types.h create mode 100644 depend/discord/user_manager.cpp create mode 100644 depend/discord/user_manager.h create mode 100644 depend/discord/voice_manager.cpp create mode 100644 depend/discord/voice_manager.h create mode 100644 depend/lib/discord_game_sdk.lib create mode 100644 src/rpc.cpp create mode 100644 src/rpc.h diff --git a/.vscode/settings.json b/.vscode/settings.json index c419bd5..065abe0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -74,6 +74,7 @@ "xtr1common": "cpp", "xtree": "cpp", "xutility": "cpp", - "*.rh": "cpp" + "*.rh": "cpp", + "csignal": "cpp" } } \ No newline at end of file diff --git a/depend/discord/achievement_manager.cpp b/depend/discord/achievement_manager.cpp new file mode 100644 index 0000000..7e3bc43 --- /dev/null +++ b/depend/discord/achievement_manager.cpp @@ -0,0 +1,98 @@ +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "achievement_manager.h" + +#include "core.h" + +#include +#include + +namespace discord { + +class AchievementEvents final { +public: + static void OnUserAchievementUpdate(void* callbackData, DiscordUserAchievement* userAchievement) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->AchievementManager(); + module.OnUserAchievementUpdate(*reinterpret_cast(userAchievement)); + } +}; + +IDiscordAchievementEvents AchievementManager::events_{ + &AchievementEvents::OnUserAchievementUpdate, +}; + +void AchievementManager::SetUserAchievement(Snowflake achievementId, + std::uint8_t percentComplete, + std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->set_user_achievement( + internal_, achievementId, percentComplete, cb.release(), wrapper); +} + +void AchievementManager::FetchUserAchievements(std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->fetch_user_achievements(internal_, cb.release(), wrapper); +} + +void AchievementManager::CountUserAchievements(std::int32_t* count) +{ + if (!count) { + return; + } + + internal_->count_user_achievements(internal_, reinterpret_cast(count)); +} + +Result AchievementManager::GetUserAchievement(Snowflake userAchievementId, + UserAchievement* userAchievement) +{ + if (!userAchievement) { + return Result::InternalError; + } + + auto result = internal_->get_user_achievement( + internal_, userAchievementId, reinterpret_cast(userAchievement)); + return static_cast(result); +} + +Result AchievementManager::GetUserAchievementAt(std::int32_t index, + UserAchievement* userAchievement) +{ + if (!userAchievement) { + return Result::InternalError; + } + + auto result = internal_->get_user_achievement_at( + internal_, index, reinterpret_cast(userAchievement)); + return static_cast(result); +} + +} // namespace discord diff --git a/depend/discord/achievement_manager.h b/depend/discord/achievement_manager.h new file mode 100644 index 0000000..1f58c8e --- /dev/null +++ b/depend/discord/achievement_manager.h @@ -0,0 +1,34 @@ +#pragma once + +#include "types.h" + +namespace discord { + +class AchievementManager final { +public: + ~AchievementManager() = default; + + void SetUserAchievement(Snowflake achievementId, + std::uint8_t percentComplete, + std::function callback); + void FetchUserAchievements(std::function callback); + void CountUserAchievements(std::int32_t* count); + Result GetUserAchievement(Snowflake userAchievementId, UserAchievement* userAchievement); + Result GetUserAchievementAt(std::int32_t index, UserAchievement* userAchievement); + + Event OnUserAchievementUpdate; + +private: + friend class Core; + + AchievementManager() = default; + AchievementManager(AchievementManager const& rhs) = delete; + AchievementManager& operator=(AchievementManager const& rhs) = delete; + AchievementManager(AchievementManager&& rhs) = delete; + AchievementManager& operator=(AchievementManager&& rhs) = delete; + + IDiscordAchievementManager* internal_; + static IDiscordAchievementEvents events_; +}; + +} // namespace discord diff --git a/depend/discord/activity_manager.cpp b/depend/discord/activity_manager.cpp new file mode 100644 index 0000000..b9b6760 --- /dev/null +++ b/depend/discord/activity_manager.cpp @@ -0,0 +1,177 @@ +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "activity_manager.h" + +#include "core.h" + +#include +#include + +namespace discord { + +class ActivityEvents final { +public: + static void OnActivityJoin(void* callbackData, char const* secret) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->ActivityManager(); + module.OnActivityJoin(static_cast(secret)); + } + + static void OnActivitySpectate(void* callbackData, char const* secret) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->ActivityManager(); + module.OnActivitySpectate(static_cast(secret)); + } + + static void OnActivityJoinRequest(void* callbackData, DiscordUser* user) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->ActivityManager(); + module.OnActivityJoinRequest(*reinterpret_cast(user)); + } + + static void OnActivityInvite(void* callbackData, + EDiscordActivityActionType type, + DiscordUser* user, + DiscordActivity* activity) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->ActivityManager(); + module.OnActivityInvite(static_cast(type), + *reinterpret_cast(user), + *reinterpret_cast(activity)); + } +}; + +IDiscordActivityEvents ActivityManager::events_{ + &ActivityEvents::OnActivityJoin, + &ActivityEvents::OnActivitySpectate, + &ActivityEvents::OnActivityJoinRequest, + &ActivityEvents::OnActivityInvite, +}; + +Result ActivityManager::RegisterCommand(char const* command) +{ + auto result = internal_->register_command(internal_, const_cast(command)); + return static_cast(result); +} + +Result ActivityManager::RegisterSteam(std::uint32_t steamId) +{ + auto result = internal_->register_steam(internal_, steamId); + return static_cast(result); +} + +void ActivityManager::UpdateActivity(Activity const& activity, std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->update_activity(internal_, + reinterpret_cast(const_cast(&activity)), + cb.release(), + wrapper); +} + +void ActivityManager::ClearActivity(std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->clear_activity(internal_, cb.release(), wrapper); +} + +void ActivityManager::SendRequestReply(UserId userId, + ActivityJoinRequestReply reply, + std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->send_request_reply(internal_, + userId, + static_cast(reply), + cb.release(), + wrapper); +} + +void ActivityManager::SendInvite(UserId userId, + ActivityActionType type, + char const* content, + std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->send_invite(internal_, + userId, + static_cast(type), + const_cast(content), + cb.release(), + wrapper); +} + +void ActivityManager::AcceptInvite(UserId userId, std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->accept_invite(internal_, userId, cb.release(), wrapper); +} + +} // namespace discord diff --git a/depend/discord/activity_manager.h b/depend/discord/activity_manager.h new file mode 100644 index 0000000..c107be2 --- /dev/null +++ b/depend/discord/activity_manager.h @@ -0,0 +1,42 @@ +#pragma once + +#include "types.h" + +namespace discord { + +class ActivityManager final { +public: + ~ActivityManager() = default; + + Result RegisterCommand(char const* command); + Result RegisterSteam(std::uint32_t steamId); + void UpdateActivity(Activity const& activity, std::function callback); + void ClearActivity(std::function callback); + void SendRequestReply(UserId userId, + ActivityJoinRequestReply reply, + std::function callback); + void SendInvite(UserId userId, + ActivityActionType type, + char const* content, + std::function callback); + void AcceptInvite(UserId userId, std::function callback); + + Event OnActivityJoin; + Event OnActivitySpectate; + Event OnActivityJoinRequest; + Event OnActivityInvite; + +private: + friend class Core; + + ActivityManager() = default; + ActivityManager(ActivityManager const& rhs) = delete; + ActivityManager& operator=(ActivityManager const& rhs) = delete; + ActivityManager(ActivityManager&& rhs) = delete; + ActivityManager& operator=(ActivityManager&& rhs) = delete; + + IDiscordActivityManager* internal_; + static IDiscordActivityEvents events_; +}; + +} // namespace discord diff --git a/depend/discord/application_manager.cpp b/depend/discord/application_manager.cpp new file mode 100644 index 0000000..0e05f3f --- /dev/null +++ b/depend/discord/application_manager.cpp @@ -0,0 +1,78 @@ +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "application_manager.h" + +#include "core.h" + +#include +#include + +namespace discord { + +void ApplicationManager::ValidateOrExit(std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->validate_or_exit(internal_, cb.release(), wrapper); +} + +void ApplicationManager::GetCurrentLocale(char locale[128]) +{ + if (!locale) { + return; + } + + internal_->get_current_locale(internal_, reinterpret_cast(locale)); +} + +void ApplicationManager::GetCurrentBranch(char branch[4096]) +{ + if (!branch) { + return; + } + + internal_->get_current_branch(internal_, reinterpret_cast(branch)); +} + +void ApplicationManager::GetOAuth2Token(std::function callback) +{ + static auto wrapper = + [](void* callbackData, EDiscordResult result, DiscordOAuth2Token* oauth2Token) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result), *reinterpret_cast(oauth2Token)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->get_oauth2_token(internal_, cb.release(), wrapper); +} + +void ApplicationManager::GetTicket(std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result, char const* data) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result), static_cast(data)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->get_ticket(internal_, cb.release(), wrapper); +} + +} // namespace discord diff --git a/depend/discord/application_manager.h b/depend/discord/application_manager.h new file mode 100644 index 0000000..ab0e856 --- /dev/null +++ b/depend/discord/application_manager.h @@ -0,0 +1,30 @@ +#pragma once + +#include "types.h" + +namespace discord { + +class ApplicationManager final { +public: + ~ApplicationManager() = default; + + void ValidateOrExit(std::function callback); + void GetCurrentLocale(char locale[128]); + void GetCurrentBranch(char branch[4096]); + void GetOAuth2Token(std::function callback); + void GetTicket(std::function callback); + +private: + friend class Core; + + ApplicationManager() = default; + ApplicationManager(ApplicationManager const& rhs) = delete; + ApplicationManager& operator=(ApplicationManager const& rhs) = delete; + ApplicationManager(ApplicationManager&& rhs) = delete; + ApplicationManager& operator=(ApplicationManager&& rhs) = delete; + + IDiscordApplicationManager* internal_; + static IDiscordApplicationEvents events_; +}; + +} // namespace discord diff --git a/depend/discord/core.cpp b/depend/discord/core.cpp new file mode 100644 index 0000000..110c9ef --- /dev/null +++ b/depend/discord/core.cpp @@ -0,0 +1,182 @@ +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "core.h" + +#include +#include + +namespace discord { + +Result Core::Create(ClientId clientId, std::uint64_t flags, Core** instance) +{ + if (!instance) { + return Result::InternalError; + } + + (*instance) = new Core(); + DiscordCreateParams params{}; + DiscordCreateParamsSetDefault(¶ms); + params.client_id = clientId; + params.flags = flags; + params.events = nullptr; + params.event_data = *instance; + params.user_events = &UserManager::events_; + params.activity_events = &ActivityManager::events_; + params.relationship_events = &RelationshipManager::events_; + params.lobby_events = &LobbyManager::events_; + params.network_events = &NetworkManager::events_; + params.overlay_events = &OverlayManager::events_; + params.store_events = &StoreManager::events_; + params.voice_events = &VoiceManager::events_; + params.achievement_events = &AchievementManager::events_; + auto result = DiscordCreate(DISCORD_VERSION, ¶ms, &((*instance)->internal_)); + if (result != DiscordResult_Ok || !(*instance)->internal_) { + delete (*instance); + (*instance) = nullptr; + } + + return static_cast(result); +} + +Core::~Core() +{ + if (internal_) { + internal_->destroy(internal_); + internal_ = nullptr; + } +} + +Result Core::RunCallbacks() +{ + auto result = internal_->run_callbacks(internal_); + return static_cast(result); +} + +void Core::SetLogHook(LogLevel minLevel, std::function hook) +{ + setLogHook_.DisconnectAll(); + setLogHook_.Connect(std::move(hook)); + static auto wrapper = + [](void* callbackData, EDiscordLogLevel level, char const* message) -> void { + auto cb(reinterpret_cast(callbackData)); + if (!cb) { + return; + } + (*cb)(static_cast(level), static_cast(message)); + }; + + internal_->set_log_hook( + internal_, static_cast(minLevel), &setLogHook_, wrapper); +} + +discord::ApplicationManager& Core::ApplicationManager() +{ + if (!applicationManager_.internal_) { + applicationManager_.internal_ = internal_->get_application_manager(internal_); + } + + return applicationManager_; +} + +discord::UserManager& Core::UserManager() +{ + if (!userManager_.internal_) { + userManager_.internal_ = internal_->get_user_manager(internal_); + } + + return userManager_; +} + +discord::ImageManager& Core::ImageManager() +{ + if (!imageManager_.internal_) { + imageManager_.internal_ = internal_->get_image_manager(internal_); + } + + return imageManager_; +} + +discord::ActivityManager& Core::ActivityManager() +{ + if (!activityManager_.internal_) { + activityManager_.internal_ = internal_->get_activity_manager(internal_); + } + + return activityManager_; +} + +discord::RelationshipManager& Core::RelationshipManager() +{ + if (!relationshipManager_.internal_) { + relationshipManager_.internal_ = internal_->get_relationship_manager(internal_); + } + + return relationshipManager_; +} + +discord::LobbyManager& Core::LobbyManager() +{ + if (!lobbyManager_.internal_) { + lobbyManager_.internal_ = internal_->get_lobby_manager(internal_); + } + + return lobbyManager_; +} + +discord::NetworkManager& Core::NetworkManager() +{ + if (!networkManager_.internal_) { + networkManager_.internal_ = internal_->get_network_manager(internal_); + } + + return networkManager_; +} + +discord::OverlayManager& Core::OverlayManager() +{ + if (!overlayManager_.internal_) { + overlayManager_.internal_ = internal_->get_overlay_manager(internal_); + } + + return overlayManager_; +} + +discord::StorageManager& Core::StorageManager() +{ + if (!storageManager_.internal_) { + storageManager_.internal_ = internal_->get_storage_manager(internal_); + } + + return storageManager_; +} + +discord::StoreManager& Core::StoreManager() +{ + if (!storeManager_.internal_) { + storeManager_.internal_ = internal_->get_store_manager(internal_); + } + + return storeManager_; +} + +discord::VoiceManager& Core::VoiceManager() +{ + if (!voiceManager_.internal_) { + voiceManager_.internal_ = internal_->get_voice_manager(internal_); + } + + return voiceManager_; +} + +discord::AchievementManager& Core::AchievementManager() +{ + if (!achievementManager_.internal_) { + achievementManager_.internal_ = internal_->get_achievement_manager(internal_); + } + + return achievementManager_; +} + +} // namespace discord diff --git a/depend/discord/core.h b/depend/discord/core.h new file mode 100644 index 0000000..8af6fca --- /dev/null +++ b/depend/discord/core.h @@ -0,0 +1,64 @@ +#pragma once + +#include "types.h" +#include "application_manager.h" +#include "user_manager.h" +#include "image_manager.h" +#include "activity_manager.h" +#include "relationship_manager.h" +#include "lobby_manager.h" +#include "network_manager.h" +#include "overlay_manager.h" +#include "storage_manager.h" +#include "store_manager.h" +#include "voice_manager.h" +#include "achievement_manager.h" + +namespace discord { + +class Core final { +public: + static Result Create(ClientId clientId, std::uint64_t flags, Core** instance); + + ~Core(); + + Result RunCallbacks(); + void SetLogHook(LogLevel minLevel, std::function hook); + + discord::ApplicationManager& ApplicationManager(); + discord::UserManager& UserManager(); + discord::ImageManager& ImageManager(); + discord::ActivityManager& ActivityManager(); + discord::RelationshipManager& RelationshipManager(); + discord::LobbyManager& LobbyManager(); + discord::NetworkManager& NetworkManager(); + discord::OverlayManager& OverlayManager(); + discord::StorageManager& StorageManager(); + discord::StoreManager& StoreManager(); + discord::VoiceManager& VoiceManager(); + discord::AchievementManager& AchievementManager(); + +private: + Core() = default; + Core(Core const& rhs) = delete; + Core& operator=(Core const& rhs) = delete; + Core(Core&& rhs) = delete; + Core& operator=(Core&& rhs) = delete; + + IDiscordCore* internal_; + Event setLogHook_; + discord::ApplicationManager applicationManager_; + discord::UserManager userManager_; + discord::ImageManager imageManager_; + discord::ActivityManager activityManager_; + discord::RelationshipManager relationshipManager_; + discord::LobbyManager lobbyManager_; + discord::NetworkManager networkManager_; + discord::OverlayManager overlayManager_; + discord::StorageManager storageManager_; + discord::StoreManager storeManager_; + discord::VoiceManager voiceManager_; + discord::AchievementManager achievementManager_; +}; + +} // namespace discord diff --git a/depend/discord/discord.h b/depend/discord/discord.h new file mode 100644 index 0000000..c991212 --- /dev/null +++ b/depend/discord/discord.h @@ -0,0 +1,16 @@ +#pragma once + +#include "types.h" +#include "core.h" +#include "application_manager.h" +#include "user_manager.h" +#include "image_manager.h" +#include "activity_manager.h" +#include "relationship_manager.h" +#include "lobby_manager.h" +#include "network_manager.h" +#include "overlay_manager.h" +#include "storage_manager.h" +#include "store_manager.h" +#include "voice_manager.h" +#include "achievement_manager.h" diff --git a/depend/discord/event.h b/depend/discord/event.h new file mode 100644 index 0000000..610887d --- /dev/null +++ b/depend/discord/event.h @@ -0,0 +1,59 @@ +#pragma once + +#include +#include + +namespace discord { + +template +class Event final { +public: + using Token = int; + + Event() { slots_.reserve(4); } + + Event(Event const&) = default; + Event(Event&&) = default; + ~Event() = default; + + Event& operator=(Event const&) = default; + Event& operator=(Event&&) = default; + + template + Token Connect(EventHandler slot) + { + slots_.emplace_back(Slot{nextToken_, std::move(slot)}); + return nextToken_++; + } + + void Disconnect(Token token) + { + for (auto& slot : slots_) { + if (slot.token == token) { + slot = slots_.back(); + slots_.pop_back(); + break; + } + } + } + + void DisconnectAll() { slots_ = {}; } + + void operator()(Args... args) + { + for (auto const& slot : slots_) { + slot.fn(std::forward(args)...); + } + } + +private: + struct Slot { + Token token; + std::function fn; + }; + + Token nextToken_{}; + std::vector slots_{}; +}; + +} // namespace discord diff --git a/depend/discord/ffi.h b/depend/discord/ffi.h new file mode 100644 index 0000000..765fde7 --- /dev/null +++ b/depend/discord/ffi.h @@ -0,0 +1,942 @@ +#ifndef _DISCORD_GAME_SDK_H_ +#define _DISCORD_GAME_SDK_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#ifndef __cplusplus +#include +#endif + +#define DISCORD_VERSION 2 +#define DISCORD_APPLICATION_MANAGER_VERSION 1 +#define DISCORD_USER_MANAGER_VERSION 1 +#define DISCORD_IMAGE_MANAGER_VERSION 1 +#define DISCORD_ACTIVITY_MANAGER_VERSION 1 +#define DISCORD_RELATIONSHIP_MANAGER_VERSION 1 +#define DISCORD_LOBBY_MANAGER_VERSION 1 +#define DISCORD_NETWORK_MANAGER_VERSION 1 +#define DISCORD_OVERLAY_MANAGER_VERSION 1 +#define DISCORD_STORAGE_MANAGER_VERSION 1 +#define DISCORD_STORE_MANAGER_VERSION 1 +#define DISCORD_VOICE_MANAGER_VERSION 1 +#define DISCORD_ACHIEVEMENT_MANAGER_VERSION 1 + +enum EDiscordResult { + DiscordResult_Ok = 0, + DiscordResult_ServiceUnavailable = 1, + DiscordResult_InvalidVersion = 2, + DiscordResult_LockFailed = 3, + DiscordResult_InternalError = 4, + DiscordResult_InvalidPayload = 5, + DiscordResult_InvalidCommand = 6, + DiscordResult_InvalidPermissions = 7, + DiscordResult_NotFetched = 8, + DiscordResult_NotFound = 9, + DiscordResult_Conflict = 10, + DiscordResult_InvalidSecret = 11, + DiscordResult_InvalidJoinSecret = 12, + DiscordResult_NoEligibleActivity = 13, + DiscordResult_InvalidInvite = 14, + DiscordResult_NotAuthenticated = 15, + DiscordResult_InvalidAccessToken = 16, + DiscordResult_ApplicationMismatch = 17, + DiscordResult_InvalidDataUrl = 18, + DiscordResult_InvalidBase64 = 19, + DiscordResult_NotFiltered = 20, + DiscordResult_LobbyFull = 21, + DiscordResult_InvalidLobbySecret = 22, + DiscordResult_InvalidFilename = 23, + DiscordResult_InvalidFileSize = 24, + DiscordResult_InvalidEntitlement = 25, + DiscordResult_NotInstalled = 26, + DiscordResult_NotRunning = 27, + DiscordResult_InsufficientBuffer = 28, + DiscordResult_PurchaseCanceled = 29, + DiscordResult_InvalidGuild = 30, + DiscordResult_InvalidEvent = 31, + DiscordResult_InvalidChannel = 32, + DiscordResult_InvalidOrigin = 33, + DiscordResult_RateLimited = 34, + DiscordResult_OAuth2Error = 35, + DiscordResult_SelectChannelTimeout = 36, + DiscordResult_GetGuildTimeout = 37, + DiscordResult_SelectVoiceForceRequired = 38, + DiscordResult_CaptureShortcutAlreadyListening = 39, + DiscordResult_UnauthorizedForAchievement = 40, + DiscordResult_InvalidGiftCode = 41, + DiscordResult_PurchaseError = 42, + DiscordResult_TransactionAborted = 43, +}; + +enum EDiscordCreateFlags { + DiscordCreateFlags_Default = 0, + DiscordCreateFlags_NoRequireDiscord = 1, +}; + +enum EDiscordLogLevel { + DiscordLogLevel_Error = 1, + DiscordLogLevel_Warn, + DiscordLogLevel_Info, + DiscordLogLevel_Debug, +}; + +enum EDiscordUserFlag { + DiscordUserFlag_Partner = 2, + DiscordUserFlag_HypeSquadEvents = 4, + DiscordUserFlag_HypeSquadHouse1 = 64, + DiscordUserFlag_HypeSquadHouse2 = 128, + DiscordUserFlag_HypeSquadHouse3 = 256, +}; + +enum EDiscordPremiumType { + DiscordPremiumType_None = 0, + DiscordPremiumType_Tier1 = 1, + DiscordPremiumType_Tier2 = 2, +}; + +enum EDiscordImageType { + DiscordImageType_User, +}; + +enum EDiscordActivityType { + DiscordActivityType_Playing, + DiscordActivityType_Streaming, + DiscordActivityType_Listening, + DiscordActivityType_Watching, +}; + +enum EDiscordActivityActionType { + DiscordActivityActionType_Join = 1, + DiscordActivityActionType_Spectate, +}; + +enum EDiscordActivityJoinRequestReply { + DiscordActivityJoinRequestReply_No, + DiscordActivityJoinRequestReply_Yes, + DiscordActivityJoinRequestReply_Ignore, +}; + +enum EDiscordStatus { + DiscordStatus_Offline = 0, + DiscordStatus_Online = 1, + DiscordStatus_Idle = 2, + DiscordStatus_DoNotDisturb = 3, +}; + +enum EDiscordRelationshipType { + DiscordRelationshipType_None, + DiscordRelationshipType_Friend, + DiscordRelationshipType_Blocked, + DiscordRelationshipType_PendingIncoming, + DiscordRelationshipType_PendingOutgoing, + DiscordRelationshipType_Implicit, +}; + +enum EDiscordLobbyType { + DiscordLobbyType_Private = 1, + DiscordLobbyType_Public, +}; + +enum EDiscordLobbySearchComparison { + DiscordLobbySearchComparison_LessThanOrEqual = -2, + DiscordLobbySearchComparison_LessThan, + DiscordLobbySearchComparison_Equal, + DiscordLobbySearchComparison_GreaterThan, + DiscordLobbySearchComparison_GreaterThanOrEqual, + DiscordLobbySearchComparison_NotEqual, +}; + +enum EDiscordLobbySearchCast { + DiscordLobbySearchCast_String = 1, + DiscordLobbySearchCast_Number, +}; + +enum EDiscordLobbySearchDistance { + DiscordLobbySearchDistance_Local, + DiscordLobbySearchDistance_Default, + DiscordLobbySearchDistance_Extended, + DiscordLobbySearchDistance_Global, +}; + +enum EDiscordEntitlementType { + DiscordEntitlementType_Purchase = 1, + DiscordEntitlementType_PremiumSubscription, + DiscordEntitlementType_DeveloperGift, + DiscordEntitlementType_TestModePurchase, + DiscordEntitlementType_FreePurchase, + DiscordEntitlementType_UserGift, + DiscordEntitlementType_PremiumPurchase, +}; + +enum EDiscordSkuType { + DiscordSkuType_Application = 1, + DiscordSkuType_DLC, + DiscordSkuType_Consumable, + DiscordSkuType_Bundle, +}; + +enum EDiscordInputModeType { + DiscordInputModeType_VoiceActivity = 0, + DiscordInputModeType_PushToTalk, +}; + +typedef int64_t DiscordClientId; +typedef int32_t DiscordVersion; +typedef int64_t DiscordSnowflake; +typedef int64_t DiscordTimestamp; +typedef DiscordSnowflake DiscordUserId; +typedef char DiscordLocale[128]; +typedef char DiscordBranch[4096]; +typedef DiscordSnowflake DiscordLobbyId; +typedef char DiscordLobbySecret[128]; +typedef char DiscordMetadataKey[256]; +typedef char DiscordMetadataValue[4096]; +typedef uint64_t DiscordNetworkPeerId; +typedef uint8_t DiscordNetworkChannelId; +typedef char DiscordPath[4096]; +typedef char DiscordDateTime[64]; + +struct DiscordUser { + DiscordUserId id; + char username[256]; + char discriminator[8]; + char avatar[128]; + bool bot; +}; + +struct DiscordOAuth2Token { + char access_token[128]; + char scopes[1024]; + DiscordTimestamp expires; +}; + +struct DiscordImageHandle { + enum EDiscordImageType type; + int64_t id; + uint32_t size; +}; + +struct DiscordImageDimensions { + uint32_t width; + uint32_t height; +}; + +struct DiscordActivityTimestamps { + DiscordTimestamp start; + DiscordTimestamp end; +}; + +struct DiscordActivityAssets { + char large_image[128]; + char large_text[128]; + char small_image[128]; + char small_text[128]; +}; + +struct DiscordPartySize { + int32_t current_size; + int32_t max_size; +}; + +struct DiscordActivityParty { + char id[128]; + struct DiscordPartySize size; +}; + +struct DiscordActivitySecrets { + char match[128]; + char join[128]; + char spectate[128]; +}; + +struct DiscordActivity { + enum EDiscordActivityType type; + int64_t application_id; + char name[128]; + char state[128]; + char details[128]; + struct DiscordActivityTimestamps timestamps; + struct DiscordActivityAssets assets; + struct DiscordActivityParty party; + struct DiscordActivitySecrets secrets; + bool instance; +}; + +struct DiscordPresence { + enum EDiscordStatus status; + struct DiscordActivity activity; +}; + +struct DiscordRelationship { + enum EDiscordRelationshipType type; + struct DiscordUser user; + struct DiscordPresence presence; +}; + +struct DiscordLobby { + DiscordLobbyId id; + enum EDiscordLobbyType type; + DiscordUserId owner_id; + DiscordLobbySecret secret; + uint32_t capacity; + bool locked; +}; + +struct DiscordFileStat { + char filename[260]; + uint64_t size; + uint64_t last_modified; +}; + +struct DiscordEntitlement { + DiscordSnowflake id; + enum EDiscordEntitlementType type; + DiscordSnowflake sku_id; +}; + +struct DiscordSkuPrice { + uint32_t amount; + char currency[16]; +}; + +struct DiscordSku { + DiscordSnowflake id; + enum EDiscordSkuType type; + char name[256]; + struct DiscordSkuPrice price; +}; + +struct DiscordInputMode { + enum EDiscordInputModeType type; + char shortcut[256]; +}; + +struct DiscordUserAchievement { + DiscordSnowflake user_id; + DiscordSnowflake achievement_id; + uint8_t percent_complete; + DiscordDateTime unlocked_at; +}; + +struct IDiscordLobbyTransaction { + enum EDiscordResult (*set_type)(struct IDiscordLobbyTransaction* lobby_transaction, + enum EDiscordLobbyType type); + enum EDiscordResult (*set_owner)(struct IDiscordLobbyTransaction* lobby_transaction, + DiscordUserId owner_id); + enum EDiscordResult (*set_capacity)(struct IDiscordLobbyTransaction* lobby_transaction, + uint32_t capacity); + enum EDiscordResult (*set_metadata)(struct IDiscordLobbyTransaction* lobby_transaction, + DiscordMetadataKey key, + DiscordMetadataValue value); + enum EDiscordResult (*delete_metadata)(struct IDiscordLobbyTransaction* lobby_transaction, + DiscordMetadataKey key); + enum EDiscordResult (*set_locked)(struct IDiscordLobbyTransaction* lobby_transaction, + bool locked); +}; + +struct IDiscordLobbyMemberTransaction { + enum EDiscordResult (*set_metadata)( + struct IDiscordLobbyMemberTransaction* lobby_member_transaction, + DiscordMetadataKey key, + DiscordMetadataValue value); + enum EDiscordResult (*delete_metadata)( + struct IDiscordLobbyMemberTransaction* lobby_member_transaction, + DiscordMetadataKey key); +}; + +struct IDiscordLobbySearchQuery { + enum EDiscordResult (*filter)(struct IDiscordLobbySearchQuery* lobby_search_query, + DiscordMetadataKey key, + enum EDiscordLobbySearchComparison comparison, + enum EDiscordLobbySearchCast cast, + DiscordMetadataValue value); + enum EDiscordResult (*sort)(struct IDiscordLobbySearchQuery* lobby_search_query, + DiscordMetadataKey key, + enum EDiscordLobbySearchCast cast, + DiscordMetadataValue value); + enum EDiscordResult (*limit)(struct IDiscordLobbySearchQuery* lobby_search_query, + uint32_t limit); + enum EDiscordResult (*distance)(struct IDiscordLobbySearchQuery* lobby_search_query, + enum EDiscordLobbySearchDistance distance); +}; + +typedef void* IDiscordApplicationEvents; + +struct IDiscordApplicationManager { + void (*validate_or_exit)(struct IDiscordApplicationManager* manager, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*get_current_locale)(struct IDiscordApplicationManager* manager, DiscordLocale* locale); + void (*get_current_branch)(struct IDiscordApplicationManager* manager, DiscordBranch* branch); + void (*get_oauth2_token)(struct IDiscordApplicationManager* manager, + void* callback_data, + void (*callback)(void* callback_data, + enum EDiscordResult result, + struct DiscordOAuth2Token* oauth2_token)); + void (*get_ticket)(struct IDiscordApplicationManager* manager, + void* callback_data, + void (*callback)(void* callback_data, + enum EDiscordResult result, + const char* data)); +}; + +struct IDiscordUserEvents { + void (*on_current_user_update)(void* event_data); +}; + +struct IDiscordUserManager { + enum EDiscordResult (*get_current_user)(struct IDiscordUserManager* manager, + struct DiscordUser* current_user); + void (*get_user)(struct IDiscordUserManager* manager, + DiscordUserId user_id, + void* callback_data, + void (*callback)(void* callback_data, + enum EDiscordResult result, + struct DiscordUser* user)); + enum EDiscordResult (*get_current_user_premium_type)(struct IDiscordUserManager* manager, + enum EDiscordPremiumType* premium_type); + enum EDiscordResult (*current_user_has_flag)(struct IDiscordUserManager* manager, + enum EDiscordUserFlag flag, + bool* has_flag); +}; + +typedef void* IDiscordImageEvents; + +struct IDiscordImageManager { + void (*fetch)(struct IDiscordImageManager* manager, + struct DiscordImageHandle handle, + bool refresh, + void* callback_data, + void (*callback)(void* callback_data, + enum EDiscordResult result, + struct DiscordImageHandle handle_result)); + enum EDiscordResult (*get_dimensions)(struct IDiscordImageManager* manager, + struct DiscordImageHandle handle, + struct DiscordImageDimensions* dimensions); + enum EDiscordResult (*get_data)(struct IDiscordImageManager* manager, + struct DiscordImageHandle handle, + uint8_t* data, + uint32_t data_length); +}; + +struct IDiscordActivityEvents { + void (*on_activity_join)(void* event_data, const char* secret); + void (*on_activity_spectate)(void* event_data, const char* secret); + void (*on_activity_join_request)(void* event_data, struct DiscordUser* user); + void (*on_activity_invite)(void* event_data, + enum EDiscordActivityActionType type, + struct DiscordUser* user, + struct DiscordActivity* activity); +}; + +struct IDiscordActivityManager { + enum EDiscordResult (*register_command)(struct IDiscordActivityManager* manager, + const char* command); + enum EDiscordResult (*register_steam)(struct IDiscordActivityManager* manager, + uint32_t steam_id); + void (*update_activity)(struct IDiscordActivityManager* manager, + struct DiscordActivity* activity, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*clear_activity)(struct IDiscordActivityManager* manager, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*send_request_reply)(struct IDiscordActivityManager* manager, + DiscordUserId user_id, + enum EDiscordActivityJoinRequestReply reply, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*send_invite)(struct IDiscordActivityManager* manager, + DiscordUserId user_id, + enum EDiscordActivityActionType type, + const char* content, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*accept_invite)(struct IDiscordActivityManager* manager, + DiscordUserId user_id, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); +}; + +struct IDiscordRelationshipEvents { + void (*on_refresh)(void* event_data); + void (*on_relationship_update)(void* event_data, struct DiscordRelationship* relationship); +}; + +struct IDiscordRelationshipManager { + void (*filter)(struct IDiscordRelationshipManager* manager, + void* filter_data, + bool (*filter)(void* filter_data, struct DiscordRelationship* relationship)); + enum EDiscordResult (*count)(struct IDiscordRelationshipManager* manager, int32_t* count); + enum EDiscordResult (*get)(struct IDiscordRelationshipManager* manager, + DiscordUserId user_id, + struct DiscordRelationship* relationship); + enum EDiscordResult (*get_at)(struct IDiscordRelationshipManager* manager, + uint32_t index, + struct DiscordRelationship* relationship); +}; + +struct IDiscordLobbyEvents { + void (*on_lobby_update)(void* event_data, int64_t lobby_id); + void (*on_lobby_delete)(void* event_data, int64_t lobby_id, uint32_t reason); + void (*on_member_connect)(void* event_data, int64_t lobby_id, int64_t user_id); + void (*on_member_update)(void* event_data, int64_t lobby_id, int64_t user_id); + void (*on_member_disconnect)(void* event_data, int64_t lobby_id, int64_t user_id); + void (*on_lobby_message)(void* event_data, + int64_t lobby_id, + int64_t user_id, + uint8_t* data, + uint32_t data_length); + void (*on_speaking)(void* event_data, int64_t lobby_id, int64_t user_id, bool speaking); + void (*on_network_message)(void* event_data, + int64_t lobby_id, + int64_t user_id, + uint8_t channel_id, + uint8_t* data, + uint32_t data_length); +}; + +struct IDiscordLobbyManager { + enum EDiscordResult (*get_lobby_create_transaction)( + struct IDiscordLobbyManager* manager, + struct IDiscordLobbyTransaction** transaction); + enum EDiscordResult (*get_lobby_update_transaction)( + struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + struct IDiscordLobbyTransaction** transaction); + enum EDiscordResult (*get_member_update_transaction)( + struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordUserId user_id, + struct IDiscordLobbyMemberTransaction** transaction); + void (*create_lobby)(struct IDiscordLobbyManager* manager, + struct IDiscordLobbyTransaction* transaction, + void* callback_data, + void (*callback)(void* callback_data, + enum EDiscordResult result, + struct DiscordLobby* lobby)); + void (*update_lobby)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + struct IDiscordLobbyTransaction* transaction, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*delete_lobby)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*connect_lobby)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordLobbySecret secret, + void* callback_data, + void (*callback)(void* callback_data, + enum EDiscordResult result, + struct DiscordLobby* lobby)); + void (*connect_lobby_with_activity_secret)(struct IDiscordLobbyManager* manager, + DiscordLobbySecret activity_secret, + void* callback_data, + void (*callback)(void* callback_data, + enum EDiscordResult result, + struct DiscordLobby* lobby)); + void (*disconnect_lobby)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (*get_lobby)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + struct DiscordLobby* lobby); + enum EDiscordResult (*get_lobby_activity_secret)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordLobbySecret* secret); + enum EDiscordResult (*get_lobby_metadata_value)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordMetadataKey key, + DiscordMetadataValue* value); + enum EDiscordResult (*get_lobby_metadata_key)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + int32_t index, + DiscordMetadataKey* key); + enum EDiscordResult (*lobby_metadata_count)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + int32_t* count); + enum EDiscordResult (*member_count)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + int32_t* count); + enum EDiscordResult (*get_member_user_id)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + int32_t index, + DiscordUserId* user_id); + enum EDiscordResult (*get_member_user)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordUserId user_id, + struct DiscordUser* user); + enum EDiscordResult (*get_member_metadata_value)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordUserId user_id, + DiscordMetadataKey key, + DiscordMetadataValue* value); + enum EDiscordResult (*get_member_metadata_key)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordUserId user_id, + int32_t index, + DiscordMetadataKey* key); + enum EDiscordResult (*member_metadata_count)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordUserId user_id, + int32_t* count); + void (*update_member)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordUserId user_id, + struct IDiscordLobbyMemberTransaction* transaction, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*send_lobby_message)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + uint8_t* data, + uint32_t data_length, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (*get_search_query)(struct IDiscordLobbyManager* manager, + struct IDiscordLobbySearchQuery** query); + void (*search)(struct IDiscordLobbyManager* manager, + struct IDiscordLobbySearchQuery* query, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*lobby_count)(struct IDiscordLobbyManager* manager, int32_t* count); + enum EDiscordResult (*get_lobby_id)(struct IDiscordLobbyManager* manager, + int32_t index, + DiscordLobbyId* lobby_id); + void (*connect_voice)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*disconnect_voice)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (*connect_network)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id); + enum EDiscordResult (*disconnect_network)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id); + enum EDiscordResult (*flush_network)(struct IDiscordLobbyManager* manager); + enum EDiscordResult (*open_network_channel)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + uint8_t channel_id, + bool reliable); + enum EDiscordResult (*send_network_message)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordUserId user_id, + uint8_t channel_id, + uint8_t* data, + uint32_t data_length); +}; + +struct IDiscordNetworkEvents { + void (*on_message)(void* event_data, + DiscordNetworkPeerId peer_id, + DiscordNetworkChannelId channel_id, + uint8_t* data, + uint32_t data_length); + void (*on_route_update)(void* event_data, const char* route_data); +}; + +struct IDiscordNetworkManager { + /** + * Get the local peer ID for this process. + */ + void (*get_peer_id)(struct IDiscordNetworkManager* manager, DiscordNetworkPeerId* peer_id); + /** + * Send pending network messages. + */ + enum EDiscordResult (*flush)(struct IDiscordNetworkManager* manager); + /** + * Open a connection to a remote peer. + */ + enum EDiscordResult (*open_peer)(struct IDiscordNetworkManager* manager, + DiscordNetworkPeerId peer_id, + const char* route_data); + /** + * Update the route data for a connected peer. + */ + enum EDiscordResult (*update_peer)(struct IDiscordNetworkManager* manager, + DiscordNetworkPeerId peer_id, + const char* route_data); + /** + * Close the connection to a remote peer. + */ + enum EDiscordResult (*close_peer)(struct IDiscordNetworkManager* manager, + DiscordNetworkPeerId peer_id); + /** + * Open a message channel to a connected peer. + */ + enum EDiscordResult (*open_channel)(struct IDiscordNetworkManager* manager, + DiscordNetworkPeerId peer_id, + DiscordNetworkChannelId channel_id, + bool reliable); + /** + * Close a message channel to a connected peer. + */ + enum EDiscordResult (*close_channel)(struct IDiscordNetworkManager* manager, + DiscordNetworkPeerId peer_id, + DiscordNetworkChannelId channel_id); + /** + * Send a message to a connected peer over an opened message channel. + */ + enum EDiscordResult (*send_message)(struct IDiscordNetworkManager* manager, + DiscordNetworkPeerId peer_id, + DiscordNetworkChannelId channel_id, + uint8_t* data, + uint32_t data_length); +}; + +struct IDiscordOverlayEvents { + void (*on_toggle)(void* event_data, bool locked); +}; + +struct IDiscordOverlayManager { + void (*is_enabled)(struct IDiscordOverlayManager* manager, bool* enabled); + void (*is_locked)(struct IDiscordOverlayManager* manager, bool* locked); + void (*set_locked)(struct IDiscordOverlayManager* manager, + bool locked, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*open_activity_invite)(struct IDiscordOverlayManager* manager, + enum EDiscordActivityActionType type, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*open_guild_invite)(struct IDiscordOverlayManager* manager, + const char* code, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*open_voice_settings)(struct IDiscordOverlayManager* manager, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); +}; + +typedef void* IDiscordStorageEvents; + +struct IDiscordStorageManager { + enum EDiscordResult (*read)(struct IDiscordStorageManager* manager, + const char* name, + uint8_t* data, + uint32_t data_length, + uint32_t* read); + void (*read_async)(struct IDiscordStorageManager* manager, + const char* name, + void* callback_data, + void (*callback)(void* callback_data, + enum EDiscordResult result, + uint8_t* data, + uint32_t data_length)); + void (*read_async_partial)(struct IDiscordStorageManager* manager, + const char* name, + uint64_t offset, + uint64_t length, + void* callback_data, + void (*callback)(void* callback_data, + enum EDiscordResult result, + uint8_t* data, + uint32_t data_length)); + enum EDiscordResult (*write)(struct IDiscordStorageManager* manager, + const char* name, + uint8_t* data, + uint32_t data_length); + void (*write_async)(struct IDiscordStorageManager* manager, + const char* name, + uint8_t* data, + uint32_t data_length, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (*delete_)(struct IDiscordStorageManager* manager, const char* name); + enum EDiscordResult (*exists)(struct IDiscordStorageManager* manager, + const char* name, + bool* exists); + void (*count)(struct IDiscordStorageManager* manager, int32_t* count); + enum EDiscordResult (*stat)(struct IDiscordStorageManager* manager, + const char* name, + struct DiscordFileStat* stat); + enum EDiscordResult (*stat_at)(struct IDiscordStorageManager* manager, + int32_t index, + struct DiscordFileStat* stat); + enum EDiscordResult (*get_path)(struct IDiscordStorageManager* manager, DiscordPath* path); +}; + +struct IDiscordStoreEvents { + void (*on_entitlement_create)(void* event_data, struct DiscordEntitlement* entitlement); + void (*on_entitlement_delete)(void* event_data, struct DiscordEntitlement* entitlement); +}; + +struct IDiscordStoreManager { + void (*fetch_skus)(struct IDiscordStoreManager* manager, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*count_skus)(struct IDiscordStoreManager* manager, int32_t* count); + enum EDiscordResult (*get_sku)(struct IDiscordStoreManager* manager, + DiscordSnowflake sku_id, + struct DiscordSku* sku); + enum EDiscordResult (*get_sku_at)(struct IDiscordStoreManager* manager, + int32_t index, + struct DiscordSku* sku); + void (*fetch_entitlements)(struct IDiscordStoreManager* manager, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*count_entitlements)(struct IDiscordStoreManager* manager, int32_t* count); + enum EDiscordResult (*get_entitlement)(struct IDiscordStoreManager* manager, + DiscordSnowflake entitlement_id, + struct DiscordEntitlement* entitlement); + enum EDiscordResult (*get_entitlement_at)(struct IDiscordStoreManager* manager, + int32_t index, + struct DiscordEntitlement* entitlement); + enum EDiscordResult (*has_sku_entitlement)(struct IDiscordStoreManager* manager, + DiscordSnowflake sku_id, + bool* has_entitlement); + void (*start_purchase)(struct IDiscordStoreManager* manager, + DiscordSnowflake sku_id, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); +}; + +struct IDiscordVoiceEvents { + void (*on_settings_update)(void* event_data); +}; + +struct IDiscordVoiceManager { + enum EDiscordResult (*get_input_mode)(struct IDiscordVoiceManager* manager, + struct DiscordInputMode* input_mode); + void (*set_input_mode)(struct IDiscordVoiceManager* manager, + struct DiscordInputMode input_mode, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + enum EDiscordResult (*is_self_mute)(struct IDiscordVoiceManager* manager, bool* mute); + enum EDiscordResult (*set_self_mute)(struct IDiscordVoiceManager* manager, bool mute); + enum EDiscordResult (*is_self_deaf)(struct IDiscordVoiceManager* manager, bool* deaf); + enum EDiscordResult (*set_self_deaf)(struct IDiscordVoiceManager* manager, bool deaf); + enum EDiscordResult (*is_local_mute)(struct IDiscordVoiceManager* manager, + DiscordSnowflake user_id, + bool* mute); + enum EDiscordResult (*set_local_mute)(struct IDiscordVoiceManager* manager, + DiscordSnowflake user_id, + bool mute); + enum EDiscordResult (*get_local_volume)(struct IDiscordVoiceManager* manager, + DiscordSnowflake user_id, + uint8_t* volume); + enum EDiscordResult (*set_local_volume)(struct IDiscordVoiceManager* manager, + DiscordSnowflake user_id, + uint8_t volume); +}; + +struct IDiscordAchievementEvents { + void (*on_user_achievement_update)(void* event_data, + struct DiscordUserAchievement* user_achievement); +}; + +struct IDiscordAchievementManager { + void (*set_user_achievement)(struct IDiscordAchievementManager* manager, + DiscordSnowflake achievement_id, + uint8_t percent_complete, + void* callback_data, + void (*callback)(void* callback_data, enum EDiscordResult result)); + void (*fetch_user_achievements)(struct IDiscordAchievementManager* manager, + void* callback_data, + void (*callback)(void* callback_data, + enum EDiscordResult result)); + void (*count_user_achievements)(struct IDiscordAchievementManager* manager, int32_t* count); + enum EDiscordResult (*get_user_achievement)(struct IDiscordAchievementManager* manager, + DiscordSnowflake user_achievement_id, + struct DiscordUserAchievement* user_achievement); + enum EDiscordResult (*get_user_achievement_at)(struct IDiscordAchievementManager* manager, + int32_t index, + struct DiscordUserAchievement* user_achievement); +}; + +typedef void* IDiscordCoreEvents; + +struct IDiscordCore { + void (*destroy)(struct IDiscordCore* core); + enum EDiscordResult (*run_callbacks)(struct IDiscordCore* core); + void (*set_log_hook)(struct IDiscordCore* core, + enum EDiscordLogLevel min_level, + void* hook_data, + void (*hook)(void* hook_data, + enum EDiscordLogLevel level, + const char* message)); + struct IDiscordApplicationManager* (*get_application_manager)(struct IDiscordCore* core); + struct IDiscordUserManager* (*get_user_manager)(struct IDiscordCore* core); + struct IDiscordImageManager* (*get_image_manager)(struct IDiscordCore* core); + struct IDiscordActivityManager* (*get_activity_manager)(struct IDiscordCore* core); + struct IDiscordRelationshipManager* (*get_relationship_manager)(struct IDiscordCore* core); + struct IDiscordLobbyManager* (*get_lobby_manager)(struct IDiscordCore* core); + struct IDiscordNetworkManager* (*get_network_manager)(struct IDiscordCore* core); + struct IDiscordOverlayManager* (*get_overlay_manager)(struct IDiscordCore* core); + struct IDiscordStorageManager* (*get_storage_manager)(struct IDiscordCore* core); + struct IDiscordStoreManager* (*get_store_manager)(struct IDiscordCore* core); + struct IDiscordVoiceManager* (*get_voice_manager)(struct IDiscordCore* core); + struct IDiscordAchievementManager* (*get_achievement_manager)(struct IDiscordCore* core); +}; + +struct DiscordCreateParams { + DiscordClientId client_id; + uint64_t flags; + IDiscordCoreEvents* events; + void* event_data; + IDiscordApplicationEvents* application_events; + DiscordVersion application_version; + struct IDiscordUserEvents* user_events; + DiscordVersion user_version; + IDiscordImageEvents* image_events; + DiscordVersion image_version; + struct IDiscordActivityEvents* activity_events; + DiscordVersion activity_version; + struct IDiscordRelationshipEvents* relationship_events; + DiscordVersion relationship_version; + struct IDiscordLobbyEvents* lobby_events; + DiscordVersion lobby_version; + struct IDiscordNetworkEvents* network_events; + DiscordVersion network_version; + struct IDiscordOverlayEvents* overlay_events; + DiscordVersion overlay_version; + IDiscordStorageEvents* storage_events; + DiscordVersion storage_version; + struct IDiscordStoreEvents* store_events; + DiscordVersion store_version; + struct IDiscordVoiceEvents* voice_events; + DiscordVersion voice_version; + struct IDiscordAchievementEvents* achievement_events; + DiscordVersion achievement_version; +}; + +#ifdef __cplusplus +inline +#else +static +#endif + void + DiscordCreateParamsSetDefault(struct DiscordCreateParams* params) +{ + memset(params, 0, sizeof(struct DiscordCreateParams)); + params->application_version = DISCORD_APPLICATION_MANAGER_VERSION; + params->user_version = DISCORD_USER_MANAGER_VERSION; + params->image_version = DISCORD_IMAGE_MANAGER_VERSION; + params->activity_version = DISCORD_ACTIVITY_MANAGER_VERSION; + params->relationship_version = DISCORD_RELATIONSHIP_MANAGER_VERSION; + params->lobby_version = DISCORD_LOBBY_MANAGER_VERSION; + params->network_version = DISCORD_NETWORK_MANAGER_VERSION; + params->overlay_version = DISCORD_OVERLAY_MANAGER_VERSION; + params->storage_version = DISCORD_STORAGE_MANAGER_VERSION; + params->store_version = DISCORD_STORE_MANAGER_VERSION; + params->voice_version = DISCORD_VOICE_MANAGER_VERSION; + params->achievement_version = DISCORD_ACHIEVEMENT_MANAGER_VERSION; +} + +enum EDiscordResult DiscordCreate(DiscordVersion version, + struct DiscordCreateParams* params, + struct IDiscordCore** result); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/depend/discord/image_manager.cpp b/depend/discord/image_manager.cpp new file mode 100644 index 0000000..03b1db4 --- /dev/null +++ b/depend/discord/image_manager.cpp @@ -0,0 +1,57 @@ +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "image_manager.h" + +#include "core.h" + +#include +#include + +namespace discord { + +void ImageManager::Fetch(ImageHandle handle, + bool refresh, + std::function callback) +{ + static auto wrapper = + [](void* callbackData, EDiscordResult result, DiscordImageHandle handleResult) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result), *reinterpret_cast(&handleResult)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->fetch(internal_, + *reinterpret_cast(&handle), + (refresh ? 1 : 0), + cb.release(), + wrapper); +} + +Result ImageManager::GetDimensions(ImageHandle handle, ImageDimensions* dimensions) +{ + if (!dimensions) { + return Result::InternalError; + } + + auto result = internal_->get_dimensions(internal_, + *reinterpret_cast(&handle), + reinterpret_cast(dimensions)); + return static_cast(result); +} + +Result ImageManager::GetData(ImageHandle handle, std::uint8_t* data, std::uint32_t dataLength) +{ + auto result = internal_->get_data(internal_, + *reinterpret_cast(&handle), + reinterpret_cast(data), + dataLength); + return static_cast(result); +} + +} // namespace discord diff --git a/depend/discord/image_manager.h b/depend/discord/image_manager.h new file mode 100644 index 0000000..b096b17 --- /dev/null +++ b/depend/discord/image_manager.h @@ -0,0 +1,28 @@ +#pragma once + +#include "types.h" + +namespace discord { + +class ImageManager final { +public: + ~ImageManager() = default; + + void Fetch(ImageHandle handle, bool refresh, std::function callback); + Result GetDimensions(ImageHandle handle, ImageDimensions* dimensions); + Result GetData(ImageHandle handle, std::uint8_t* data, std::uint32_t dataLength); + +private: + friend class Core; + + ImageManager() = default; + ImageManager(ImageManager const& rhs) = delete; + ImageManager& operator=(ImageManager const& rhs) = delete; + ImageManager(ImageManager&& rhs) = delete; + ImageManager& operator=(ImageManager&& rhs) = delete; + + IDiscordImageManager* internal_; + static IDiscordImageEvents events_; +}; + +} // namespace discord diff --git a/depend/discord/lobby_manager.cpp b/depend/discord/lobby_manager.cpp new file mode 100644 index 0000000..6bf1a1a --- /dev/null +++ b/depend/discord/lobby_manager.cpp @@ -0,0 +1,547 @@ +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "lobby_manager.h" + +#include "core.h" + +#include +#include + +namespace discord { + +class LobbyEvents final { +public: + static void OnLobbyUpdate(void* callbackData, int64_t lobbyId) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->LobbyManager(); + module.OnLobbyUpdate(lobbyId); + } + + static void OnLobbyDelete(void* callbackData, int64_t lobbyId, uint32_t reason) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->LobbyManager(); + module.OnLobbyDelete(lobbyId, reason); + } + + static void OnMemberConnect(void* callbackData, int64_t lobbyId, int64_t userId) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->LobbyManager(); + module.OnMemberConnect(lobbyId, userId); + } + + static void OnMemberUpdate(void* callbackData, int64_t lobbyId, int64_t userId) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->LobbyManager(); + module.OnMemberUpdate(lobbyId, userId); + } + + static void OnMemberDisconnect(void* callbackData, int64_t lobbyId, int64_t userId) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->LobbyManager(); + module.OnMemberDisconnect(lobbyId, userId); + } + + static void OnLobbyMessage(void* callbackData, + int64_t lobbyId, + int64_t userId, + uint8_t* data, + uint32_t dataLength) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->LobbyManager(); + module.OnLobbyMessage(lobbyId, userId, data, dataLength); + } + + static void OnSpeaking(void* callbackData, int64_t lobbyId, int64_t userId, bool speaking) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->LobbyManager(); + module.OnSpeaking(lobbyId, userId, (speaking != 0)); + } + + static void OnNetworkMessage(void* callbackData, + int64_t lobbyId, + int64_t userId, + uint8_t channelId, + uint8_t* data, + uint32_t dataLength) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->LobbyManager(); + module.OnNetworkMessage(lobbyId, userId, channelId, data, dataLength); + } +}; + +IDiscordLobbyEvents LobbyManager::events_{ + &LobbyEvents::OnLobbyUpdate, + &LobbyEvents::OnLobbyDelete, + &LobbyEvents::OnMemberConnect, + &LobbyEvents::OnMemberUpdate, + &LobbyEvents::OnMemberDisconnect, + &LobbyEvents::OnLobbyMessage, + &LobbyEvents::OnSpeaking, + &LobbyEvents::OnNetworkMessage, +}; + +Result LobbyManager::GetLobbyCreateTransaction(LobbyTransaction* transaction) +{ + if (!transaction) { + return Result::InternalError; + } + + auto result = internal_->get_lobby_create_transaction(internal_, transaction->Receive()); + return static_cast(result); +} + +Result LobbyManager::GetLobbyUpdateTransaction(LobbyId lobbyId, LobbyTransaction* transaction) +{ + if (!transaction) { + return Result::InternalError; + } + + auto result = + internal_->get_lobby_update_transaction(internal_, lobbyId, transaction->Receive()); + return static_cast(result); +} + +Result LobbyManager::GetMemberUpdateTransaction(LobbyId lobbyId, + UserId userId, + LobbyMemberTransaction* transaction) +{ + if (!transaction) { + return Result::InternalError; + } + + auto result = + internal_->get_member_update_transaction(internal_, lobbyId, userId, transaction->Receive()); + return static_cast(result); +} + +void LobbyManager::CreateLobby(LobbyTransaction const& transaction, + std::function callback) +{ + static auto wrapper = + [](void* callbackData, EDiscordResult result, DiscordLobby* lobby) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result), *reinterpret_cast(lobby)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->create_lobby( + internal_, const_cast(transaction).Internal(), cb.release(), wrapper); +} + +void LobbyManager::UpdateLobby(LobbyId lobbyId, + LobbyTransaction const& transaction, + std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->update_lobby(internal_, + lobbyId, + const_cast(transaction).Internal(), + cb.release(), + wrapper); +} + +void LobbyManager::DeleteLobby(LobbyId lobbyId, std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->delete_lobby(internal_, lobbyId, cb.release(), wrapper); +} + +void LobbyManager::ConnectLobby(LobbyId lobbyId, + LobbySecret secret, + std::function callback) +{ + static auto wrapper = + [](void* callbackData, EDiscordResult result, DiscordLobby* lobby) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result), *reinterpret_cast(lobby)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->connect_lobby(internal_, lobbyId, const_cast(secret), cb.release(), wrapper); +} + +void LobbyManager::ConnectLobbyWithActivitySecret( + LobbySecret activitySecret, + std::function callback) +{ + static auto wrapper = + [](void* callbackData, EDiscordResult result, DiscordLobby* lobby) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result), *reinterpret_cast(lobby)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->connect_lobby_with_activity_secret( + internal_, const_cast(activitySecret), cb.release(), wrapper); +} + +void LobbyManager::DisconnectLobby(LobbyId lobbyId, std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->disconnect_lobby(internal_, lobbyId, cb.release(), wrapper); +} + +Result LobbyManager::GetLobby(LobbyId lobbyId, Lobby* lobby) +{ + if (!lobby) { + return Result::InternalError; + } + + auto result = internal_->get_lobby(internal_, lobbyId, reinterpret_cast(lobby)); + return static_cast(result); +} + +Result LobbyManager::GetLobbyActivitySecret(LobbyId lobbyId, char secret[128]) +{ + if (!secret) { + return Result::InternalError; + } + + auto result = internal_->get_lobby_activity_secret( + internal_, lobbyId, reinterpret_cast(secret)); + return static_cast(result); +} + +Result LobbyManager::GetLobbyMetadataValue(LobbyId lobbyId, MetadataKey key, char value[4096]) +{ + if (!value) { + return Result::InternalError; + } + + auto result = internal_->get_lobby_metadata_value( + internal_, lobbyId, const_cast(key), reinterpret_cast(value)); + return static_cast(result); +} + +Result LobbyManager::GetLobbyMetadataKey(LobbyId lobbyId, std::int32_t index, char key[256]) +{ + if (!key) { + return Result::InternalError; + } + + auto result = internal_->get_lobby_metadata_key( + internal_, lobbyId, index, reinterpret_cast(key)); + return static_cast(result); +} + +Result LobbyManager::LobbyMetadataCount(LobbyId lobbyId, std::int32_t* count) +{ + if (!count) { + return Result::InternalError; + } + + auto result = + internal_->lobby_metadata_count(internal_, lobbyId, reinterpret_cast(count)); + return static_cast(result); +} + +Result LobbyManager::MemberCount(LobbyId lobbyId, std::int32_t* count) +{ + if (!count) { + return Result::InternalError; + } + + auto result = internal_->member_count(internal_, lobbyId, reinterpret_cast(count)); + return static_cast(result); +} + +Result LobbyManager::GetMemberUserId(LobbyId lobbyId, std::int32_t index, UserId* userId) +{ + if (!userId) { + return Result::InternalError; + } + + auto result = + internal_->get_member_user_id(internal_, lobbyId, index, reinterpret_cast(userId)); + return static_cast(result); +} + +Result LobbyManager::GetMemberUser(LobbyId lobbyId, UserId userId, User* user) +{ + if (!user) { + return Result::InternalError; + } + + auto result = + internal_->get_member_user(internal_, lobbyId, userId, reinterpret_cast(user)); + return static_cast(result); +} + +Result LobbyManager::GetMemberMetadataValue(LobbyId lobbyId, + UserId userId, + MetadataKey key, + char value[4096]) +{ + if (!value) { + return Result::InternalError; + } + + auto result = + internal_->get_member_metadata_value(internal_, + lobbyId, + userId, + const_cast(key), + reinterpret_cast(value)); + return static_cast(result); +} + +Result LobbyManager::GetMemberMetadataKey(LobbyId lobbyId, + UserId userId, + std::int32_t index, + char key[256]) +{ + if (!key) { + return Result::InternalError; + } + + auto result = internal_->get_member_metadata_key( + internal_, lobbyId, userId, index, reinterpret_cast(key)); + return static_cast(result); +} + +Result LobbyManager::MemberMetadataCount(LobbyId lobbyId, UserId userId, std::int32_t* count) +{ + if (!count) { + return Result::InternalError; + } + + auto result = internal_->member_metadata_count( + internal_, lobbyId, userId, reinterpret_cast(count)); + return static_cast(result); +} + +void LobbyManager::UpdateMember(LobbyId lobbyId, + UserId userId, + LobbyMemberTransaction const& transaction, + std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->update_member(internal_, + lobbyId, + userId, + const_cast(transaction).Internal(), + cb.release(), + wrapper); +} + +void LobbyManager::SendLobbyMessage(LobbyId lobbyId, + std::uint8_t* data, + std::uint32_t dataLength, + std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->send_lobby_message( + internal_, lobbyId, reinterpret_cast(data), dataLength, cb.release(), wrapper); +} + +Result LobbyManager::GetSearchQuery(LobbySearchQuery* query) +{ + if (!query) { + return Result::InternalError; + } + + auto result = internal_->get_search_query(internal_, query->Receive()); + return static_cast(result); +} + +void LobbyManager::Search(LobbySearchQuery const& query, std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->search( + internal_, const_cast(query).Internal(), cb.release(), wrapper); +} + +void LobbyManager::LobbyCount(std::int32_t* count) +{ + if (!count) { + return; + } + + internal_->lobby_count(internal_, reinterpret_cast(count)); +} + +Result LobbyManager::GetLobbyId(std::int32_t index, LobbyId* lobbyId) +{ + if (!lobbyId) { + return Result::InternalError; + } + + auto result = internal_->get_lobby_id(internal_, index, reinterpret_cast(lobbyId)); + return static_cast(result); +} + +void LobbyManager::ConnectVoice(LobbyId lobbyId, std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->connect_voice(internal_, lobbyId, cb.release(), wrapper); +} + +void LobbyManager::DisconnectVoice(LobbyId lobbyId, std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->disconnect_voice(internal_, lobbyId, cb.release(), wrapper); +} + +Result LobbyManager::ConnectNetwork(LobbyId lobbyId) +{ + auto result = internal_->connect_network(internal_, lobbyId); + return static_cast(result); +} + +Result LobbyManager::DisconnectNetwork(LobbyId lobbyId) +{ + auto result = internal_->disconnect_network(internal_, lobbyId); + return static_cast(result); +} + +Result LobbyManager::FlushNetwork() +{ + auto result = internal_->flush_network(internal_); + return static_cast(result); +} + +Result LobbyManager::OpenNetworkChannel(LobbyId lobbyId, std::uint8_t channelId, bool reliable) +{ + auto result = + internal_->open_network_channel(internal_, lobbyId, channelId, (reliable ? 1 : 0)); + return static_cast(result); +} + +Result LobbyManager::SendNetworkMessage(LobbyId lobbyId, + UserId userId, + std::uint8_t channelId, + std::uint8_t* data, + std::uint32_t dataLength) +{ + auto result = internal_->send_network_message( + internal_, lobbyId, userId, channelId, reinterpret_cast(data), dataLength); + return static_cast(result); +} + +} // namespace discord diff --git a/depend/discord/lobby_manager.h b/depend/discord/lobby_manager.h new file mode 100644 index 0000000..96380cb --- /dev/null +++ b/depend/discord/lobby_manager.h @@ -0,0 +1,88 @@ +#pragma once + +#include "types.h" + +namespace discord { + +class LobbyManager final { +public: + ~LobbyManager() = default; + + Result GetLobbyCreateTransaction(LobbyTransaction* transaction); + Result GetLobbyUpdateTransaction(LobbyId lobbyId, LobbyTransaction* transaction); + Result GetMemberUpdateTransaction(LobbyId lobbyId, + UserId userId, + LobbyMemberTransaction* transaction); + void CreateLobby(LobbyTransaction const& transaction, + std::function callback); + void UpdateLobby(LobbyId lobbyId, + LobbyTransaction const& transaction, + std::function callback); + void DeleteLobby(LobbyId lobbyId, std::function callback); + void ConnectLobby(LobbyId lobbyId, + LobbySecret secret, + std::function callback); + void ConnectLobbyWithActivitySecret(LobbySecret activitySecret, + std::function callback); + void DisconnectLobby(LobbyId lobbyId, std::function callback); + Result GetLobby(LobbyId lobbyId, Lobby* lobby); + Result GetLobbyActivitySecret(LobbyId lobbyId, char secret[128]); + Result GetLobbyMetadataValue(LobbyId lobbyId, MetadataKey key, char value[4096]); + Result GetLobbyMetadataKey(LobbyId lobbyId, std::int32_t index, char key[256]); + Result LobbyMetadataCount(LobbyId lobbyId, std::int32_t* count); + Result MemberCount(LobbyId lobbyId, std::int32_t* count); + Result GetMemberUserId(LobbyId lobbyId, std::int32_t index, UserId* userId); + Result GetMemberUser(LobbyId lobbyId, UserId userId, User* user); + Result GetMemberMetadataValue(LobbyId lobbyId, + UserId userId, + MetadataKey key, + char value[4096]); + Result GetMemberMetadataKey(LobbyId lobbyId, UserId userId, std::int32_t index, char key[256]); + Result MemberMetadataCount(LobbyId lobbyId, UserId userId, std::int32_t* count); + void UpdateMember(LobbyId lobbyId, + UserId userId, + LobbyMemberTransaction const& transaction, + std::function callback); + void SendLobbyMessage(LobbyId lobbyId, + std::uint8_t* data, + std::uint32_t dataLength, + std::function callback); + Result GetSearchQuery(LobbySearchQuery* query); + void Search(LobbySearchQuery const& query, std::function callback); + void LobbyCount(std::int32_t* count); + Result GetLobbyId(std::int32_t index, LobbyId* lobbyId); + void ConnectVoice(LobbyId lobbyId, std::function callback); + void DisconnectVoice(LobbyId lobbyId, std::function callback); + Result ConnectNetwork(LobbyId lobbyId); + Result DisconnectNetwork(LobbyId lobbyId); + Result FlushNetwork(); + Result OpenNetworkChannel(LobbyId lobbyId, std::uint8_t channelId, bool reliable); + Result SendNetworkMessage(LobbyId lobbyId, + UserId userId, + std::uint8_t channelId, + std::uint8_t* data, + std::uint32_t dataLength); + + Event OnLobbyUpdate; + Event OnLobbyDelete; + Event OnMemberConnect; + Event OnMemberUpdate; + Event OnMemberDisconnect; + Event OnLobbyMessage; + Event OnSpeaking; + Event OnNetworkMessage; + +private: + friend class Core; + + LobbyManager() = default; + LobbyManager(LobbyManager const& rhs) = delete; + LobbyManager& operator=(LobbyManager const& rhs) = delete; + LobbyManager(LobbyManager&& rhs) = delete; + LobbyManager& operator=(LobbyManager&& rhs) = delete; + + IDiscordLobbyManager* internal_; + static IDiscordLobbyEvents events_; +}; + +} // namespace discord diff --git a/depend/discord/network_manager.cpp b/depend/discord/network_manager.cpp new file mode 100644 index 0000000..97c219e --- /dev/null +++ b/depend/discord/network_manager.cpp @@ -0,0 +1,103 @@ +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "network_manager.h" + +#include "core.h" + +#include +#include + +namespace discord { + +class NetworkEvents final { +public: + static void OnMessage(void* callbackData, + DiscordNetworkPeerId peerId, + DiscordNetworkChannelId channelId, + uint8_t* data, + uint32_t dataLength) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->NetworkManager(); + module.OnMessage(peerId, channelId, data, dataLength); + } + + static void OnRouteUpdate(void* callbackData, char const* routeData) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->NetworkManager(); + module.OnRouteUpdate(static_cast(routeData)); + } +}; + +IDiscordNetworkEvents NetworkManager::events_{ + &NetworkEvents::OnMessage, + &NetworkEvents::OnRouteUpdate, +}; + +void NetworkManager::GetPeerId(NetworkPeerId* peerId) +{ + if (!peerId) { + return; + } + + internal_->get_peer_id(internal_, reinterpret_cast(peerId)); +} + +Result NetworkManager::Flush() +{ + auto result = internal_->flush(internal_); + return static_cast(result); +} + +Result NetworkManager::OpenPeer(NetworkPeerId peerId, char const* routeData) +{ + auto result = internal_->open_peer(internal_, peerId, const_cast(routeData)); + return static_cast(result); +} + +Result NetworkManager::UpdatePeer(NetworkPeerId peerId, char const* routeData) +{ + auto result = internal_->update_peer(internal_, peerId, const_cast(routeData)); + return static_cast(result); +} + +Result NetworkManager::ClosePeer(NetworkPeerId peerId) +{ + auto result = internal_->close_peer(internal_, peerId); + return static_cast(result); +} + +Result NetworkManager::OpenChannel(NetworkPeerId peerId, NetworkChannelId channelId, bool reliable) +{ + auto result = internal_->open_channel(internal_, peerId, channelId, (reliable ? 1 : 0)); + return static_cast(result); +} + +Result NetworkManager::CloseChannel(NetworkPeerId peerId, NetworkChannelId channelId) +{ + auto result = internal_->close_channel(internal_, peerId, channelId); + return static_cast(result); +} + +Result NetworkManager::SendMessage(NetworkPeerId peerId, + NetworkChannelId channelId, + std::uint8_t* data, + std::uint32_t dataLength) +{ + auto result = internal_->send_message( + internal_, peerId, channelId, reinterpret_cast(data), dataLength); + return static_cast(result); +} + +} // namespace discord diff --git a/depend/discord/network_manager.h b/depend/discord/network_manager.h new file mode 100644 index 0000000..e374670 --- /dev/null +++ b/depend/discord/network_manager.h @@ -0,0 +1,63 @@ +#pragma once + +#include "types.h" + +namespace discord { + +class NetworkManager final { +public: + ~NetworkManager() = default; + + /** + * Get the local peer ID for this process. + */ + void GetPeerId(NetworkPeerId* peerId); + /** + * Send pending network messages. + */ + Result Flush(); + /** + * Open a connection to a remote peer. + */ + Result OpenPeer(NetworkPeerId peerId, char const* routeData); + /** + * Update the route data for a connected peer. + */ + Result UpdatePeer(NetworkPeerId peerId, char const* routeData); + /** + * Close the connection to a remote peer. + */ + Result ClosePeer(NetworkPeerId peerId); + /** + * Open a message channel to a connected peer. + */ + Result OpenChannel(NetworkPeerId peerId, NetworkChannelId channelId, bool reliable); + /** + * Close a message channel to a connected peer. + */ + Result CloseChannel(NetworkPeerId peerId, NetworkChannelId channelId); + /** + * Send a message to a connected peer over an opened message channel. + */ + Result SendMessage(NetworkPeerId peerId, + NetworkChannelId channelId, + std::uint8_t* data, + std::uint32_t dataLength); + + Event OnMessage; + Event OnRouteUpdate; + +private: + friend class Core; + + NetworkManager() = default; + NetworkManager(NetworkManager const& rhs) = delete; + NetworkManager& operator=(NetworkManager const& rhs) = delete; + NetworkManager(NetworkManager&& rhs) = delete; + NetworkManager& operator=(NetworkManager&& rhs) = delete; + + IDiscordNetworkManager* internal_; + static IDiscordNetworkEvents events_; +}; + +} // namespace discord diff --git a/depend/discord/overlay_manager.cpp b/depend/discord/overlay_manager.cpp new file mode 100644 index 0000000..e1c91ce --- /dev/null +++ b/depend/discord/overlay_manager.cpp @@ -0,0 +1,112 @@ +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "overlay_manager.h" + +#include "core.h" + +#include +#include + +namespace discord { + +class OverlayEvents final { +public: + static void OnToggle(void* callbackData, bool locked) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->OverlayManager(); + module.OnToggle((locked != 0)); + } +}; + +IDiscordOverlayEvents OverlayManager::events_{ + &OverlayEvents::OnToggle, +}; + +void OverlayManager::IsEnabled(bool* enabled) +{ + if (!enabled) { + return; + } + + internal_->is_enabled(internal_, reinterpret_cast(enabled)); +} + +void OverlayManager::IsLocked(bool* locked) +{ + if (!locked) { + return; + } + + internal_->is_locked(internal_, reinterpret_cast(locked)); +} + +void OverlayManager::SetLocked(bool locked, std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->set_locked(internal_, (locked ? 1 : 0), cb.release(), wrapper); +} + +void OverlayManager::OpenActivityInvite(ActivityActionType type, + std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->open_activity_invite( + internal_, static_cast(type), cb.release(), wrapper); +} + +void OverlayManager::OpenGuildInvite(char const* code, std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->open_guild_invite(internal_, const_cast(code), cb.release(), wrapper); +} + +void OverlayManager::OpenVoiceSettings(std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->open_voice_settings(internal_, cb.release(), wrapper); +} + +} // namespace discord diff --git a/depend/discord/overlay_manager.h b/depend/discord/overlay_manager.h new file mode 100644 index 0000000..c452aed --- /dev/null +++ b/depend/discord/overlay_manager.h @@ -0,0 +1,33 @@ +#pragma once + +#include "types.h" + +namespace discord { + +class OverlayManager final { +public: + ~OverlayManager() = default; + + void IsEnabled(bool* enabled); + void IsLocked(bool* locked); + void SetLocked(bool locked, std::function callback); + void OpenActivityInvite(ActivityActionType type, std::function callback); + void OpenGuildInvite(char const* code, std::function callback); + void OpenVoiceSettings(std::function callback); + + Event OnToggle; + +private: + friend class Core; + + OverlayManager() = default; + OverlayManager(OverlayManager const& rhs) = delete; + OverlayManager& operator=(OverlayManager const& rhs) = delete; + OverlayManager(OverlayManager&& rhs) = delete; + OverlayManager& operator=(OverlayManager&& rhs) = delete; + + IDiscordOverlayManager* internal_; + static IDiscordOverlayEvents events_; +}; + +} // namespace discord diff --git a/depend/discord/relationship_manager.cpp b/depend/discord/relationship_manager.cpp new file mode 100644 index 0000000..005f2b0 --- /dev/null +++ b/depend/discord/relationship_manager.cpp @@ -0,0 +1,90 @@ +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "relationship_manager.h" + +#include "core.h" + +#include +#include + +namespace discord { + +class RelationshipEvents final { +public: + static void OnRefresh(void* callbackData) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->RelationshipManager(); + module.OnRefresh(); + } + + static void OnRelationshipUpdate(void* callbackData, DiscordRelationship* relationship) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->RelationshipManager(); + module.OnRelationshipUpdate(*reinterpret_cast(relationship)); + } +}; + +IDiscordRelationshipEvents RelationshipManager::events_{ + &RelationshipEvents::OnRefresh, + &RelationshipEvents::OnRelationshipUpdate, +}; + +void RelationshipManager::Filter(std::function filter) +{ + static auto wrapper = [](void* callbackData, DiscordRelationship* relationship) -> bool { + auto cb(reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return {}; + } + return (*cb)(*reinterpret_cast(relationship)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(filter))); + internal_->filter(internal_, cb.get(), wrapper); +} + +Result RelationshipManager::Count(std::int32_t* count) +{ + if (!count) { + return Result::InternalError; + } + + auto result = internal_->count(internal_, reinterpret_cast(count)); + return static_cast(result); +} + +Result RelationshipManager::Get(UserId userId, Relationship* relationship) +{ + if (!relationship) { + return Result::InternalError; + } + + auto result = + internal_->get(internal_, userId, reinterpret_cast(relationship)); + return static_cast(result); +} + +Result RelationshipManager::GetAt(std::uint32_t index, Relationship* relationship) +{ + if (!relationship) { + return Result::InternalError; + } + + auto result = + internal_->get_at(internal_, index, reinterpret_cast(relationship)); + return static_cast(result); +} + +} // namespace discord diff --git a/depend/discord/relationship_manager.h b/depend/discord/relationship_manager.h new file mode 100644 index 0000000..e9cd016 --- /dev/null +++ b/depend/discord/relationship_manager.h @@ -0,0 +1,32 @@ +#pragma once + +#include "types.h" + +namespace discord { + +class RelationshipManager final { +public: + ~RelationshipManager() = default; + + void Filter(std::function filter); + Result Count(std::int32_t* count); + Result Get(UserId userId, Relationship* relationship); + Result GetAt(std::uint32_t index, Relationship* relationship); + + Event<> OnRefresh; + Event OnRelationshipUpdate; + +private: + friend class Core; + + RelationshipManager() = default; + RelationshipManager(RelationshipManager const& rhs) = delete; + RelationshipManager& operator=(RelationshipManager const& rhs) = delete; + RelationshipManager(RelationshipManager&& rhs) = delete; + RelationshipManager& operator=(RelationshipManager&& rhs) = delete; + + IDiscordRelationshipManager* internal_; + static IDiscordRelationshipEvents events_; +}; + +} // namespace discord diff --git a/depend/discord/storage_manager.cpp b/depend/discord/storage_manager.cpp new file mode 100644 index 0000000..fbf9ca7 --- /dev/null +++ b/depend/discord/storage_manager.cpp @@ -0,0 +1,158 @@ +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "storage_manager.h" + +#include "core.h" + +#include +#include + +namespace discord { + +Result StorageManager::Read(char const* name, + std::uint8_t* data, + std::uint32_t dataLength, + std::uint32_t* read) +{ + if (!read) { + return Result::InternalError; + } + + auto result = internal_->read(internal_, + const_cast(name), + reinterpret_cast(data), + dataLength, + reinterpret_cast(read)); + return static_cast(result); +} + +void StorageManager::ReadAsync(char const* name, + std::function callback) +{ + static auto wrapper = + [](void* callbackData, EDiscordResult result, uint8_t* data, uint32_t dataLength) -> void { + std::unique_ptr> cb( + reinterpret_cast*>( + callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result), data, dataLength); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->read_async(internal_, const_cast(name), cb.release(), wrapper); +} + +void StorageManager::ReadAsyncPartial( + char const* name, + std::uint64_t offset, + std::uint64_t length, + std::function callback) +{ + static auto wrapper = + [](void* callbackData, EDiscordResult result, uint8_t* data, uint32_t dataLength) -> void { + std::unique_ptr> cb( + reinterpret_cast*>( + callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result), data, dataLength); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->read_async_partial( + internal_, const_cast(name), offset, length, cb.release(), wrapper); +} + +Result StorageManager::Write(char const* name, std::uint8_t* data, std::uint32_t dataLength) +{ + auto result = internal_->write( + internal_, const_cast(name), reinterpret_cast(data), dataLength); + return static_cast(result); +} + +void StorageManager::WriteAsync(char const* name, + std::uint8_t* data, + std::uint32_t dataLength, + std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->write_async(internal_, + const_cast(name), + reinterpret_cast(data), + dataLength, + cb.release(), + wrapper); +} + +Result StorageManager::Delete(char const* name) +{ + auto result = internal_->delete_(internal_, const_cast(name)); + return static_cast(result); +} + +Result StorageManager::Exists(char const* name, bool* exists) +{ + if (!exists) { + return Result::InternalError; + } + + auto result = + internal_->exists(internal_, const_cast(name), reinterpret_cast(exists)); + return static_cast(result); +} + +void StorageManager::Count(std::int32_t* count) +{ + if (!count) { + return; + } + + internal_->count(internal_, reinterpret_cast(count)); +} + +Result StorageManager::Stat(char const* name, FileStat* stat) +{ + if (!stat) { + return Result::InternalError; + } + + auto result = + internal_->stat(internal_, const_cast(name), reinterpret_cast(stat)); + return static_cast(result); +} + +Result StorageManager::StatAt(std::int32_t index, FileStat* stat) +{ + if (!stat) { + return Result::InternalError; + } + + auto result = internal_->stat_at(internal_, index, reinterpret_cast(stat)); + return static_cast(result); +} + +Result StorageManager::GetPath(char path[4096]) +{ + if (!path) { + return Result::InternalError; + } + + auto result = internal_->get_path(internal_, reinterpret_cast(path)); + return static_cast(result); +} + +} // namespace discord diff --git a/depend/discord/storage_manager.h b/depend/discord/storage_manager.h new file mode 100644 index 0000000..5d6d17b --- /dev/null +++ b/depend/discord/storage_manager.h @@ -0,0 +1,46 @@ +#pragma once + +#include "types.h" + +namespace discord { + +class StorageManager final { +public: + ~StorageManager() = default; + + Result Read(char const* name, + std::uint8_t* data, + std::uint32_t dataLength, + std::uint32_t* read); + void ReadAsync(char const* name, + std::function callback); + void ReadAsyncPartial(char const* name, + std::uint64_t offset, + std::uint64_t length, + std::function callback); + Result Write(char const* name, std::uint8_t* data, std::uint32_t dataLength); + void WriteAsync(char const* name, + std::uint8_t* data, + std::uint32_t dataLength, + std::function callback); + Result Delete(char const* name); + Result Exists(char const* name, bool* exists); + void Count(std::int32_t* count); + Result Stat(char const* name, FileStat* stat); + Result StatAt(std::int32_t index, FileStat* stat); + Result GetPath(char path[4096]); + +private: + friend class Core; + + StorageManager() = default; + StorageManager(StorageManager const& rhs) = delete; + StorageManager& operator=(StorageManager const& rhs) = delete; + StorageManager(StorageManager&& rhs) = delete; + StorageManager& operator=(StorageManager&& rhs) = delete; + + IDiscordStorageManager* internal_; + static IDiscordStorageEvents events_; +}; + +} // namespace discord diff --git a/depend/discord/store_manager.cpp b/depend/discord/store_manager.cpp new file mode 100644 index 0000000..d6bdad1 --- /dev/null +++ b/depend/discord/store_manager.cpp @@ -0,0 +1,160 @@ +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "store_manager.h" + +#include "core.h" + +#include +#include + +namespace discord { + +class StoreEvents final { +public: + static void OnEntitlementCreate(void* callbackData, DiscordEntitlement* entitlement) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->StoreManager(); + module.OnEntitlementCreate(*reinterpret_cast(entitlement)); + } + + static void OnEntitlementDelete(void* callbackData, DiscordEntitlement* entitlement) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->StoreManager(); + module.OnEntitlementDelete(*reinterpret_cast(entitlement)); + } +}; + +IDiscordStoreEvents StoreManager::events_{ + &StoreEvents::OnEntitlementCreate, + &StoreEvents::OnEntitlementDelete, +}; + +void StoreManager::FetchSkus(std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->fetch_skus(internal_, cb.release(), wrapper); +} + +void StoreManager::CountSkus(std::int32_t* count) +{ + if (!count) { + return; + } + + internal_->count_skus(internal_, reinterpret_cast(count)); +} + +Result StoreManager::GetSku(Snowflake skuId, Sku* sku) +{ + if (!sku) { + return Result::InternalError; + } + + auto result = internal_->get_sku(internal_, skuId, reinterpret_cast(sku)); + return static_cast(result); +} + +Result StoreManager::GetSkuAt(std::int32_t index, Sku* sku) +{ + if (!sku) { + return Result::InternalError; + } + + auto result = internal_->get_sku_at(internal_, index, reinterpret_cast(sku)); + return static_cast(result); +} + +void StoreManager::FetchEntitlements(std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->fetch_entitlements(internal_, cb.release(), wrapper); +} + +void StoreManager::CountEntitlements(std::int32_t* count) +{ + if (!count) { + return; + } + + internal_->count_entitlements(internal_, reinterpret_cast(count)); +} + +Result StoreManager::GetEntitlement(Snowflake entitlementId, Entitlement* entitlement) +{ + if (!entitlement) { + return Result::InternalError; + } + + auto result = internal_->get_entitlement( + internal_, entitlementId, reinterpret_cast(entitlement)); + return static_cast(result); +} + +Result StoreManager::GetEntitlementAt(std::int32_t index, Entitlement* entitlement) +{ + if (!entitlement) { + return Result::InternalError; + } + + auto result = internal_->get_entitlement_at( + internal_, index, reinterpret_cast(entitlement)); + return static_cast(result); +} + +Result StoreManager::HasSkuEntitlement(Snowflake skuId, bool* hasEntitlement) +{ + if (!hasEntitlement) { + return Result::InternalError; + } + + auto result = + internal_->has_sku_entitlement(internal_, skuId, reinterpret_cast(hasEntitlement)); + return static_cast(result); +} + +void StoreManager::StartPurchase(Snowflake skuId, std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->start_purchase(internal_, skuId, cb.release(), wrapper); +} + +} // namespace discord diff --git a/depend/discord/store_manager.h b/depend/discord/store_manager.h new file mode 100644 index 0000000..8e0df8a --- /dev/null +++ b/depend/discord/store_manager.h @@ -0,0 +1,38 @@ +#pragma once + +#include "types.h" + +namespace discord { + +class StoreManager final { +public: + ~StoreManager() = default; + + void FetchSkus(std::function callback); + void CountSkus(std::int32_t* count); + Result GetSku(Snowflake skuId, Sku* sku); + Result GetSkuAt(std::int32_t index, Sku* sku); + void FetchEntitlements(std::function callback); + void CountEntitlements(std::int32_t* count); + Result GetEntitlement(Snowflake entitlementId, Entitlement* entitlement); + Result GetEntitlementAt(std::int32_t index, Entitlement* entitlement); + Result HasSkuEntitlement(Snowflake skuId, bool* hasEntitlement); + void StartPurchase(Snowflake skuId, std::function callback); + + Event OnEntitlementCreate; + Event OnEntitlementDelete; + +private: + friend class Core; + + StoreManager() = default; + StoreManager(StoreManager const& rhs) = delete; + StoreManager& operator=(StoreManager const& rhs) = delete; + StoreManager(StoreManager&& rhs) = delete; + StoreManager& operator=(StoreManager&& rhs) = delete; + + IDiscordStoreManager* internal_; + static IDiscordStoreEvents events_; +}; + +} // namespace discord diff --git a/depend/discord/types.cpp b/depend/discord/types.cpp new file mode 100644 index 0000000..66cdd49 --- /dev/null +++ b/depend/discord/types.cpp @@ -0,0 +1,769 @@ +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "types.h" + +#include +#include + +namespace discord { + +void User::SetId(UserId id) +{ + internal_.id = id; +} + +UserId User::GetId() const +{ + return internal_.id; +} + +void User::SetUsername(char const* username) +{ + strncpy(internal_.username, username, 256); + internal_.username[256 - 1] = '\0'; +} + +char const* User::GetUsername() const +{ + return internal_.username; +} + +void User::SetDiscriminator(char const* discriminator) +{ + strncpy(internal_.discriminator, discriminator, 8); + internal_.discriminator[8 - 1] = '\0'; +} + +char const* User::GetDiscriminator() const +{ + return internal_.discriminator; +} + +void User::SetAvatar(char const* avatar) +{ + strncpy(internal_.avatar, avatar, 128); + internal_.avatar[128 - 1] = '\0'; +} + +char const* User::GetAvatar() const +{ + return internal_.avatar; +} + +void User::SetBot(bool bot) +{ + internal_.bot = bot; +} + +bool User::GetBot() const +{ + return internal_.bot != 0; +} + +void OAuth2Token::SetAccessToken(char const* accessToken) +{ + strncpy(internal_.access_token, accessToken, 128); + internal_.access_token[128 - 1] = '\0'; +} + +char const* OAuth2Token::GetAccessToken() const +{ + return internal_.access_token; +} + +void OAuth2Token::SetScopes(char const* scopes) +{ + strncpy(internal_.scopes, scopes, 1024); + internal_.scopes[1024 - 1] = '\0'; +} + +char const* OAuth2Token::GetScopes() const +{ + return internal_.scopes; +} + +void OAuth2Token::SetExpires(Timestamp expires) +{ + internal_.expires = expires; +} + +Timestamp OAuth2Token::GetExpires() const +{ + return internal_.expires; +} + +void ImageHandle::SetType(ImageType type) +{ + internal_.type = static_cast(type); +} + +ImageType ImageHandle::GetType() const +{ + return static_cast(internal_.type); +} + +void ImageHandle::SetId(std::int64_t id) +{ + internal_.id = id; +} + +std::int64_t ImageHandle::GetId() const +{ + return internal_.id; +} + +void ImageHandle::SetSize(std::uint32_t size) +{ + internal_.size = size; +} + +std::uint32_t ImageHandle::GetSize() const +{ + return internal_.size; +} + +void ImageDimensions::SetWidth(std::uint32_t width) +{ + internal_.width = width; +} + +std::uint32_t ImageDimensions::GetWidth() const +{ + return internal_.width; +} + +void ImageDimensions::SetHeight(std::uint32_t height) +{ + internal_.height = height; +} + +std::uint32_t ImageDimensions::GetHeight() const +{ + return internal_.height; +} + +void ActivityTimestamps::SetStart(Timestamp start) +{ + internal_.start = start; +} + +Timestamp ActivityTimestamps::GetStart() const +{ + return internal_.start; +} + +void ActivityTimestamps::SetEnd(Timestamp end) +{ + internal_.end = end; +} + +Timestamp ActivityTimestamps::GetEnd() const +{ + return internal_.end; +} + +void ActivityAssets::SetLargeImage(char const* largeImage) +{ + strncpy(internal_.large_image, largeImage, 128); + internal_.large_image[128 - 1] = '\0'; +} + +char const* ActivityAssets::GetLargeImage() const +{ + return internal_.large_image; +} + +void ActivityAssets::SetLargeText(char const* largeText) +{ + strncpy(internal_.large_text, largeText, 128); + internal_.large_text[128 - 1] = '\0'; +} + +char const* ActivityAssets::GetLargeText() const +{ + return internal_.large_text; +} + +void ActivityAssets::SetSmallImage(char const* smallImage) +{ + strncpy(internal_.small_image, smallImage, 128); + internal_.small_image[128 - 1] = '\0'; +} + +char const* ActivityAssets::GetSmallImage() const +{ + return internal_.small_image; +} + +void ActivityAssets::SetSmallText(char const* smallText) +{ + strncpy(internal_.small_text, smallText, 128); + internal_.small_text[128 - 1] = '\0'; +} + +char const* ActivityAssets::GetSmallText() const +{ + return internal_.small_text; +} + +void PartySize::SetCurrentSize(std::int32_t currentSize) +{ + internal_.current_size = currentSize; +} + +std::int32_t PartySize::GetCurrentSize() const +{ + return internal_.current_size; +} + +void PartySize::SetMaxSize(std::int32_t maxSize) +{ + internal_.max_size = maxSize; +} + +std::int32_t PartySize::GetMaxSize() const +{ + return internal_.max_size; +} + +void ActivityParty::SetId(char const* id) +{ + strncpy(internal_.id, id, 128); + internal_.id[128 - 1] = '\0'; +} + +char const* ActivityParty::GetId() const +{ + return internal_.id; +} + +PartySize& ActivityParty::GetSize() +{ + return reinterpret_cast(internal_.size); +} + +PartySize const& ActivityParty::GetSize() const +{ + return reinterpret_cast(internal_.size); +} + +void ActivitySecrets::SetMatch(char const* match) +{ + strncpy(internal_.match, match, 128); + internal_.match[128 - 1] = '\0'; +} + +char const* ActivitySecrets::GetMatch() const +{ + return internal_.match; +} + +void ActivitySecrets::SetJoin(char const* join) +{ + strncpy(internal_.join, join, 128); + internal_.join[128 - 1] = '\0'; +} + +char const* ActivitySecrets::GetJoin() const +{ + return internal_.join; +} + +void ActivitySecrets::SetSpectate(char const* spectate) +{ + strncpy(internal_.spectate, spectate, 128); + internal_.spectate[128 - 1] = '\0'; +} + +char const* ActivitySecrets::GetSpectate() const +{ + return internal_.spectate; +} + +void Activity::SetType(ActivityType type) +{ + internal_.type = static_cast(type); +} + +ActivityType Activity::GetType() const +{ + return static_cast(internal_.type); +} + +void Activity::SetApplicationId(std::int64_t applicationId) +{ + internal_.application_id = applicationId; +} + +std::int64_t Activity::GetApplicationId() const +{ + return internal_.application_id; +} + +void Activity::SetName(char const* name) +{ + strncpy(internal_.name, name, 128); + internal_.name[128 - 1] = '\0'; +} + +char const* Activity::GetName() const +{ + return internal_.name; +} + +void Activity::SetState(char const* state) +{ + strncpy(internal_.state, state, 128); + internal_.state[128 - 1] = '\0'; +} + +char const* Activity::GetState() const +{ + return internal_.state; +} + +void Activity::SetDetails(char const* details) +{ + strncpy(internal_.details, details, 128); + internal_.details[128 - 1] = '\0'; +} + +char const* Activity::GetDetails() const +{ + return internal_.details; +} + +ActivityTimestamps& Activity::GetTimestamps() +{ + return reinterpret_cast(internal_.timestamps); +} + +ActivityTimestamps const& Activity::GetTimestamps() const +{ + return reinterpret_cast(internal_.timestamps); +} + +ActivityAssets& Activity::GetAssets() +{ + return reinterpret_cast(internal_.assets); +} + +ActivityAssets const& Activity::GetAssets() const +{ + return reinterpret_cast(internal_.assets); +} + +ActivityParty& Activity::GetParty() +{ + return reinterpret_cast(internal_.party); +} + +ActivityParty const& Activity::GetParty() const +{ + return reinterpret_cast(internal_.party); +} + +ActivitySecrets& Activity::GetSecrets() +{ + return reinterpret_cast(internal_.secrets); +} + +ActivitySecrets const& Activity::GetSecrets() const +{ + return reinterpret_cast(internal_.secrets); +} + +void Activity::SetInstance(bool instance) +{ + internal_.instance = instance; +} + +bool Activity::GetInstance() const +{ + return internal_.instance != 0; +} + +void Presence::SetStatus(Status status) +{ + internal_.status = static_cast(status); +} + +Status Presence::GetStatus() const +{ + return static_cast(internal_.status); +} + +Activity& Presence::GetActivity() +{ + return reinterpret_cast(internal_.activity); +} + +Activity const& Presence::GetActivity() const +{ + return reinterpret_cast(internal_.activity); +} + +void Relationship::SetType(RelationshipType type) +{ + internal_.type = static_cast(type); +} + +RelationshipType Relationship::GetType() const +{ + return static_cast(internal_.type); +} + +User& Relationship::GetUser() +{ + return reinterpret_cast(internal_.user); +} + +User const& Relationship::GetUser() const +{ + return reinterpret_cast(internal_.user); +} + +Presence& Relationship::GetPresence() +{ + return reinterpret_cast(internal_.presence); +} + +Presence const& Relationship::GetPresence() const +{ + return reinterpret_cast(internal_.presence); +} + +void Lobby::SetId(LobbyId id) +{ + internal_.id = id; +} + +LobbyId Lobby::GetId() const +{ + return internal_.id; +} + +void Lobby::SetType(LobbyType type) +{ + internal_.type = static_cast(type); +} + +LobbyType Lobby::GetType() const +{ + return static_cast(internal_.type); +} + +void Lobby::SetOwnerId(UserId ownerId) +{ + internal_.owner_id = ownerId; +} + +UserId Lobby::GetOwnerId() const +{ + return internal_.owner_id; +} + +void Lobby::SetSecret(LobbySecret secret) +{ + strncpy(internal_.secret, secret, 128); + internal_.secret[128 - 1] = '\0'; +} + +LobbySecret Lobby::GetSecret() const +{ + return internal_.secret; +} + +void Lobby::SetCapacity(std::uint32_t capacity) +{ + internal_.capacity = capacity; +} + +std::uint32_t Lobby::GetCapacity() const +{ + return internal_.capacity; +} + +void Lobby::SetLocked(bool locked) +{ + internal_.locked = locked; +} + +bool Lobby::GetLocked() const +{ + return internal_.locked != 0; +} + +void FileStat::SetFilename(char const* filename) +{ + strncpy(internal_.filename, filename, 260); + internal_.filename[260 - 1] = '\0'; +} + +char const* FileStat::GetFilename() const +{ + return internal_.filename; +} + +void FileStat::SetSize(std::uint64_t size) +{ + internal_.size = size; +} + +std::uint64_t FileStat::GetSize() const +{ + return internal_.size; +} + +void FileStat::SetLastModified(std::uint64_t lastModified) +{ + internal_.last_modified = lastModified; +} + +std::uint64_t FileStat::GetLastModified() const +{ + return internal_.last_modified; +} + +void Entitlement::SetId(Snowflake id) +{ + internal_.id = id; +} + +Snowflake Entitlement::GetId() const +{ + return internal_.id; +} + +void Entitlement::SetType(EntitlementType type) +{ + internal_.type = static_cast(type); +} + +EntitlementType Entitlement::GetType() const +{ + return static_cast(internal_.type); +} + +void Entitlement::SetSkuId(Snowflake skuId) +{ + internal_.sku_id = skuId; +} + +Snowflake Entitlement::GetSkuId() const +{ + return internal_.sku_id; +} + +void SkuPrice::SetAmount(std::uint32_t amount) +{ + internal_.amount = amount; +} + +std::uint32_t SkuPrice::GetAmount() const +{ + return internal_.amount; +} + +void SkuPrice::SetCurrency(char const* currency) +{ + strncpy(internal_.currency, currency, 16); + internal_.currency[16 - 1] = '\0'; +} + +char const* SkuPrice::GetCurrency() const +{ + return internal_.currency; +} + +void Sku::SetId(Snowflake id) +{ + internal_.id = id; +} + +Snowflake Sku::GetId() const +{ + return internal_.id; +} + +void Sku::SetType(SkuType type) +{ + internal_.type = static_cast(type); +} + +SkuType Sku::GetType() const +{ + return static_cast(internal_.type); +} + +void Sku::SetName(char const* name) +{ + strncpy(internal_.name, name, 256); + internal_.name[256 - 1] = '\0'; +} + +char const* Sku::GetName() const +{ + return internal_.name; +} + +SkuPrice& Sku::GetPrice() +{ + return reinterpret_cast(internal_.price); +} + +SkuPrice const& Sku::GetPrice() const +{ + return reinterpret_cast(internal_.price); +} + +void InputMode::SetType(InputModeType type) +{ + internal_.type = static_cast(type); +} + +InputModeType InputMode::GetType() const +{ + return static_cast(internal_.type); +} + +void InputMode::SetShortcut(char const* shortcut) +{ + strncpy(internal_.shortcut, shortcut, 256); + internal_.shortcut[256 - 1] = '\0'; +} + +char const* InputMode::GetShortcut() const +{ + return internal_.shortcut; +} + +void UserAchievement::SetUserId(Snowflake userId) +{ + internal_.user_id = userId; +} + +Snowflake UserAchievement::GetUserId() const +{ + return internal_.user_id; +} + +void UserAchievement::SetAchievementId(Snowflake achievementId) +{ + internal_.achievement_id = achievementId; +} + +Snowflake UserAchievement::GetAchievementId() const +{ + return internal_.achievement_id; +} + +void UserAchievement::SetPercentComplete(std::uint8_t percentComplete) +{ + internal_.percent_complete = percentComplete; +} + +std::uint8_t UserAchievement::GetPercentComplete() const +{ + return internal_.percent_complete; +} + +void UserAchievement::SetUnlockedAt(DateTime unlockedAt) +{ + strncpy(internal_.unlocked_at, unlockedAt, 64); + internal_.unlocked_at[64 - 1] = '\0'; +} + +DateTime UserAchievement::GetUnlockedAt() const +{ + return internal_.unlocked_at; +} + +Result LobbyTransaction::SetType(LobbyType type) +{ + auto result = internal_->set_type(internal_, static_cast(type)); + return static_cast(result); +} + +Result LobbyTransaction::SetOwner(UserId ownerId) +{ + auto result = internal_->set_owner(internal_, ownerId); + return static_cast(result); +} + +Result LobbyTransaction::SetCapacity(std::uint32_t capacity) +{ + auto result = internal_->set_capacity(internal_, capacity); + return static_cast(result); +} + +Result LobbyTransaction::SetMetadata(MetadataKey key, MetadataValue value) +{ + auto result = + internal_->set_metadata(internal_, const_cast(key), const_cast(value)); + return static_cast(result); +} + +Result LobbyTransaction::DeleteMetadata(MetadataKey key) +{ + auto result = internal_->delete_metadata(internal_, const_cast(key)); + return static_cast(result); +} + +Result LobbyTransaction::SetLocked(bool locked) +{ + auto result = internal_->set_locked(internal_, (locked ? 1 : 0)); + return static_cast(result); +} + +Result LobbyMemberTransaction::SetMetadata(MetadataKey key, MetadataValue value) +{ + auto result = + internal_->set_metadata(internal_, const_cast(key), const_cast(value)); + return static_cast(result); +} + +Result LobbyMemberTransaction::DeleteMetadata(MetadataKey key) +{ + auto result = internal_->delete_metadata(internal_, const_cast(key)); + return static_cast(result); +} + +Result LobbySearchQuery::Filter(MetadataKey key, + LobbySearchComparison comparison, + LobbySearchCast cast, + MetadataValue value) +{ + auto result = internal_->filter(internal_, + const_cast(key), + static_cast(comparison), + static_cast(cast), + const_cast(value)); + return static_cast(result); +} + +Result LobbySearchQuery::Sort(MetadataKey key, LobbySearchCast cast, MetadataValue value) +{ + auto result = internal_->sort(internal_, + const_cast(key), + static_cast(cast), + const_cast(value)); + return static_cast(result); +} + +Result LobbySearchQuery::Limit(std::uint32_t limit) +{ + auto result = internal_->limit(internal_, limit); + return static_cast(result); +} + +Result LobbySearchQuery::Distance(LobbySearchDistance distance) +{ + auto result = + internal_->distance(internal_, static_cast(distance)); + return static_cast(result); +} + +} // namespace discord diff --git a/depend/discord/types.h b/depend/discord/types.h new file mode 100644 index 0000000..8c7cc2b --- /dev/null +++ b/depend/discord/types.h @@ -0,0 +1,491 @@ +#pragma once + +#include "ffi.h" +#include "event.h" + +namespace discord { + +enum class Result { + Ok = 0, + ServiceUnavailable = 1, + InvalidVersion = 2, + LockFailed = 3, + InternalError = 4, + InvalidPayload = 5, + InvalidCommand = 6, + InvalidPermissions = 7, + NotFetched = 8, + NotFound = 9, + Conflict = 10, + InvalidSecret = 11, + InvalidJoinSecret = 12, + NoEligibleActivity = 13, + InvalidInvite = 14, + NotAuthenticated = 15, + InvalidAccessToken = 16, + ApplicationMismatch = 17, + InvalidDataUrl = 18, + InvalidBase64 = 19, + NotFiltered = 20, + LobbyFull = 21, + InvalidLobbySecret = 22, + InvalidFilename = 23, + InvalidFileSize = 24, + InvalidEntitlement = 25, + NotInstalled = 26, + NotRunning = 27, + InsufficientBuffer = 28, + PurchaseCanceled = 29, + InvalidGuild = 30, + InvalidEvent = 31, + InvalidChannel = 32, + InvalidOrigin = 33, + RateLimited = 34, + OAuth2Error = 35, + SelectChannelTimeout = 36, + GetGuildTimeout = 37, + SelectVoiceForceRequired = 38, + CaptureShortcutAlreadyListening = 39, + UnauthorizedForAchievement = 40, + InvalidGiftCode = 41, + PurchaseError = 42, + TransactionAborted = 43, +}; + +enum class CreateFlags { + Default = 0, + NoRequireDiscord = 1, +}; + +enum class LogLevel { + Error = 1, + Warn, + Info, + Debug, +}; + +enum class UserFlag { + Partner = 2, + HypeSquadEvents = 4, + HypeSquadHouse1 = 64, + HypeSquadHouse2 = 128, + HypeSquadHouse3 = 256, +}; + +enum class PremiumType { + None = 0, + Tier1 = 1, + Tier2 = 2, +}; + +enum class ImageType { + User, +}; + +enum class ActivityType { + Playing, + Streaming, + Listening, + Watching, +}; + +enum class ActivityActionType { + Join = 1, + Spectate, +}; + +enum class ActivityJoinRequestReply { + No, + Yes, + Ignore, +}; + +enum class Status { + Offline = 0, + Online = 1, + Idle = 2, + DoNotDisturb = 3, +}; + +enum class RelationshipType { + None, + Friend, + Blocked, + PendingIncoming, + PendingOutgoing, + Implicit, +}; + +enum class LobbyType { + Private = 1, + Public, +}; + +enum class LobbySearchComparison { + LessThanOrEqual = -2, + LessThan, + Equal, + GreaterThan, + GreaterThanOrEqual, + NotEqual, +}; + +enum class LobbySearchCast { + String = 1, + Number, +}; + +enum class LobbySearchDistance { + Local, + Default, + Extended, + Global, +}; + +enum class EntitlementType { + Purchase = 1, + PremiumSubscription, + DeveloperGift, + TestModePurchase, + FreePurchase, + UserGift, + PremiumPurchase, +}; + +enum class SkuType { + Application = 1, + DLC, + Consumable, + Bundle, +}; + +enum class InputModeType { + VoiceActivity = 0, + PushToTalk, +}; + +using ClientId = std::int64_t; +using Version = std::int32_t; +using Snowflake = std::int64_t; +using Timestamp = std::int64_t; +using UserId = Snowflake; +using Locale = char const*; +using Branch = char const*; +using LobbyId = Snowflake; +using LobbySecret = char const*; +using MetadataKey = char const*; +using MetadataValue = char const*; +using NetworkPeerId = std::uint64_t; +using NetworkChannelId = std::uint8_t; +using Path = char const*; +using DateTime = char const*; + +class User final { +public: + void SetId(UserId id); + UserId GetId() const; + void SetUsername(char const* username); + char const* GetUsername() const; + void SetDiscriminator(char const* discriminator); + char const* GetDiscriminator() const; + void SetAvatar(char const* avatar); + char const* GetAvatar() const; + void SetBot(bool bot); + bool GetBot() const; + +private: + DiscordUser internal_; +}; + +class OAuth2Token final { +public: + void SetAccessToken(char const* accessToken); + char const* GetAccessToken() const; + void SetScopes(char const* scopes); + char const* GetScopes() const; + void SetExpires(Timestamp expires); + Timestamp GetExpires() const; + +private: + DiscordOAuth2Token internal_; +}; + +class ImageHandle final { +public: + void SetType(ImageType type); + ImageType GetType() const; + void SetId(std::int64_t id); + std::int64_t GetId() const; + void SetSize(std::uint32_t size); + std::uint32_t GetSize() const; + +private: + DiscordImageHandle internal_; +}; + +class ImageDimensions final { +public: + void SetWidth(std::uint32_t width); + std::uint32_t GetWidth() const; + void SetHeight(std::uint32_t height); + std::uint32_t GetHeight() const; + +private: + DiscordImageDimensions internal_; +}; + +class ActivityTimestamps final { +public: + void SetStart(Timestamp start); + Timestamp GetStart() const; + void SetEnd(Timestamp end); + Timestamp GetEnd() const; + +private: + DiscordActivityTimestamps internal_; +}; + +class ActivityAssets final { +public: + void SetLargeImage(char const* largeImage); + char const* GetLargeImage() const; + void SetLargeText(char const* largeText); + char const* GetLargeText() const; + void SetSmallImage(char const* smallImage); + char const* GetSmallImage() const; + void SetSmallText(char const* smallText); + char const* GetSmallText() const; + +private: + DiscordActivityAssets internal_; +}; + +class PartySize final { +public: + void SetCurrentSize(std::int32_t currentSize); + std::int32_t GetCurrentSize() const; + void SetMaxSize(std::int32_t maxSize); + std::int32_t GetMaxSize() const; + +private: + DiscordPartySize internal_; +}; + +class ActivityParty final { +public: + void SetId(char const* id); + char const* GetId() const; + PartySize& GetSize(); + PartySize const& GetSize() const; + +private: + DiscordActivityParty internal_; +}; + +class ActivitySecrets final { +public: + void SetMatch(char const* match); + char const* GetMatch() const; + void SetJoin(char const* join); + char const* GetJoin() const; + void SetSpectate(char const* spectate); + char const* GetSpectate() const; + +private: + DiscordActivitySecrets internal_; +}; + +class Activity final { +public: + void SetType(ActivityType type); + ActivityType GetType() const; + void SetApplicationId(std::int64_t applicationId); + std::int64_t GetApplicationId() const; + void SetName(char const* name); + char const* GetName() const; + void SetState(char const* state); + char const* GetState() const; + void SetDetails(char const* details); + char const* GetDetails() const; + ActivityTimestamps& GetTimestamps(); + ActivityTimestamps const& GetTimestamps() const; + ActivityAssets& GetAssets(); + ActivityAssets const& GetAssets() const; + ActivityParty& GetParty(); + ActivityParty const& GetParty() const; + ActivitySecrets& GetSecrets(); + ActivitySecrets const& GetSecrets() const; + void SetInstance(bool instance); + bool GetInstance() const; + +private: + DiscordActivity internal_; +}; + +class Presence final { +public: + void SetStatus(Status status); + Status GetStatus() const; + Activity& GetActivity(); + Activity const& GetActivity() const; + +private: + DiscordPresence internal_; +}; + +class Relationship final { +public: + void SetType(RelationshipType type); + RelationshipType GetType() const; + User& GetUser(); + User const& GetUser() const; + Presence& GetPresence(); + Presence const& GetPresence() const; + +private: + DiscordRelationship internal_; +}; + +class Lobby final { +public: + void SetId(LobbyId id); + LobbyId GetId() const; + void SetType(LobbyType type); + LobbyType GetType() const; + void SetOwnerId(UserId ownerId); + UserId GetOwnerId() const; + void SetSecret(LobbySecret secret); + LobbySecret GetSecret() const; + void SetCapacity(std::uint32_t capacity); + std::uint32_t GetCapacity() const; + void SetLocked(bool locked); + bool GetLocked() const; + +private: + DiscordLobby internal_; +}; + +class FileStat final { +public: + void SetFilename(char const* filename); + char const* GetFilename() const; + void SetSize(std::uint64_t size); + std::uint64_t GetSize() const; + void SetLastModified(std::uint64_t lastModified); + std::uint64_t GetLastModified() const; + +private: + DiscordFileStat internal_; +}; + +class Entitlement final { +public: + void SetId(Snowflake id); + Snowflake GetId() const; + void SetType(EntitlementType type); + EntitlementType GetType() const; + void SetSkuId(Snowflake skuId); + Snowflake GetSkuId() const; + +private: + DiscordEntitlement internal_; +}; + +class SkuPrice final { +public: + void SetAmount(std::uint32_t amount); + std::uint32_t GetAmount() const; + void SetCurrency(char const* currency); + char const* GetCurrency() const; + +private: + DiscordSkuPrice internal_; +}; + +class Sku final { +public: + void SetId(Snowflake id); + Snowflake GetId() const; + void SetType(SkuType type); + SkuType GetType() const; + void SetName(char const* name); + char const* GetName() const; + SkuPrice& GetPrice(); + SkuPrice const& GetPrice() const; + +private: + DiscordSku internal_; +}; + +class InputMode final { +public: + void SetType(InputModeType type); + InputModeType GetType() const; + void SetShortcut(char const* shortcut); + char const* GetShortcut() const; + +private: + DiscordInputMode internal_; +}; + +class UserAchievement final { +public: + void SetUserId(Snowflake userId); + Snowflake GetUserId() const; + void SetAchievementId(Snowflake achievementId); + Snowflake GetAchievementId() const; + void SetPercentComplete(std::uint8_t percentComplete); + std::uint8_t GetPercentComplete() const; + void SetUnlockedAt(DateTime unlockedAt); + DateTime GetUnlockedAt() const; + +private: + DiscordUserAchievement internal_; +}; + +class LobbyTransaction final { +public: + Result SetType(LobbyType type); + Result SetOwner(UserId ownerId); + Result SetCapacity(std::uint32_t capacity); + Result SetMetadata(MetadataKey key, MetadataValue value); + Result DeleteMetadata(MetadataKey key); + Result SetLocked(bool locked); + + IDiscordLobbyTransaction** Receive() { return &internal_; } + IDiscordLobbyTransaction* Internal() { return internal_; } + +private: + IDiscordLobbyTransaction* internal_; +}; + +class LobbyMemberTransaction final { +public: + Result SetMetadata(MetadataKey key, MetadataValue value); + Result DeleteMetadata(MetadataKey key); + + IDiscordLobbyMemberTransaction** Receive() { return &internal_; } + IDiscordLobbyMemberTransaction* Internal() { return internal_; } + +private: + IDiscordLobbyMemberTransaction* internal_; +}; + +class LobbySearchQuery final { +public: + Result Filter(MetadataKey key, + LobbySearchComparison comparison, + LobbySearchCast cast, + MetadataValue value); + Result Sort(MetadataKey key, LobbySearchCast cast, MetadataValue value); + Result Limit(std::uint32_t limit); + Result Distance(LobbySearchDistance distance); + + IDiscordLobbySearchQuery** Receive() { return &internal_; } + IDiscordLobbySearchQuery* Internal() { return internal_; } + +private: + IDiscordLobbySearchQuery* internal_; +}; + +} // namespace discord diff --git a/depend/discord/user_manager.cpp b/depend/discord/user_manager.cpp new file mode 100644 index 0000000..e704e28 --- /dev/null +++ b/depend/discord/user_manager.cpp @@ -0,0 +1,80 @@ +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "user_manager.h" + +#include "core.h" + +#include +#include + +namespace discord { + +class UserEvents final { +public: + static void OnCurrentUserUpdate(void* callbackData) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->UserManager(); + module.OnCurrentUserUpdate(); + } +}; + +IDiscordUserEvents UserManager::events_{ + &UserEvents::OnCurrentUserUpdate, +}; + +Result UserManager::GetCurrentUser(User* currentUser) +{ + if (!currentUser) { + return Result::InternalError; + } + + auto result = + internal_->get_current_user(internal_, reinterpret_cast(currentUser)); + return static_cast(result); +} + +void UserManager::GetUser(UserId userId, std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result, DiscordUser* user) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result), *reinterpret_cast(user)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->get_user(internal_, userId, cb.release(), wrapper); +} + +Result UserManager::GetCurrentUserPremiumType(PremiumType* premiumType) +{ + if (!premiumType) { + return Result::InternalError; + } + + auto result = internal_->get_current_user_premium_type( + internal_, reinterpret_cast(premiumType)); + return static_cast(result); +} + +Result UserManager::CurrentUserHasFlag(UserFlag flag, bool* hasFlag) +{ + if (!hasFlag) { + return Result::InternalError; + } + + auto result = internal_->current_user_has_flag( + internal_, static_cast(flag), reinterpret_cast(hasFlag)); + return static_cast(result); +} + +} // namespace discord diff --git a/depend/discord/user_manager.h b/depend/discord/user_manager.h new file mode 100644 index 0000000..d85de1b --- /dev/null +++ b/depend/discord/user_manager.h @@ -0,0 +1,31 @@ +#pragma once + +#include "types.h" + +namespace discord { + +class UserManager final { +public: + ~UserManager() = default; + + Result GetCurrentUser(User* currentUser); + void GetUser(UserId userId, std::function callback); + Result GetCurrentUserPremiumType(PremiumType* premiumType); + Result CurrentUserHasFlag(UserFlag flag, bool* hasFlag); + + Event<> OnCurrentUserUpdate; + +private: + friend class Core; + + UserManager() = default; + UserManager(UserManager const& rhs) = delete; + UserManager& operator=(UserManager const& rhs) = delete; + UserManager(UserManager&& rhs) = delete; + UserManager& operator=(UserManager&& rhs) = delete; + + IDiscordUserManager* internal_; + static IDiscordUserEvents events_; +}; + +} // namespace discord diff --git a/depend/discord/voice_manager.cpp b/depend/discord/voice_manager.cpp new file mode 100644 index 0000000..a92d4bd --- /dev/null +++ b/depend/discord/voice_manager.cpp @@ -0,0 +1,124 @@ +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "voice_manager.h" + +#include "core.h" + +#include +#include + +namespace discord { + +class VoiceEvents final { +public: + static void OnSettingsUpdate(void* callbackData) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->VoiceManager(); + module.OnSettingsUpdate(); + } +}; + +IDiscordVoiceEvents VoiceManager::events_{ + &VoiceEvents::OnSettingsUpdate, +}; + +Result VoiceManager::GetInputMode(InputMode* inputMode) +{ + if (!inputMode) { + return Result::InternalError; + } + + auto result = + internal_->get_input_mode(internal_, reinterpret_cast(inputMode)); + return static_cast(result); +} + +void VoiceManager::SetInputMode(InputMode inputMode, std::function callback) +{ + static auto wrapper = [](void* callbackData, EDiscordResult result) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(static_cast(result)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(callback))); + internal_->set_input_mode( + internal_, *reinterpret_cast(&inputMode), cb.release(), wrapper); +} + +Result VoiceManager::IsSelfMute(bool* mute) +{ + if (!mute) { + return Result::InternalError; + } + + auto result = internal_->is_self_mute(internal_, reinterpret_cast(mute)); + return static_cast(result); +} + +Result VoiceManager::SetSelfMute(bool mute) +{ + auto result = internal_->set_self_mute(internal_, (mute ? 1 : 0)); + return static_cast(result); +} + +Result VoiceManager::IsSelfDeaf(bool* deaf) +{ + if (!deaf) { + return Result::InternalError; + } + + auto result = internal_->is_self_deaf(internal_, reinterpret_cast(deaf)); + return static_cast(result); +} + +Result VoiceManager::SetSelfDeaf(bool deaf) +{ + auto result = internal_->set_self_deaf(internal_, (deaf ? 1 : 0)); + return static_cast(result); +} + +Result VoiceManager::IsLocalMute(Snowflake userId, bool* mute) +{ + if (!mute) { + return Result::InternalError; + } + + auto result = internal_->is_local_mute(internal_, userId, reinterpret_cast(mute)); + return static_cast(result); +} + +Result VoiceManager::SetLocalMute(Snowflake userId, bool mute) +{ + auto result = internal_->set_local_mute(internal_, userId, (mute ? 1 : 0)); + return static_cast(result); +} + +Result VoiceManager::GetLocalVolume(Snowflake userId, std::uint8_t* volume) +{ + if (!volume) { + return Result::InternalError; + } + + auto result = + internal_->get_local_volume(internal_, userId, reinterpret_cast(volume)); + return static_cast(result); +} + +Result VoiceManager::SetLocalVolume(Snowflake userId, std::uint8_t volume) +{ + auto result = internal_->set_local_volume(internal_, userId, volume); + return static_cast(result); +} + +} // namespace discord diff --git a/depend/discord/voice_manager.h b/depend/discord/voice_manager.h new file mode 100644 index 0000000..95b20e9 --- /dev/null +++ b/depend/discord/voice_manager.h @@ -0,0 +1,37 @@ +#pragma once + +#include "types.h" + +namespace discord { + +class VoiceManager final { +public: + ~VoiceManager() = default; + + Result GetInputMode(InputMode* inputMode); + void SetInputMode(InputMode inputMode, std::function callback); + Result IsSelfMute(bool* mute); + Result SetSelfMute(bool mute); + Result IsSelfDeaf(bool* deaf); + Result SetSelfDeaf(bool deaf); + Result IsLocalMute(Snowflake userId, bool* mute); + Result SetLocalMute(Snowflake userId, bool mute); + Result GetLocalVolume(Snowflake userId, std::uint8_t* volume); + Result SetLocalVolume(Snowflake userId, std::uint8_t volume); + + Event<> OnSettingsUpdate; + +private: + friend class Core; + + VoiceManager() = default; + VoiceManager(VoiceManager const& rhs) = delete; + VoiceManager& operator=(VoiceManager const& rhs) = delete; + VoiceManager(VoiceManager&& rhs) = delete; + VoiceManager& operator=(VoiceManager&& rhs) = delete; + + IDiscordVoiceManager* internal_; + static IDiscordVoiceEvents events_; +}; + +} // namespace discord diff --git a/depend/lib/discord_game_sdk.lib b/depend/lib/discord_game_sdk.lib new file mode 100644 index 0000000000000000000000000000000000000000..58ec2820f7544ba9fc53a323b07fa23b662e8634 GIT binary patch literal 2358 zcmcIl-EI;=6#jM*io_VAjWl7(J)Qsqyyg`M55% zWiiNUFU6>q0B{{pFMwzUh_!)*Grz~T0I&B+_8BYf?Cn;ntoUYsvr^it?pBy-ck7O8 zvLmBqv99?MjFk^`ebN)3gRZ_~_3c4tIEHu}#-9dKRr@w>m6n6h4QR+qIo` zz$svLkGnl)HCTt7owm`md!N9g>;y|A|!HR2$LV@bZ z7-EP_>~msE{{nM3YGY9TElSf*FdG1JDhr1!ttEo=$e7J05?M)D!PaRjYAf=GT0&PM z7*M;f5PRt)s3{rKdVhSB-uG4D9Sy!nMaTk@8yVX)dPX`Yrxs~&PW`7aL`W8}d@B6% z!i+mKh*Lc2$L$5APKhA6>+u0t4BP5s+)fg6h#r2si6lfiIOx53rAViomPj^Kd}{MFpz=yzr68$RY(*HfVYE&w0QgF z5hK#F%6-Uyp^tWH;r1o|5sj}7YzU1D6()VJy28xMrku7mtdhE-dTjdUWy^C8XA|GY zXd7YEinMb!eU*xkoJ|~;t7FM5Cw`AI_-zTF`!?p*@+0{9xA6x>@XtRSzdzhYO+e)_ z{9GzRj@-soImOxhT`D7f{~zaBuzf@s%uqvR0h_hrNr+SYCFeI;r~5n@q`m#dgRf0! sF_`yWXfH%^ftU{|rb4w=KHBo72@N_ooASBvs81=X%A(memInfo.ullTotalPhys * 1e-6); // Bytes -> MegaBytes + + if (m_bDiscordRPC) + { + RPC::Init(); + } } void Menu::DrawOverlay() @@ -384,6 +390,24 @@ void Menu::ShowPage() } } } + + ImGui::Spacing(); + + ImGui::Columns(2); + if (ImGui::Checkbox(TEXT("Menu.DiscordRPC"), &m_bDiscordRPC)) + { + if (m_bDiscordRPC) + { + RPC::Init(); + } + else + { + RPC::Shutdown(); + } + gConfig.SetValue("menu.discord_rpc", m_bDiscordRPC); + } + ImGui::NextColumn(); + ImGui::Columns(1); ImGui::EndTabItem(); } diff --git a/src/menu.h b/src/menu.h index 5c7f18c..2ac8177 100644 --- a/src/menu.h +++ b/src/menu.h @@ -44,6 +44,7 @@ public: static inline bool m_bShowMenu; static inline char m_nInputBuffer[INPUT_BUFFER_SIZE] = ""; }; + static inline bool m_bDiscordRPC; Menu() = delete; Menu(const Menu&) = delete; diff --git a/src/player.cpp b/src/player.cpp index 91c0857..6f2574d 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -578,7 +578,7 @@ void Player::ShowPage() { ImGui::BeginChild("PlayerMenus"); - Ui::EditReference(TEXT("Player.Armour"), pPlayer->m_fArmour, 0, 100, pInfo->m_nMaxArmour); + Ui::EditReference(TEXT("Player.Armour"), pPlayer->m_fArmour, 0, 100, BY_GAME(pInfo->m_nMaxArmour, pInfo->m_nMaxArmour, 100)); #ifdef GTASA if (ImGui::CollapsingHeader(TEXT("Player.Body"))) { diff --git a/src/rpc.cpp b/src/rpc.cpp new file mode 100644 index 0000000..58b0f90 --- /dev/null +++ b/src/rpc.cpp @@ -0,0 +1,123 @@ +#include "pch.h" +#include "rpc.h" +#include "util.h" +#include "menu.h" +#include "vehicle.h" +#include "cheatmenu.h" + +char asciitolower(char in) +{ + if (in <= 'Z' && in >= 'A') + return in - ('Z' - 'z'); + return in; +} + +void RPC::Shutdown() +{ +} + +void RPC::Init() +{ + discord::Result result = discord::Core::Create(951199292981403669, DiscordCreateFlags_Default, &pCore); + bInit = result == discord::Result::Ok; +} + +void RPC::Process() +{ + if (!Menu::m_bDiscordRPC) + { + return; + } + + static std::string detailsText, stateText, smallImg, smallImgText, largeImg, largeImgText; + static size_t curImage = 1; + static size_t timer = 0; + static size_t startTime = CTimer::m_snTimeInMilliseconds; + + CPlayerInfo *pInfo = &CWorld::Players[CWorld::PlayerInFocus]; + CPlayerPed *pPed = pInfo->m_pPed; + + if (pPed) + { + size_t curTimer = CTimer::m_snTimeInMilliseconds; + size_t wantedLevel = pPed->m_pWanted->m_nWantedLevel; + if (wantedLevel > 0) + { + detailsText = std::format("{}: ", TEXT("Player.WantedLevel")); + for (size_t i = 0; i < wantedLevel; ++i) + { + detailsText += "☆"; + } + } + else + { + detailsText = std::format("{}: ${}", TEXT("Player.Money"), pInfo->m_nMoney); + } + + if (BY_GAME(pPed->m_nPedFlags.bInVehicle, pPed->m_bInVehicle, pPed->m_bInVehicle)) + { + std::string name = Vehicle::GetNameFromModel(pPed->m_pVehicle->m_nModelIndex); + std::transform(name.begin(), name.end(), name.begin(), asciitolower); + smallImgText = std::format("{} {} {} {}", TEXT("RPC.Driving"), name, TEXT("RPC.In"), Util::GetLocationName(&pPed->GetPosition())); + smallImg = "drive"; + } + else + { + smallImg = "walk"; + smallImgText = std::format("{} {} {}", TEXT("RPC.Walking"), TEXT("RPC.In"), Util::GetLocationName(&pPed->GetPosition())); + } + + size_t seconds = curTimer - startTime; + size_t minutes = (seconds / 60) % 60; + size_t hours = (minutes / 60) % 60; + stateText = std::format(TEXT("RPC.PlayingFor"), hours, minutes, seconds); + + if (BY_GAME(Util::IsOnMission(), false, false)) + { + stateText = TEXT("RPC.DoingMission"); + } + + if (CheatMenu::IsMenuShown()) + { + stateText = TEXT("RPC.BrowsingCheatMenu"); + } + + if (BY_GAME(FrontEndMenuManager.m_bMenuActive, FrontendMenuManager.m_bMenuVisible, FrontEndMenuManager.m_bMenuActive)) + { + stateText = TEXT("RPC.InsideMenus"); + } + + largeImgText = std::format("{}: {} / {} {}: {} / {}", TEXT("Player.Armour"), pPed->m_fArmour, BY_GAME(pInfo->m_nMaxArmour, pInfo->m_nMaxArmour, 100), TEXT("Player.Health"), pPed->m_fHealth, BY_GAME(pPed->m_fMaxHealth, 100, 100)); + largeImg = std::format("{}{}", BY_GAME("sa", "vc", "3"), curImage); + + discord::Activity activity{}; + activity.SetDetails(detailsText.c_str()); + activity.SetState(stateText.c_str()); + activity.GetAssets().SetSmallImage(smallImg.c_str()); + activity.GetAssets().SetSmallText(smallImgText.c_str()); + activity.GetAssets().SetLargeImage(largeImg.c_str()); + activity.GetAssets().SetLargeText(largeImgText.c_str()); + + activity.SetType(discord::ActivityType::Playing); + pCore->ActivityManager().UpdateActivity(activity, + [](discord::Result result) + { + if (result != discord::Result::Ok) + { + gLog << "Failed to set discord activity!" << std::endl; + } + }); + pCore->RunCallbacks(); + + if (curTimer - timer > 10000) + { + curImage++; + + if (curImage > totalLargeImages) + { + curImage = 1; + } + timer = curTimer; + } + } +} \ No newline at end of file diff --git a/src/rpc.h b/src/rpc.h new file mode 100644 index 0000000..4f44951 --- /dev/null +++ b/src/rpc.h @@ -0,0 +1,18 @@ +#pragma once +#include "../depend/discord/discord.h" + +class RPC +{ +private: + static inline discord::Core* pCore; + static inline bool bInit = false; + static inline size_t totalLargeImages = 5; + +public: + RPC() = delete; + RPC(RPC&) = delete; + + static void Init(); + static void Process(); + static void Shutdown(); +}; \ No newline at end of file diff --git a/src/version.h b/src/version.h index 77e77b1..a4597d7 100644 --- a/src/version.h +++ b/src/version.h @@ -2,5 +2,5 @@ #define MENU_NAME "Cheat Menu" #define MENU_VERSION_NUMBER "3.2" #define MENU_VERSION MENU_VERSION_NUMBER"-beta" -#define BUILD_NUMBER "20220304" +#define BUILD_NUMBER "20220306" #define MENU_TITLE MENU_NAME " v" MENU_VERSION diff --git a/tools/premake5.lua b/tools/premake5.lua index f52fba2..534b2d4 100644 --- a/tools/premake5.lua +++ b/tools/premake5.lua @@ -30,16 +30,28 @@ workspace "CheatMenu" location "../build" targetdir "../build/bin" -project "Depend" + links { + "d3d9", + "d3d11", + "Pdh", + "urlmon", + "depend", + "discord_game_sdk" + } + +project "depend" kind "StaticLib" files { - "../depned/**.h", + "../depend/**.h", "../depend/**.hpp", "../depend/**.c", "../depend/**.cpp" } - libdirs (PSDK_DIR .. "/output/lib") + libdirs { + PSDK_DIR .. "/output/lib", + "../depend/lib" + } filter "configurations:Debug" defines { "DEBUG", "IS_PLATFORM_WIN" } @@ -108,7 +120,6 @@ project "CheatMenuIII" libdirs (PSDK_DIR .. "/output/lib") defines { - "NDEBUG", "IS_PLATFORM_WIN" , "_CRT_SECURE_NO_WARNINGS", "_CRT_NON_CONFORMING_SWPRINTFS", @@ -123,24 +134,14 @@ project "CheatMenuIII" filter "configurations:Debug" symbols "On" links { - "Depend", - "d3d9", - "d3d11", - "XInput9_1_0", - "Pdh", - "urlmon", + "depend", "plugin_III_d.lib" } filter "configurations:Release" optimize "On" links { - "Depend", - "d3d9", - "d3d11", - "XInput9_1_0", - "Pdh", - "urlmon", + "depend", "plugin_III.lib" } @@ -202,7 +203,6 @@ project "CheatMenuVC" libdirs (PSDK_DIR .. "/output/lib") defines { - "NDEBUG", "IS_PLATFORM_WIN" , "_CRT_SECURE_NO_WARNINGS", "_CRT_NON_CONFORMING_SWPRINTFS", @@ -217,24 +217,14 @@ project "CheatMenuVC" filter "configurations:Debug" symbols "On" links { - "Depend", - "d3d9", - "d3d11", - "XInput9_1_0", - "Pdh", - "urlmon", + "depend", "plugin_vc_d.lib" } filter "configurations:Release" optimize "On" links { - "Depend", - "d3d9", - "d3d11", - "XInput9_1_0", - "Pdh", - "urlmon", + "depend", "plugin_vc.lib" } @@ -253,10 +243,12 @@ project "CheatMenuSA" PSDK_DIR .. "/shared/", PSDK_DIR .. "/shared/game/" } - libdirs (PSDK_DIR .. "/output/lib") + libdirs { + PSDK_DIR .. "/output/lib", + "../depend/lib" + } defines { - "NDEBUG", "IS_PLATFORM_WIN" , "_CRT_SECURE_NO_WARNINGS", "_CRT_NON_CONFORMING_SWPRINTFS", @@ -271,24 +263,14 @@ project "CheatMenuSA" filter "configurations:Debug" symbols "On" links { - "Depend", - "d3d9", - "d3d11", - "XInput9_1_0", - "Pdh", - "urlmon", - "plugin_d.lib" + "depend", + "plugin_d.lib", } filter "configurations:Release" optimize "On" links { - "Depend", - "d3d9", - "d3d11", - "XInput9_1_0", - "Pdh", - "urlmon", - "plugin.lib" + "depend", + "plugin.lib", } \ No newline at end of file