From 62fdc45d3f2bf3a676971977f594e73fb8fe2eff Mon Sep 17 00:00:00 2001 From: str1k3r <115313679+S1l3ntStr1ke87@users.noreply.github.com> Date: Thu, 21 May 2026 23:11:34 -0400 Subject: [PATCH] Feat: update to Game SDK, add Discord Login This is honestly shitty code that works imo --- Minecraft.Client/CMakeLists.txt | 1 + .../Windows64/ExtraLibs/discordrpc/backoff.h | 40 - .../ExtraLibs/discordrpc/connection.h | 19 - .../ExtraLibs/discordrpc/connection_win.cpp | 128 -- .../ExtraLibs/discordrpc/discord_register.h | 26 - .../discordrpc/discord_register_win.cpp | 186 --- .../ExtraLibs/discordrpc/discord_rpc.cpp | 504 -------- .../ExtraLibs/discordrpc/discord_rpc.h | 94 -- .../ExtraLibs/discordrpc/dllmain.cpp | 8 - .../ExtraLibs/discordrpc/msg_queue.h | 36 - .../ExtraLibs/discordrpc/rpc_connection.cpp | 137 -- .../ExtraLibs/discordrpc/rpc_connection.h | 59 - .../ExtraLibs/discordrpc/serialization.cpp | 270 ---- .../ExtraLibs/discordrpc/serialization.h | 215 ---- .../discordsdk/achievement_manager.cpp | 99 ++ .../discordsdk/achievement_manager.h | 34 + .../ExtraLibs/discordsdk/activity_manager.cpp | 177 +++ .../ExtraLibs/discordsdk/activity_manager.h | 42 + .../discordsdk/application_manager.cpp | 78 ++ .../discordsdk/application_manager.h | 30 + .../Windows64/ExtraLibs/discordsdk/core.cpp | 182 +++ .../Windows64/ExtraLibs/discordsdk/core.h | 64 + .../Windows64/ExtraLibs/discordsdk/discord.h | 16 + .../discordsdk/discord_game_sdk.dll.lib | Bin 0 -> 2352 bytes .../Windows64/ExtraLibs/discordsdk/event.h | 59 + .../Windows64/ExtraLibs/discordsdk/ffi.h | 1113 +++++++++++++++++ .../ExtraLibs/discordsdk/image_manager.cpp | 57 + .../ExtraLibs/discordsdk/image_manager.h | 28 + .../ExtraLibs/discordsdk/lobby_manager.cpp | 554 ++++++++ .../ExtraLibs/discordsdk/lobby_manager.h | 88 ++ .../ExtraLibs/discordsdk/network_manager.cpp | 103 ++ .../ExtraLibs/discordsdk/network_manager.h | 63 + .../ExtraLibs/discordsdk/overlay_manager.cpp | 229 ++++ .../ExtraLibs/discordsdk/overlay_manager.h | 57 + .../discordsdk/relationship_manager.cpp | 91 ++ .../discordsdk/relationship_manager.h | 32 + .../ExtraLibs/discordsdk/storage_manager.cpp | 158 +++ .../ExtraLibs/discordsdk/storage_manager.h | 46 + .../ExtraLibs/discordsdk/store_manager.cpp | 162 +++ .../ExtraLibs/discordsdk/store_manager.h | 38 + .../Windows64/ExtraLibs/discordsdk/types.cpp | 879 +++++++++++++ .../Windows64/ExtraLibs/discordsdk/types.h | 567 +++++++++ .../ExtraLibs/discordsdk/user_manager.cpp | 80 ++ .../ExtraLibs/discordsdk/user_manager.h | 31 + .../ExtraLibs/discordsdk/voice_manager.cpp | 124 ++ .../ExtraLibs/discordsdk/voice_manager.h | 37 + .../Windows64/Windows64_Launcher.cpp | 220 +++- .../Windows64/Windows64_Launcher.h | 7 +- Minecraft.Client/cmake/sources/Windows.cmake | 26 +- 49 files changed, 5494 insertions(+), 1800 deletions(-) delete mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordrpc/backoff.h delete mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordrpc/connection.h delete mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordrpc/connection_win.cpp delete mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordrpc/discord_register.h delete mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordrpc/discord_register_win.cpp delete mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordrpc/discord_rpc.cpp delete mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordrpc/discord_rpc.h delete mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordrpc/dllmain.cpp delete mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordrpc/msg_queue.h delete mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordrpc/rpc_connection.cpp delete mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordrpc/rpc_connection.h delete mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordrpc/serialization.cpp delete mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordrpc/serialization.h create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/achievement_manager.cpp create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/achievement_manager.h create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/activity_manager.cpp create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/activity_manager.h create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/application_manager.cpp create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/application_manager.h create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/core.cpp create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/core.h create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/discord.h create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/discord_game_sdk.dll.lib create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/event.h create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/ffi.h create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/image_manager.cpp create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/image_manager.h create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/lobby_manager.cpp create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/lobby_manager.h create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/network_manager.cpp create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/network_manager.h create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/overlay_manager.cpp create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/overlay_manager.h create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/relationship_manager.cpp create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/relationship_manager.h create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/storage_manager.cpp create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/storage_manager.h create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/store_manager.cpp create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/store_manager.h create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/types.cpp create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/types.h create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/user_manager.cpp create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/user_manager.h create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/voice_manager.cpp create mode 100644 Minecraft.Client/Windows64/ExtraLibs/discordsdk/voice_manager.h diff --git a/Minecraft.Client/CMakeLists.txt b/Minecraft.Client/CMakeLists.txt index 2ce219d3..89ca1879 100644 --- a/Minecraft.Client/CMakeLists.txt +++ b/Minecraft.Client/CMakeLists.txt @@ -60,6 +60,7 @@ target_link_libraries(Minecraft.Client PRIVATE 4JLibs.${PLATFORM_NAME}.Profile 4JLibs.${PLATFORM_NAME}.Storage 4JLibs.${PLATFORM_NAME}.Render + $<$:${CMAKE_CURRENT_SOURCE_DIR}/Windows64/ExtraLibs/discordsdk/discord_game_sdk.dll.lib> ) # Iggy libs diff --git a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/backoff.h b/Minecraft.Client/Windows64/ExtraLibs/discordrpc/backoff.h deleted file mode 100644 index a47d622e..00000000 --- a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/backoff.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -struct Backoff { - int64_t minAmount; - int64_t maxAmount; - int64_t current; - int fails; - std::mt19937_64 randGenerator; - std::uniform_real_distribution<> randDistribution; - - double rand01() { return randDistribution(randGenerator); } - - Backoff(int64_t min, int64_t max) - : minAmount(min) - , maxAmount(max) - , current(min) - , fails(0) - , randGenerator((uint64_t)time(0)) - { - } - - void reset() - { - fails = 0; - current = minAmount; - } - - int64_t nextDelay() - { - ++fails; - int64_t delay = (int64_t)((double)current * 2.0 * rand01()); - current = (std::min)(current + delay, maxAmount); - return current; - } -}; diff --git a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/connection.h b/Minecraft.Client/Windows64/ExtraLibs/discordrpc/connection.h deleted file mode 100644 index a8f99b9f..00000000 --- a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/connection.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -// This is to wrap the platform specific kinds of connect/read/write. - -#include -#include - -// not really connectiony, but need per-platform -int GetProcessId(); - -struct BaseConnection { - static BaseConnection* Create(); - static void Destroy(BaseConnection*&); - bool isOpen{false}; - bool Open(); - bool Close(); - bool Write(const void* data, size_t length); - bool Read(void* data, size_t length); -}; diff --git a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/connection_win.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordrpc/connection_win.cpp deleted file mode 100644 index 2dd2750c..00000000 --- a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/connection_win.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include "connection.h" - -#define WIN32_LEAN_AND_MEAN -#define NOMCX -#define NOSERVICE -#define NOIME -#include -#include - -int GetProcessId() -{ - return (int)::GetCurrentProcessId(); -} - -struct BaseConnectionWin : public BaseConnection { - HANDLE pipe{INVALID_HANDLE_VALUE}; -}; - -static BaseConnectionWin Connection; - -/*static*/ BaseConnection* BaseConnection::Create() -{ - return &Connection; -} - -/*static*/ void BaseConnection::Destroy(BaseConnection*& c) -{ - auto self = reinterpret_cast(c); - self->Close(); - c = nullptr; -} - -bool BaseConnection::Open() -{ - wchar_t pipeName[]{L"\\\\?\\pipe\\discord-ipc-0"}; - const size_t pipeDigit = sizeof(pipeName) / sizeof(wchar_t) - 2; - pipeName[pipeDigit] = L'0'; - auto self = reinterpret_cast(this); - for (;;) { - self->pipe = ::CreateFileW( - pipeName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); - if (self->pipe != INVALID_HANDLE_VALUE) { - self->isOpen = true; - return true; - } - - auto lastError = GetLastError(); - if (lastError == ERROR_FILE_NOT_FOUND) { - if (pipeName[pipeDigit] < L'9') { - pipeName[pipeDigit]++; - continue; - } - } - else if (lastError == ERROR_PIPE_BUSY) { - if (!WaitNamedPipeW(pipeName, 10000)) { - return false; - } - continue; - } - return false; - } -} - -bool BaseConnection::Close() -{ - auto self = reinterpret_cast(this); - ::CloseHandle(self->pipe); - self->pipe = INVALID_HANDLE_VALUE; - self->isOpen = false; - return true; -} - -bool BaseConnection::Write(const void* data, size_t length) -{ - if (length == 0) { - return true; - } - auto self = reinterpret_cast(this); - assert(self); - if (!self) { - return false; - } - if (self->pipe == INVALID_HANDLE_VALUE) { - return false; - } - assert(data); - if (!data) { - return false; - } - const DWORD bytesLength = (DWORD)length; - DWORD bytesWritten = 0; - return ::WriteFile(self->pipe, data, bytesLength, &bytesWritten, nullptr) == TRUE && - bytesWritten == bytesLength; -} - -bool BaseConnection::Read(void* data, size_t length) -{ - assert(data); - if (!data) { - return false; - } - auto self = reinterpret_cast(this); - assert(self); - if (!self) { - return false; - } - if (self->pipe == INVALID_HANDLE_VALUE) { - return false; - } - DWORD bytesAvailable = 0; - if (::PeekNamedPipe(self->pipe, nullptr, 0, nullptr, &bytesAvailable, nullptr)) { - if (bytesAvailable >= length) { - DWORD bytesToRead = (DWORD)length; - DWORD bytesRead = 0; - if (::ReadFile(self->pipe, data, bytesToRead, &bytesRead, nullptr) == TRUE) { - assert(bytesToRead == bytesRead); - return true; - } - else { - Close(); - } - } - } - else { - Close(); - } - return false; -} diff --git a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/discord_register.h b/Minecraft.Client/Windows64/ExtraLibs/discordrpc/discord_register.h deleted file mode 100644 index 16fb42f3..00000000 --- a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/discord_register.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#if defined(DISCORD_DYNAMIC_LIB) -#if defined(_WIN32) -#if defined(DISCORD_BUILDING_SDK) -#define DISCORD_EXPORT __declspec(dllexport) -#else -#define DISCORD_EXPORT __declspec(dllimport) -#endif -#else -#define DISCORD_EXPORT __attribute__((visibility("default"))) -#endif -#else -#define DISCORD_EXPORT -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command); -DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, const char* steamId); - -#ifdef __cplusplus -} -#endif diff --git a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/discord_register_win.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordrpc/discord_register_win.cpp deleted file mode 100644 index 0b1c4a13..00000000 --- a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/discord_register_win.cpp +++ /dev/null @@ -1,186 +0,0 @@ -#include "discord_rpc.h" -#include "discord_register.h" - -#define WIN32_LEAN_AND_MEAN -#define NOMCX -#define NOSERVICE -#define NOIME -#include -#include -#include - -/** - * Updated fixes for MinGW and WinXP - * This block is written the way it does not involve changing the rest of the code - * Checked to be compiling - * 1) strsafe.h belongs to Windows SDK and cannot be added to MinGW - * #include guarded, functions redirected to substitutes - * 2) RegSetKeyValueW and LSTATUS are not declared in - * The entire function is rewritten - */ -#ifdef __MINGW32__ -#include -/// strsafe.h fixes -static HRESULT StringCbPrintfW(LPWSTR pszDest, size_t cbDest, LPCWSTR pszFormat, ...) -{ - HRESULT ret; - va_list va; - va_start(va, pszFormat); - cbDest /= 2; // Size is divided by 2 to convert from bytes to wide characters - causes segfault - // othervise - ret = vsnwprintf(pszDest, cbDest, pszFormat, va); - pszDest[cbDest - 1] = 0; // Terminate the string in case a buffer overflow; -1 will be returned - va_end(va); - return ret; -} -#else -#include -#include -#endif // __MINGW32__ - -/// winreg.h fixes -#ifndef LSTATUS -#define LSTATUS LONG -#endif -#ifdef RegSetKeyValueW -#undefine RegSetKeyValueW -#endif -#define RegSetKeyValueW regset -static LSTATUS regset(HKEY hkey, - LPCWSTR subkey, - LPCWSTR name, - DWORD type, - const void* data, - DWORD len) -{ - HKEY htkey = hkey, hsubkey = nullptr; - LSTATUS ret; - if (subkey && subkey[0]) { - if ((ret = RegCreateKeyExW(hkey, subkey, 0, 0, 0, KEY_ALL_ACCESS, 0, &hsubkey, 0)) != - ERROR_SUCCESS) - return ret; - htkey = hsubkey; - } - ret = RegSetValueExW(htkey, name, 0, type, (const BYTE*)data, len); - if (hsubkey && hsubkey != hkey) - RegCloseKey(hsubkey); - return ret; -} - -static void Discord_RegisterW(const wchar_t* applicationId, const wchar_t* command) -{ - // https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx - // we want to register games so we can run them as discord-:// - // Update the HKEY_CURRENT_USER, because it doesn't seem to require special permissions. - - wchar_t exeFilePath[MAX_PATH]; - DWORD exeLen = GetModuleFileNameW(nullptr, exeFilePath, MAX_PATH); - wchar_t openCommand[1024]; - - if (command && command[0]) { - StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", command); - } - else { - // StringCbCopyW(openCommand, sizeof(openCommand), exeFilePath); - StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", exeFilePath); - } - - wchar_t protocolName[64]; - StringCbPrintfW(protocolName, sizeof(protocolName), L"discord-%s", applicationId); - wchar_t protocolDescription[128]; - StringCbPrintfW( - protocolDescription, sizeof(protocolDescription), L"URL:Run game %s protocol", applicationId); - wchar_t urlProtocol = 0; - - wchar_t keyName[256]; - StringCbPrintfW(keyName, sizeof(keyName), L"Software\\Classes\\%s", protocolName); - HKEY key; - auto status = - RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, nullptr, 0, KEY_WRITE, nullptr, &key, nullptr); - if (status != ERROR_SUCCESS) { - fprintf(stderr, "Error creating key\n"); - return; - } - DWORD len; - LSTATUS result; - len = (DWORD)lstrlenW(protocolDescription) + 1; - result = - RegSetKeyValueW(key, nullptr, nullptr, REG_SZ, protocolDescription, len * sizeof(wchar_t)); - if (FAILED(result)) { - fprintf(stderr, "Error writing description\n"); - } - - len = (DWORD)lstrlenW(protocolDescription) + 1; - result = RegSetKeyValueW(key, nullptr, L"URL Protocol", REG_SZ, &urlProtocol, sizeof(wchar_t)); - if (FAILED(result)) { - fprintf(stderr, "Error writing description\n"); - } - - result = RegSetKeyValueW( - key, L"DefaultIcon", nullptr, REG_SZ, exeFilePath, (exeLen + 1) * sizeof(wchar_t)); - if (FAILED(result)) { - fprintf(stderr, "Error writing icon\n"); - } - - len = (DWORD)lstrlenW(openCommand) + 1; - result = RegSetKeyValueW( - key, L"shell\\open\\command", nullptr, REG_SZ, openCommand, len * sizeof(wchar_t)); - if (FAILED(result)) { - fprintf(stderr, "Error writing command\n"); - } - RegCloseKey(key); -} - -extern "C" DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command) -{ - wchar_t appId[32]; - MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32); - - wchar_t openCommand[1024]; - const wchar_t* wcommand = nullptr; - if (command && command[0]) { - const auto commandBufferLen = sizeof(openCommand) / sizeof(*openCommand); - MultiByteToWideChar(CP_UTF8, 0, command, -1, openCommand, commandBufferLen); - wcommand = openCommand; - } - - Discord_RegisterW(appId, wcommand); -} - -extern "C" DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, - const char* steamId) -{ - wchar_t appId[32]; - MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32); - - wchar_t wSteamId[32]; - MultiByteToWideChar(CP_UTF8, 0, steamId, -1, wSteamId, 32); - - HKEY key; - auto status = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", 0, KEY_READ, &key); - if (status != ERROR_SUCCESS) { - fprintf(stderr, "Error opening Steam key\n"); - return; - } - - wchar_t steamPath[MAX_PATH]; - DWORD pathBytes = sizeof(steamPath); - status = RegQueryValueExW(key, L"SteamExe", nullptr, nullptr, (BYTE*)steamPath, &pathBytes); - RegCloseKey(key); - if (status != ERROR_SUCCESS || pathBytes < 1) { - fprintf(stderr, "Error reading SteamExe key\n"); - return; - } - - DWORD pathChars = pathBytes / sizeof(wchar_t); - for (DWORD i = 0; i < pathChars; ++i) { - if (steamPath[i] == L'/') { - steamPath[i] = L'\\'; - } - } - - wchar_t command[1024]; - StringCbPrintfW(command, sizeof(command), L"\"%s\" steam://rungameid/%s", steamPath, wSteamId); - - Discord_RegisterW(appId, command); -} diff --git a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/discord_rpc.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordrpc/discord_rpc.cpp deleted file mode 100644 index 03924538..00000000 --- a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/discord_rpc.cpp +++ /dev/null @@ -1,504 +0,0 @@ -#include "discord_rpc.h" - -#include "backoff.h" -#include "discord_register.h" -#include "msg_queue.h" -#include "rpc_connection.h" -#include "serialization.h" - -#include -#include -#include - -#ifndef DISCORD_DISABLE_IO_THREAD -#include -#include -#endif - -constexpr size_t MaxMessageSize{16 * 1024}; -constexpr size_t MessageQueueSize{8}; -constexpr size_t JoinQueueSize{8}; - -struct QueuedMessage { - size_t length; - char buffer[MaxMessageSize]; - - void Copy(const QueuedMessage& other) - { - length = other.length; - if (length) { - memcpy(buffer, other.buffer, length); - } - } -}; - -struct User { - // snowflake (64bit int), turned into a ascii decimal string, at most 20 chars +1 null - // terminator = 21 - char userId[32]; - // 32 unicode glyphs is max name size => 4 bytes per glyph in the worst case, +1 for null - // terminator = 129 - char username[344]; - // 4 decimal digits + 1 null terminator = 5 - char discriminator[8]; - // optional 'a_' + md5 hex digest (32 bytes) + null terminator = 35 - char avatar[128]; - // Rounded way up because I'm paranoid about games breaking from future changes in these sizes -}; - -static RpcConnection* Connection{nullptr}; -static DiscordEventHandlers QueuedHandlers{}; -static DiscordEventHandlers Handlers{}; -static std::atomic_bool WasJustConnected{false}; -static std::atomic_bool WasJustDisconnected{false}; -static std::atomic_bool GotErrorMessage{false}; -static std::atomic_bool WasJoinGame{false}; -static std::atomic_bool WasSpectateGame{false}; -static std::atomic_bool UpdatePresence{false}; -static char JoinGameSecret[256]; -static char SpectateGameSecret[256]; -static int LastErrorCode{0}; -static char LastErrorMessage[256]; -static int LastDisconnectErrorCode{0}; -static char LastDisconnectErrorMessage[256]; -static std::mutex PresenceMutex; -static std::mutex HandlerMutex; -static QueuedMessage QueuedPresence{}; -static MsgQueue SendQueue; -static MsgQueue JoinAskQueue; -static User connectedUser; - -// We want to auto connect, and retry on failure, but not as fast as possible. This does expoential -// backoff from 0.5 seconds to 1 minute -static Backoff ReconnectTimeMs(500, 60 * 1000); -static auto NextConnect = std::chrono::system_clock::now(); -static int Pid{0}; -static int Nonce{1}; - -#ifndef DISCORD_DISABLE_IO_THREAD -static void Discord_UpdateConnection(void); -class IoThreadHolder { -private: - std::atomic_bool keepRunning{true}; - std::mutex waitForIOMutex; - std::condition_variable waitForIOActivity; - std::thread ioThread; - -public: - void Start() - { - keepRunning.store(true); - ioThread = std::thread([&]() { - const std::chrono::duration maxWait{500LL}; - Discord_UpdateConnection(); - while (keepRunning.load()) { - std::unique_lock lock(waitForIOMutex); - waitForIOActivity.wait_for(lock, maxWait); - Discord_UpdateConnection(); - } - }); - } - - void Notify() { waitForIOActivity.notify_all(); } - - void Stop() - { - keepRunning.exchange(false); - Notify(); - if (ioThread.joinable()) { - ioThread.join(); - } - } - - ~IoThreadHolder() { Stop(); } -}; -#else -class IoThreadHolder { -public: - void Start() {} - void Stop() {} - void Notify() {} -}; -#endif // DISCORD_DISABLE_IO_THREAD -static IoThreadHolder* IoThread{nullptr}; - -static void UpdateReconnectTime() -{ - NextConnect = std::chrono::system_clock::now() + - std::chrono::duration{ReconnectTimeMs.nextDelay()}; -} - -#ifdef DISCORD_DISABLE_IO_THREAD -extern "C" DISCORD_EXPORT void Discord_UpdateConnection(void) -#else -static void Discord_UpdateConnection(void) -#endif -{ - if (!Connection) { - return; - } - - if (!Connection->IsOpen()) { - if (std::chrono::system_clock::now() >= NextConnect) { - UpdateReconnectTime(); - Connection->Open(); - } - } - else { - // reads - - for (;;) { - JsonDocument message; - - if (!Connection->Read(message)) { - break; - } - - const char* evtName = GetStrMember(&message, "evt"); - const char* nonce = GetStrMember(&message, "nonce"); - - if (nonce) { - // in responses only -- should use to match up response when needed. - - if (evtName && strcmp(evtName, "ERROR") == 0) { - auto data = GetObjMember(&message, "data"); - LastErrorCode = GetIntMember(data, "code"); - StringCopy(LastErrorMessage, GetStrMember(data, "message", "")); - GotErrorMessage.store(true); - } - } - else { - // should have evt == name of event, optional data - if (evtName == nullptr) { - continue; - } - - auto data = GetObjMember(&message, "data"); - - if (strcmp(evtName, "ACTIVITY_JOIN") == 0) { - auto secret = GetStrMember(data, "secret"); - if (secret) { - StringCopy(JoinGameSecret, secret); - WasJoinGame.store(true); - } - } - else if (strcmp(evtName, "ACTIVITY_SPECTATE") == 0) { - auto secret = GetStrMember(data, "secret"); - if (secret) { - StringCopy(SpectateGameSecret, secret); - WasSpectateGame.store(true); - } - } - else if (strcmp(evtName, "ACTIVITY_JOIN_REQUEST") == 0) { - auto user = GetObjMember(data, "user"); - auto userId = GetStrMember(user, "id"); - auto username = GetStrMember(user, "username"); - auto avatar = GetStrMember(user, "avatar"); - auto joinReq = JoinAskQueue.GetNextAddMessage(); - if (userId && username && joinReq) { - StringCopy(joinReq->userId, userId); - StringCopy(joinReq->username, username); - auto discriminator = GetStrMember(user, "discriminator"); - if (discriminator) { - StringCopy(joinReq->discriminator, discriminator); - } - if (avatar) { - StringCopy(joinReq->avatar, avatar); - } - else { - joinReq->avatar[0] = 0; - } - JoinAskQueue.CommitAdd(); - } - } - } - } - - // writes - if (UpdatePresence.exchange(false) && QueuedPresence.length) { - QueuedMessage local; - { - std::lock_guard guard(PresenceMutex); - local.Copy(QueuedPresence); - } - if (!Connection->Write(local.buffer, local.length)) { - // if we fail to send, requeue - std::lock_guard guard(PresenceMutex); - QueuedPresence.Copy(local); - UpdatePresence.exchange(true); - } - } - - while (SendQueue.HavePendingSends()) { - auto qmessage = SendQueue.GetNextSendMessage(); - Connection->Write(qmessage->buffer, qmessage->length); - SendQueue.CommitSend(); - } - } -} - -static void SignalIOActivity() -{ - if (IoThread != nullptr) { - IoThread->Notify(); - } -} - -static bool RegisterForEvent(const char* evtName) -{ - auto qmessage = SendQueue.GetNextAddMessage(); - if (qmessage) { - qmessage->length = - JsonWriteSubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName); - SendQueue.CommitAdd(); - SignalIOActivity(); - return true; - } - return false; -} - -static bool DeregisterForEvent(const char* evtName) -{ - auto qmessage = SendQueue.GetNextAddMessage(); - if (qmessage) { - qmessage->length = - JsonWriteUnsubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName); - SendQueue.CommitAdd(); - SignalIOActivity(); - return true; - } - return false; -} - -extern "C" DISCORD_EXPORT void Discord_Initialize(const char* applicationId, - DiscordEventHandlers* handlers, - int autoRegister, - const char* optionalSteamId) -{ - IoThread = new (std::nothrow) IoThreadHolder(); - if (IoThread == nullptr) { - return; - } - - if (autoRegister) { - if (optionalSteamId && optionalSteamId[0]) { - Discord_RegisterSteamGame(applicationId, optionalSteamId); - } - else { - Discord_Register(applicationId, nullptr); - } - } - - Pid = GetProcessId(); - - { - std::lock_guard guard(HandlerMutex); - - if (handlers) { - QueuedHandlers = *handlers; - } - else { - QueuedHandlers = {}; - } - - Handlers = {}; - } - - if (Connection) { - return; - } - - Connection = RpcConnection::Create(applicationId); - Connection->onConnect = [](JsonDocument& readyMessage) { - Discord_UpdateHandlers(&QueuedHandlers); - if (QueuedPresence.length > 0) { - UpdatePresence.exchange(true); - SignalIOActivity(); - } - auto data = GetObjMember(&readyMessage, "data"); - auto user = GetObjMember(data, "user"); - auto userId = GetStrMember(user, "id"); - auto username = GetStrMember(user, "username"); - auto avatar = GetStrMember(user, "avatar"); - if (userId && username) { - StringCopy(connectedUser.userId, userId); - StringCopy(connectedUser.username, username); - auto discriminator = GetStrMember(user, "discriminator"); - if (discriminator) { - StringCopy(connectedUser.discriminator, discriminator); - } - if (avatar) { - StringCopy(connectedUser.avatar, avatar); - } - else { - connectedUser.avatar[0] = 0; - } - } - WasJustConnected.exchange(true); - ReconnectTimeMs.reset(); - }; - Connection->onDisconnect = [](int err, const char* message) { - LastDisconnectErrorCode = err; - StringCopy(LastDisconnectErrorMessage, message); - WasJustDisconnected.exchange(true); - UpdateReconnectTime(); - }; - - IoThread->Start(); -} - -extern "C" DISCORD_EXPORT void Discord_Shutdown(void) -{ - if (!Connection) { - return; - } - Connection->onConnect = nullptr; - Connection->onDisconnect = nullptr; - Handlers = {}; - QueuedPresence.length = 0; - UpdatePresence.exchange(false); - if (IoThread != nullptr) { - IoThread->Stop(); - delete IoThread; - IoThread = nullptr; - } - - RpcConnection::Destroy(Connection); -} - -extern "C" DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence) -{ - { - std::lock_guard guard(PresenceMutex); - QueuedPresence.length = JsonWriteRichPresenceObj( - QueuedPresence.buffer, sizeof(QueuedPresence.buffer), Nonce++, Pid, presence); - UpdatePresence.exchange(true); - } - SignalIOActivity(); -} - -extern "C" DISCORD_EXPORT void Discord_ClearPresence(void) -{ - Discord_UpdatePresence(nullptr); -} - -extern "C" DISCORD_EXPORT void Discord_Respond(const char* userId, /* DISCORD_REPLY_ */ int reply) -{ - // if we are not connected, let's not batch up stale messages for later - if (!Connection || !Connection->IsOpen()) { - return; - } - auto qmessage = SendQueue.GetNextAddMessage(); - if (qmessage) { - qmessage->length = - JsonWriteJoinReply(qmessage->buffer, sizeof(qmessage->buffer), userId, reply, Nonce++); - SendQueue.CommitAdd(); - SignalIOActivity(); - } -} - -extern "C" DISCORD_EXPORT void Discord_RunCallbacks(void) -{ - // Note on some weirdness: internally we might connect, get other signals, disconnect any number - // of times inbetween calls here. Externally, we want the sequence to seem sane, so any other - // signals are book-ended by calls to ready and disconnect. - - if (!Connection) { - return; - } - - bool wasDisconnected = WasJustDisconnected.exchange(false); - bool isConnected = Connection->IsOpen(); - - if (isConnected) { - // if we are connected, disconnect cb first - std::lock_guard guard(HandlerMutex); - if (wasDisconnected && Handlers.disconnected) { - Handlers.disconnected(LastDisconnectErrorCode, LastDisconnectErrorMessage); - } - } - - if (WasJustConnected.exchange(false)) { - std::lock_guard guard(HandlerMutex); - if (Handlers.ready) { - DiscordUser du{connectedUser.userId, - connectedUser.username, - connectedUser.discriminator, - connectedUser.avatar}; - Handlers.ready(&du); - } - } - - if (GotErrorMessage.exchange(false)) { - std::lock_guard guard(HandlerMutex); - if (Handlers.errored) { - Handlers.errored(LastErrorCode, LastErrorMessage); - } - } - - if (WasJoinGame.exchange(false)) { - std::lock_guard guard(HandlerMutex); - if (Handlers.joinGame) { - Handlers.joinGame(JoinGameSecret); - } - } - - if (WasSpectateGame.exchange(false)) { - std::lock_guard guard(HandlerMutex); - if (Handlers.spectateGame) { - Handlers.spectateGame(SpectateGameSecret); - } - } - - // Right now this batches up any requests and sends them all in a burst; I could imagine a world - // where the implementer would rather sequentially accept/reject each one before the next invite - // is sent. I left it this way because I could also imagine wanting to process these all and - // maybe show them in one common dialog and/or start fetching the avatars in parallel, and if - // not it should be trivial for the implementer to make a queue themselves. - while (JoinAskQueue.HavePendingSends()) { - auto req = JoinAskQueue.GetNextSendMessage(); - { - std::lock_guard guard(HandlerMutex); - if (Handlers.joinRequest) { - DiscordUser du{req->userId, req->username, req->discriminator, req->avatar}; - Handlers.joinRequest(&du); - } - } - JoinAskQueue.CommitSend(); - } - - if (!isConnected) { - // if we are not connected, disconnect message last - std::lock_guard guard(HandlerMutex); - if (wasDisconnected && Handlers.disconnected) { - Handlers.disconnected(LastDisconnectErrorCode, LastDisconnectErrorMessage); - } - } -} - -extern "C" DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* newHandlers) -{ - if (newHandlers) { -#define HANDLE_EVENT_REGISTRATION(handler_name, event) \ - if (!Handlers.handler_name && newHandlers->handler_name) { \ - RegisterForEvent(event); \ - } \ - else if (Handlers.handler_name && !newHandlers->handler_name) { \ - DeregisterForEvent(event); \ - } - - std::lock_guard guard(HandlerMutex); - HANDLE_EVENT_REGISTRATION(joinGame, "ACTIVITY_JOIN") - HANDLE_EVENT_REGISTRATION(spectateGame, "ACTIVITY_SPECTATE") - HANDLE_EVENT_REGISTRATION(joinRequest, "ACTIVITY_JOIN_REQUEST") - -#undef HANDLE_EVENT_REGISTRATION - - Handlers = *newHandlers; - } - else { - std::lock_guard guard(HandlerMutex); - Handlers = {}; - } - return; -} diff --git a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/discord_rpc.h b/Minecraft.Client/Windows64/ExtraLibs/discordrpc/discord_rpc.h deleted file mode 100644 index 4455133a..00000000 --- a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/discord_rpc.h +++ /dev/null @@ -1,94 +0,0 @@ -#pragma once -#include - -// clang-format off - -#if defined(DISCORD_DYNAMIC_LIB) -# if defined(_WIN32) -# if defined(DISCORD_BUILDING_SDK) -# define DISCORD_EXPORT __declspec(dllexport) -# else -# define DISCORD_EXPORT __declspec(dllimport) -# endif -# else -# define DISCORD_EXPORT __attribute__((visibility("default"))) -# endif -#else -# define DISCORD_EXPORT -#endif - -// clang-format on - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct DiscordRichPresence { - const char* state; /* max 128 bytes */ - const char* details; /* max 128 bytes */ - const char* button1Label; - const char* button1Url; - const char* button2Label; - const char* button2Url; - int64_t startTimestamp; - int64_t endTimestamp; - const char* largeImageKey; /* max 32 bytes */ - const char* largeImageText; /* max 128 bytes */ - const char* smallImageKey; /* max 32 bytes */ - const char* smallImageText; /* max 128 bytes */ - const char* partyId; /* max 128 bytes */ - int partySize; - int partyMax; - int partyPrivacy; - const char* matchSecret; /* max 128 bytes */ - const char* joinSecret; /* max 128 bytes */ - const char* spectateSecret; /* max 128 bytes */ - int8_t instance; -} DiscordRichPresence; - -typedef struct DiscordUser { - const char* userId; - const char* username; - const char* discriminator; - const char* avatar; -} DiscordUser; - -typedef struct DiscordEventHandlers { - void (*ready)(const DiscordUser* request); - void (*disconnected)(int errorCode, const char* message); - void (*errored)(int errorCode, const char* message); - void (*joinGame)(const char* joinSecret); - void (*spectateGame)(const char* spectateSecret); - void (*joinRequest)(const DiscordUser* request); -} DiscordEventHandlers; - -#define DISCORD_REPLY_NO 0 -#define DISCORD_REPLY_YES 1 -#define DISCORD_REPLY_IGNORE 2 -#define DISCORD_PARTY_PRIVATE 0 -#define DISCORD_PARTY_PUBLIC 1 - -DISCORD_EXPORT void Discord_Initialize(const char* applicationId, - DiscordEventHandlers* handlers, - int autoRegister, - const char* optionalSteamId); -DISCORD_EXPORT void Discord_Shutdown(void); - -/* checks for incoming messages, dispatches callbacks */ -DISCORD_EXPORT void Discord_RunCallbacks(void); - -/* If you disable the lib starting its own io thread, you'll need to call this from your own */ -#ifdef DISCORD_DISABLE_IO_THREAD -DISCORD_EXPORT void Discord_UpdateConnection(void); -#endif - -DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence); -DISCORD_EXPORT void Discord_ClearPresence(void); - -DISCORD_EXPORT void Discord_Respond(const char* userid, /* DISCORD_REPLY_ */ int reply); - -DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* handlers); - -#ifdef __cplusplus -} /* extern "C" */ -#endif diff --git a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/dllmain.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordrpc/dllmain.cpp deleted file mode 100644 index fbfc2950..00000000 --- a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/dllmain.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include - -// outsmart GCC's missing-declarations warning -BOOL WINAPI DllMain(HMODULE, DWORD, LPVOID); -BOOL WINAPI DllMain(HMODULE, DWORD, LPVOID) -{ - return TRUE; -} diff --git a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/msg_queue.h b/Minecraft.Client/Windows64/ExtraLibs/discordrpc/msg_queue.h deleted file mode 100644 index 77f380e7..00000000 --- a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/msg_queue.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include - -// A simple queue. No locks, but only works with a single thread as producer and a single thread as -// a consumer. Mutex up as needed. - -template -class MsgQueue { - ElementType queue_[QueueSize]; - std::atomic_uint nextAdd_{0}; - std::atomic_uint nextSend_{0}; - std::atomic_uint pendingSends_{0}; - -public: - MsgQueue() {} - - ElementType* GetNextAddMessage() - { - // if we are falling behind, bail - if (pendingSends_.load() >= QueueSize) { - return nullptr; - } - auto index = (nextAdd_++) % QueueSize; - return &queue_[index]; - } - void CommitAdd() { ++pendingSends_; } - - bool HavePendingSends() const { return pendingSends_.load() != 0; } - ElementType* GetNextSendMessage() - { - auto index = (nextSend_++) % QueueSize; - return &queue_[index]; - } - void CommitSend() { --pendingSends_; } -}; diff --git a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/rpc_connection.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordrpc/rpc_connection.cpp deleted file mode 100644 index 09331621..00000000 --- a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/rpc_connection.cpp +++ /dev/null @@ -1,137 +0,0 @@ -#include "rpc_connection.h" -#include "serialization.h" - -#include - -static const int RpcVersion = 1; -static RpcConnection Instance; - -/*static*/ RpcConnection* RpcConnection::Create(const char* applicationId) -{ - Instance.connection = BaseConnection::Create(); - StringCopy(Instance.appId, applicationId); - return &Instance; -} - -/*static*/ void RpcConnection::Destroy(RpcConnection*& c) -{ - c->Close(); - BaseConnection::Destroy(c->connection); - c = nullptr; -} - -void RpcConnection::Open() -{ - if (state == State::Connected) { - return; - } - - if (state == State::Disconnected && !connection->Open()) { - return; - } - - if (state == State::SentHandshake) { - JsonDocument message; - if (Read(message)) { - auto cmd = GetStrMember(&message, "cmd"); - auto evt = GetStrMember(&message, "evt"); - if (cmd && evt && !strcmp(cmd, "DISPATCH") && !strcmp(evt, "READY")) { - state = State::Connected; - if (onConnect) { - onConnect(message); - } - } - } - } - else { - sendFrame.opcode = Opcode::Handshake; - sendFrame.length = (uint32_t)JsonWriteHandshakeObj( - sendFrame.message, sizeof(sendFrame.message), RpcVersion, appId); - - if (connection->Write(&sendFrame, sizeof(MessageFrameHeader) + sendFrame.length)) { - state = State::SentHandshake; - } - else { - Close(); - } - } -} - -void RpcConnection::Close() -{ - if (onDisconnect && (state == State::Connected || state == State::SentHandshake)) { - onDisconnect(lastErrorCode, lastErrorMessage); - } - connection->Close(); - state = State::Disconnected; -} - -bool RpcConnection::Write(const void* data, size_t length) -{ - sendFrame.opcode = Opcode::Frame; - memcpy(sendFrame.message, data, length); - sendFrame.length = (uint32_t)length; - if (!connection->Write(&sendFrame, sizeof(MessageFrameHeader) + length)) { - Close(); - return false; - } - return true; -} - -bool RpcConnection::Read(JsonDocument& message) -{ - if (state != State::Connected && state != State::SentHandshake) { - return false; - } - MessageFrame readFrame; - for (;;) { - bool didRead = connection->Read(&readFrame, sizeof(MessageFrameHeader)); - if (!didRead) { - if (!connection->isOpen) { - lastErrorCode = (int)ErrorCode::PipeClosed; - StringCopy(lastErrorMessage, "Pipe closed"); - Close(); - } - return false; - } - - if (readFrame.length > 0) { - didRead = connection->Read(readFrame.message, readFrame.length); - if (!didRead) { - lastErrorCode = (int)ErrorCode::ReadCorrupt; - StringCopy(lastErrorMessage, "Partial data in frame"); - Close(); - return false; - } - readFrame.message[readFrame.length] = 0; - } - - switch (readFrame.opcode) { - case Opcode::Close: { - message.ParseInsitu(readFrame.message); - lastErrorCode = GetIntMember(&message, "code"); - StringCopy(lastErrorMessage, GetStrMember(&message, "message", "")); - Close(); - return false; - } - case Opcode::Frame: - message.ParseInsitu(readFrame.message); - return true; - case Opcode::Ping: - readFrame.opcode = Opcode::Pong; - if (!connection->Write(&readFrame, sizeof(MessageFrameHeader) + readFrame.length)) { - Close(); - } - break; - case Opcode::Pong: - break; - case Opcode::Handshake: - default: - // something bad happened - lastErrorCode = (int)ErrorCode::ReadCorrupt; - StringCopy(lastErrorMessage, "Bad ipc frame"); - Close(); - return false; - } - } -} diff --git a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/rpc_connection.h b/Minecraft.Client/Windows64/ExtraLibs/discordrpc/rpc_connection.h deleted file mode 100644 index bbdd05c7..00000000 --- a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/rpc_connection.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include "connection.h" -#include "serialization.h" - -// I took this from the buffer size libuv uses for named pipes; I suspect ours would usually be much -// smaller. -constexpr size_t MaxRpcFrameSize = 64 * 1024; - -struct RpcConnection { - enum class ErrorCode : int { - Success = 0, - PipeClosed = 1, - ReadCorrupt = 2, - }; - - enum class Opcode : uint32_t { - Handshake = 0, - Frame = 1, - Close = 2, - Ping = 3, - Pong = 4, - }; - - struct MessageFrameHeader { - Opcode opcode; - uint32_t length; - }; - - struct MessageFrame : public MessageFrameHeader { - char message[MaxRpcFrameSize - sizeof(MessageFrameHeader)]; - }; - - enum class State : uint32_t { - Disconnected, - SentHandshake, - AwaitingResponse, - Connected, - }; - - BaseConnection* connection{nullptr}; - State state{State::Disconnected}; - void (*onConnect)(JsonDocument& message){nullptr}; - void (*onDisconnect)(int errorCode, const char* message){nullptr}; - char appId[64]{}; - int lastErrorCode{0}; - char lastErrorMessage[256]{}; - RpcConnection::MessageFrame sendFrame; - - static RpcConnection* Create(const char* applicationId); - static void Destroy(RpcConnection*&); - - inline bool IsOpen() const { return state == State::Connected; } - - void Open(); - void Close(); - bool Write(const void* data, size_t length); - bool Read(JsonDocument& message); -}; diff --git a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/serialization.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordrpc/serialization.cpp deleted file mode 100644 index 2e0b3349..00000000 --- a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/serialization.cpp +++ /dev/null @@ -1,270 +0,0 @@ -#include "serialization.h" -#include "connection.h" -#include "discord_rpc.h" - -template -void NumberToString(char* dest, T number) -{ - if (!number) { - *dest++ = '0'; - *dest++ = 0; - return; - } - if (number < 0) { - *dest++ = '-'; - number = -number; - } - char temp[32]; - int place = 0; - while (number) { - auto digit = number % 10; - number = number / 10; - temp[place++] = '0' + (char)digit; - } - for (--place; place >= 0; --place) { - *dest++ = temp[place]; - } - *dest = 0; -} - -// it's ever so slightly faster to not have to strlen the key -template -void WriteKey(JsonWriter& w, T& k) -{ - w.Key(k, sizeof(T) - 1); -} - -struct WriteObject { - JsonWriter& writer; - WriteObject(JsonWriter& w) - : writer(w) - { - writer.StartObject(); - } - template - WriteObject(JsonWriter& w, T& name) - : writer(w) - { - WriteKey(writer, name); - writer.StartObject(); - } - ~WriteObject() { writer.EndObject(); } -}; - -struct WriteArray { - JsonWriter& writer; - template - WriteArray(JsonWriter& w, T& name) - : writer(w) - { - WriteKey(writer, name); - writer.StartArray(); - } - ~WriteArray() { writer.EndArray(); } -}; - -template -void WriteOptionalString(JsonWriter& w, T& k, const char* value) -{ - if (value && value[0]) { - w.Key(k, sizeof(T) - 1); - w.String(value); - } -} - -static void JsonWriteNonce(JsonWriter& writer, int nonce) -{ - WriteKey(writer, "nonce"); - char nonceBuffer[32]; - NumberToString(nonceBuffer, nonce); - writer.String(nonceBuffer); -} - -size_t JsonWriteRichPresenceObj(char* dest, - size_t maxLen, - int nonce, - int pid, - const DiscordRichPresence* presence) -{ - JsonWriter writer(dest, maxLen); - - { - WriteObject top(writer); - - JsonWriteNonce(writer, nonce); - - WriteKey(writer, "cmd"); - writer.String("SET_ACTIVITY"); - - { - WriteObject args(writer, "args"); - - WriteKey(writer, "pid"); - writer.Int(pid); - - if (presence != nullptr) { - WriteObject activity(writer, "activity"); - - WriteOptionalString(writer, "state", presence->state); - WriteOptionalString(writer, "details", presence->details); - - if (presence->startTimestamp || presence->endTimestamp) { - WriteObject timestamps(writer, "timestamps"); - - if (presence->startTimestamp) { - WriteKey(writer, "start"); - writer.Int64(presence->startTimestamp); - } - - if (presence->endTimestamp) { - WriteKey(writer, "end"); - writer.Int64(presence->endTimestamp); - } - } - - if ((presence->largeImageKey && presence->largeImageKey[0]) || - (presence->largeImageText && presence->largeImageText[0]) || - (presence->smallImageKey && presence->smallImageKey[0]) || - (presence->smallImageText && presence->smallImageText[0])) { - WriteObject assets(writer, "assets"); - WriteOptionalString(writer, "large_image", presence->largeImageKey); - WriteOptionalString(writer, "large_text", presence->largeImageText); - WriteOptionalString(writer, "small_image", presence->smallImageKey); - WriteOptionalString(writer, "small_text", presence->smallImageText); - } - - if ((presence->partyId && presence->partyId[0]) || presence->partySize || - presence->partyMax || presence->partyPrivacy) { - WriteObject party(writer, "party"); - WriteOptionalString(writer, "id", presence->partyId); - if (presence->partySize && presence->partyMax) { - WriteArray size(writer, "size"); - writer.Int(presence->partySize); - writer.Int(presence->partyMax); - } - - if (presence->partyPrivacy) { - WriteKey(writer, "privacy"); - writer.Int(presence->partyPrivacy); - } - } - - if ((presence->matchSecret && presence->matchSecret[0]) || - (presence->joinSecret && presence->joinSecret[0]) || - (presence->spectateSecret && presence->spectateSecret[0])) { - WriteObject secrets(writer, "secrets"); - WriteOptionalString(writer, "match", presence->matchSecret); - WriteOptionalString(writer, "join", presence->joinSecret); - WriteOptionalString(writer, "spectate", presence->spectateSecret); - } - - if ((presence->button1Label && presence->button1Label[0]) && - (presence->button1Url && presence->button1Url[0])) - { - WriteArray buttons(writer, "buttons"); - - { - WriteObject btn(writer); - WriteOptionalString(writer, "label", presence->button1Label); - WriteOptionalString(writer, "url", presence->button1Url); - } - - if ((presence->button2Label && presence->button2Label[0]) && - (presence->button2Url && presence->button2Url[0])) - { - WriteObject btn(writer); - WriteOptionalString(writer, "label", presence->button2Label); - WriteOptionalString(writer, "url", presence->button2Url); - } - } - - writer.Key("instance"); - writer.Bool(presence->instance != 0); - } - } - } - - return writer.Size(); -} - -size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char* applicationId) -{ - JsonWriter writer(dest, maxLen); - - { - WriteObject obj(writer); - WriteKey(writer, "v"); - writer.Int(version); - WriteKey(writer, "client_id"); - writer.String(applicationId); - } - - return writer.Size(); -} - -size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName) -{ - JsonWriter writer(dest, maxLen); - - { - WriteObject obj(writer); - - JsonWriteNonce(writer, nonce); - - WriteKey(writer, "cmd"); - writer.String("SUBSCRIBE"); - - WriteKey(writer, "evt"); - writer.String(evtName); - } - - return writer.Size(); -} - -size_t JsonWriteUnsubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName) -{ - JsonWriter writer(dest, maxLen); - - { - WriteObject obj(writer); - - JsonWriteNonce(writer, nonce); - - WriteKey(writer, "cmd"); - writer.String("UNSUBSCRIBE"); - - WriteKey(writer, "evt"); - writer.String(evtName); - } - - return writer.Size(); -} - -size_t JsonWriteJoinReply(char* dest, size_t maxLen, const char* userId, int reply, int nonce) -{ - JsonWriter writer(dest, maxLen); - - { - WriteObject obj(writer); - - WriteKey(writer, "cmd"); - if (reply == DISCORD_REPLY_YES) { - writer.String("SEND_ACTIVITY_JOIN_INVITE"); - } - else { - writer.String("CLOSE_ACTIVITY_JOIN_REQUEST"); - } - - WriteKey(writer, "args"); - { - WriteObject args(writer); - - WriteKey(writer, "user_id"); - writer.String(userId); - } - - JsonWriteNonce(writer, nonce); - } - - return writer.Size(); -} diff --git a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/serialization.h b/Minecraft.Client/Windows64/ExtraLibs/discordrpc/serialization.h deleted file mode 100644 index 4fd06abe..00000000 --- a/Minecraft.Client/Windows64/ExtraLibs/discordrpc/serialization.h +++ /dev/null @@ -1,215 +0,0 @@ -#pragma once - -#include - -#ifndef __MINGW32__ -#pragma warning(push) - -#pragma warning(disable : 4061) // enum is not explicitly handled by a case label -#pragma warning(disable : 4365) // signed/unsigned mismatch -#pragma warning(disable : 4464) // relative include path contains -#pragma warning(disable : 4668) // is not defined as a preprocessor macro -#pragma warning(disable : 6313) // Incorrect operator -#endif // __MINGW32__ - -#include "../rapidjson/document.h" -#include "../rapidjson/stringbuffer.h" -#include "../rapidjson/writer.h" - -#ifndef __MINGW32__ -#pragma warning(pop) -#endif // __MINGW32__ - -// if only there was a standard library function for this -template -inline size_t StringCopy(char (&dest)[Len], const char* src) -{ - if (!src || !Len) { - return 0; - } - size_t copied; - char* out = dest; - for (copied = 1; *src && copied < Len; ++copied) { - *out++ = *src++; - } - *out = 0; - return copied - 1; -} - -size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char* applicationId); - -// Commands -struct DiscordRichPresence; -size_t JsonWriteRichPresenceObj(char* dest, - size_t maxLen, - int nonce, - int pid, - const DiscordRichPresence* presence); -size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName); - -size_t JsonWriteUnsubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName); - -size_t JsonWriteJoinReply(char* dest, size_t maxLen, const char* userId, int reply, int nonce); - -// I want to use as few allocations as I can get away with, and to do that with RapidJson, you need -// to supply some of your own allocators for stuff rather than use the defaults - -class LinearAllocator { -public: - char* buffer_; - char* end_; - LinearAllocator() - { - assert(0); // needed for some default case in rapidjson, should not use - } - LinearAllocator(char* buffer, size_t size) - : buffer_(buffer) - , end_(buffer + size) - { - } - static const bool kNeedFree = false; - void* Malloc(size_t size) - { - char* res = buffer_; - buffer_ += size; - if (buffer_ > end_) { - buffer_ = res; - return nullptr; - } - return res; - } - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) - { - if (newSize == 0) { - return nullptr; - } - // allocate how much you need in the first place - assert(!originalPtr && !originalSize); - // unused parameter warning - (void)(originalPtr); - (void)(originalSize); - return Malloc(newSize); - } - static void Free(void* ptr) - { - /* shrug */ - (void)ptr; - } -}; - -template -class FixedLinearAllocator : public LinearAllocator { -public: - char fixedBuffer_[Size]; - FixedLinearAllocator() - : LinearAllocator(fixedBuffer_, Size) - { - } - static const bool kNeedFree = false; -}; - -// wonder why this isn't a thing already, maybe I missed it -class DirectStringBuffer { -public: - using Ch = char; - char* buffer_; - char* end_; - char* current_; - - DirectStringBuffer(char* buffer, size_t maxLen) - : buffer_(buffer) - , end_(buffer + maxLen) - , current_(buffer) - { - } - - void Put(char c) - { - if (current_ < end_) { - *current_++ = c; - } - } - void Flush() {} - size_t GetSize() const { return (size_t)(current_ - buffer_); } -}; - -using MallocAllocator = rapidjson::CrtAllocator; -using PoolAllocator = rapidjson::MemoryPoolAllocator; -using UTF8 = rapidjson::UTF8; -// Writer appears to need about 16 bytes per nested object level (with 64bit size_t) -using StackAllocator = FixedLinearAllocator<2048>; -constexpr size_t WriterNestingLevels = 2048 / (2 * sizeof(size_t)); -using JsonWriterBase = - rapidjson::Writer; -class JsonWriter : public JsonWriterBase { -public: - DirectStringBuffer stringBuffer_; - StackAllocator stackAlloc_; - - JsonWriter(char* dest, size_t maxLen) - : JsonWriterBase(stringBuffer_, &stackAlloc_, WriterNestingLevels) - , stringBuffer_(dest, maxLen) - , stackAlloc_() - { - } - - size_t Size() const { return stringBuffer_.GetSize(); } -}; - -using JsonDocumentBase = rapidjson::GenericDocument; -class JsonDocument : public JsonDocumentBase { -public: - static const int kDefaultChunkCapacity = 32 * 1024; - // json parser will use this buffer first, then allocate more if needed; I seriously doubt we - // send any messages that would use all of this, though. - char parseBuffer_[32 * 1024]; - MallocAllocator mallocAllocator_; - PoolAllocator poolAllocator_; - StackAllocator stackAllocator_; - JsonDocument() - : JsonDocumentBase(rapidjson::kObjectType, - &poolAllocator_, - sizeof(stackAllocator_.fixedBuffer_), - &stackAllocator_) - , poolAllocator_(parseBuffer_, sizeof(parseBuffer_), kDefaultChunkCapacity, &mallocAllocator_) - , stackAllocator_() - { - } -}; - -using JsonValue = rapidjson::GenericValue; - -inline JsonValue* GetObjMember(JsonValue* obj, const char* name) -{ - if (obj) { - auto member = obj->FindMember(name); - if (member != obj->MemberEnd() && member->value.IsObject()) { - return &member->value; - } - } - return nullptr; -} - -inline int GetIntMember(JsonValue* obj, const char* name, int notFoundDefault = 0) -{ - if (obj) { - auto member = obj->FindMember(name); - if (member != obj->MemberEnd() && member->value.IsInt()) { - return member->value.GetInt(); - } - } - return notFoundDefault; -} - -inline const char* GetStrMember(JsonValue* obj, - const char* name, - const char* notFoundDefault = nullptr) -{ - if (obj) { - auto member = obj->FindMember(name); - if (member != obj->MemberEnd() && member->value.IsString()) { - return member->value.GetString(); - } - } - return notFoundDefault; -} diff --git a/Minecraft.Client/Windows64/ExtraLibs/discordsdk/achievement_manager.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/achievement_manager.cpp new file mode 100644 index 00000000..43a6d4c9 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/achievement_manager.cpp @@ -0,0 +1,99 @@ +#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 DISCORD_CALLBACK 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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/achievement_manager.h b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/achievement_manager.h new file mode 100644 index 00000000..1f58c8eb --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/activity_manager.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/activity_manager.cpp new file mode 100644 index 00000000..3c200746 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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 DISCORD_CALLBACK 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 DISCORD_CALLBACK 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 DISCORD_CALLBACK OnActivityJoinRequest(void* callbackData, DiscordUser* user) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->ActivityManager(); + module.OnActivityJoinRequest(*reinterpret_cast(user)); + } + + static void DISCORD_CALLBACK 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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/activity_manager.h b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/activity_manager.h new file mode 100644 index 00000000..c107be27 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/application_manager.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/application_manager.cpp new file mode 100644 index 00000000..0e05f3f3 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/application_manager.h b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/application_manager.h new file mode 100644 index 00000000..ab0e8563 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/core.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/core.cpp new file mode 100644 index 00000000..110c9ef6 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/core.h b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/core.h new file mode 100644 index 00000000..8af6fca2 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/discord.h b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/discord.h new file mode 100644 index 00000000..c9912129 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/discord_game_sdk.dll.lib b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/discord_game_sdk.dll.lib new file mode 100644 index 0000000000000000000000000000000000000000..562b01cdc82b16bd9c269015ade613797e1a3e2a GIT binary patch literal 2352 zcmcIlPj3=I6#ualio_UV8!twKm8d-k2rP+-FSV|j8y>1tFEgPXr7JBgHjgw!a zSC5<CvMHzXZP7ouRvQ70@ur{CRKQ%=t3o6SO zIXTByM{xkR0O=BlYyiJ7F0=3u*C*>CLCRo(2jEL&HP zwXUJ|^^Z{1+F`YNQxc!2MP0$h+r!$9THb1Gq3qtZZ5!Iapo`3IPxbRS_1>`irgh>M z@iXny{y;U_YL7&%6Rl$oJ|T#=aNLU5af?#mE+t?i0yK%ZSOrQkU__k)iWNiM-8c+m zOzmNa5KC{sT3R=nr^l%Smjd3=;)@{otRPWJo4Pj8QaQ1;PKzt*zc?dIvx4k7mn(8M z?$IJf`h*Qk&G2s8N3PEfmp1kTL6yJpL_`qqa*@>zW|S*_G| z+-?7On@DC6>kMmbm7tNpNUI=qWL3-R_Q?D*GZY$+y=UnVn7tB26coVmpe;C#zph3u zQ(!W52oo9kn#1^;Y~YREPWizpHc8NFTy|Ai6iqq#<)kv|L&-tYH^*9Lb1<5iAKvCc zQ(o{Hn!XBx&kRj0F3Us7JTLx$Ecj#DUN{@`*@7p2ZZ`fT4et8~$L}xMDDzM`*?c7k zJ}Xc}HWtJd%laRJ@W?GM&hy0h30X2nEfs}q-pVI)!6f^|Sw`zaR{b73ey>dZH-R-_ r;rEq`!8%i +#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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/ffi.h b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/ffi.h new file mode 100644 index 00000000..4a210574 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/ffi.h @@ -0,0 +1,1113 @@ +#ifndef _DISCORD_GAME_SDK_H_ +#define _DISCORD_GAME_SDK_H_ + +#ifdef _WIN32 +#include +#include +#endif + +#ifdef _WIN32 +#ifdef _WIN64 +#define DISCORD_API +#else +#define DISCORD_API __stdcall +#endif +#else +#define DISCORD_API +#endif + +#define DISCORD_CALLBACK DISCORD_API + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#ifndef __cplusplus +#include +#endif + +#define DISCORD_VERSION 3 +#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 2 +#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, + DiscordResult_DrawingInitFailed = 44, +}; + +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 EDiscordActivityPartyPrivacy { + DiscordActivityPartyPrivacy_Private = 0, + DiscordActivityPartyPrivacy_Public = 1, +}; + +enum EDiscordActivityType { + DiscordActivityType_Playing, + DiscordActivityType_Streaming, + DiscordActivityType_Listening, + DiscordActivityType_Watching, +}; + +enum EDiscordActivityActionType { + DiscordActivityActionType_Join = 1, + DiscordActivityActionType_Spectate, +}; + +enum EDiscordActivitySupportedPlatformFlags { + DiscordActivitySupportedPlatformFlags_Desktop = 1, + DiscordActivitySupportedPlatformFlags_Android = 2, + DiscordActivitySupportedPlatformFlags_iOS = 4, +}; + +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 EDiscordKeyVariant { + DiscordKeyVariant_Normal, + DiscordKeyVariant_Right, + DiscordKeyVariant_Left, +}; + +enum EDiscordMouseButton { + DiscordMouseButton_Left, + DiscordMouseButton_Middle, + DiscordMouseButton_Right, +}; + +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; +#ifdef __APPLE__ +typedef void IDXGISwapChain; +#endif +#ifdef __linux__ +typedef void IDXGISwapChain; +#endif +#ifdef __APPLE__ +typedef void MSG; +#endif +#ifdef __linux__ +typedef void MSG; +#endif +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; + enum EDiscordActivityPartyPrivacy privacy; +}; + +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; + uint32_t supported_platforms; +}; + +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 DiscordImeUnderline { + int32_t from; + int32_t to; + uint32_t color; + uint32_t background_color; + bool thick; +}; + +struct DiscordRect { + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +}; + +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(DISCORD_API* set_type)(struct IDiscordLobbyTransaction* lobby_transaction, + enum EDiscordLobbyType type); + enum EDiscordResult(DISCORD_API* set_owner)(struct IDiscordLobbyTransaction* lobby_transaction, + DiscordUserId owner_id); + enum EDiscordResult(DISCORD_API* set_capacity)( + struct IDiscordLobbyTransaction* lobby_transaction, + uint32_t capacity); + enum EDiscordResult(DISCORD_API* set_metadata)( + struct IDiscordLobbyTransaction* lobby_transaction, + DiscordMetadataKey key, + DiscordMetadataValue value); + enum EDiscordResult(DISCORD_API* delete_metadata)( + struct IDiscordLobbyTransaction* lobby_transaction, + DiscordMetadataKey key); + enum EDiscordResult(DISCORD_API* set_locked)(struct IDiscordLobbyTransaction* lobby_transaction, + bool locked); +}; + +struct IDiscordLobbyMemberTransaction { + enum EDiscordResult(DISCORD_API* set_metadata)( + struct IDiscordLobbyMemberTransaction* lobby_member_transaction, + DiscordMetadataKey key, + DiscordMetadataValue value); + enum EDiscordResult(DISCORD_API* delete_metadata)( + struct IDiscordLobbyMemberTransaction* lobby_member_transaction, + DiscordMetadataKey key); +}; + +struct IDiscordLobbySearchQuery { + enum EDiscordResult(DISCORD_API* filter)(struct IDiscordLobbySearchQuery* lobby_search_query, + DiscordMetadataKey key, + enum EDiscordLobbySearchComparison comparison, + enum EDiscordLobbySearchCast cast, + DiscordMetadataValue value); + enum EDiscordResult(DISCORD_API* sort)(struct IDiscordLobbySearchQuery* lobby_search_query, + DiscordMetadataKey key, + enum EDiscordLobbySearchCast cast, + DiscordMetadataValue value); + enum EDiscordResult(DISCORD_API* limit)(struct IDiscordLobbySearchQuery* lobby_search_query, + uint32_t limit); + enum EDiscordResult(DISCORD_API* distance)(struct IDiscordLobbySearchQuery* lobby_search_query, + enum EDiscordLobbySearchDistance distance); +}; + +typedef void* IDiscordApplicationEvents; + +struct IDiscordApplicationManager { + void(DISCORD_API* validate_or_exit)(struct IDiscordApplicationManager* manager, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + void(DISCORD_API* get_current_locale)(struct IDiscordApplicationManager* manager, + DiscordLocale* locale); + void(DISCORD_API* get_current_branch)(struct IDiscordApplicationManager* manager, + DiscordBranch* branch); + void(DISCORD_API* get_oauth2_token)( + struct IDiscordApplicationManager* manager, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result, + struct DiscordOAuth2Token* oauth2_token)); + void(DISCORD_API* get_ticket)(struct IDiscordApplicationManager* manager, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result, + const char* data)); +}; + +struct IDiscordUserEvents { + void(DISCORD_API* on_current_user_update)(void* event_data); +}; + +struct IDiscordUserManager { + enum EDiscordResult(DISCORD_API* get_current_user)(struct IDiscordUserManager* manager, + struct DiscordUser* current_user); + void(DISCORD_API* get_user)(struct IDiscordUserManager* manager, + DiscordUserId user_id, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result, + struct DiscordUser* user)); + enum EDiscordResult(DISCORD_API* get_current_user_premium_type)( + struct IDiscordUserManager* manager, + enum EDiscordPremiumType* premium_type); + enum EDiscordResult(DISCORD_API* current_user_has_flag)(struct IDiscordUserManager* manager, + enum EDiscordUserFlag flag, + bool* has_flag); +}; + +typedef void* IDiscordImageEvents; + +struct IDiscordImageManager { + void(DISCORD_API* fetch)(struct IDiscordImageManager* manager, + struct DiscordImageHandle handle, + bool refresh, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result, + struct DiscordImageHandle handle_result)); + enum EDiscordResult(DISCORD_API* get_dimensions)(struct IDiscordImageManager* manager, + struct DiscordImageHandle handle, + struct DiscordImageDimensions* dimensions); + enum EDiscordResult(DISCORD_API* get_data)(struct IDiscordImageManager* manager, + struct DiscordImageHandle handle, + uint8_t* data, + uint32_t data_length); +}; + +struct IDiscordActivityEvents { + void(DISCORD_API* on_activity_join)(void* event_data, const char* secret); + void(DISCORD_API* on_activity_spectate)(void* event_data, const char* secret); + void(DISCORD_API* on_activity_join_request)(void* event_data, struct DiscordUser* user); + void(DISCORD_API* on_activity_invite)(void* event_data, + enum EDiscordActivityActionType type, + struct DiscordUser* user, + struct DiscordActivity* activity); +}; + +struct IDiscordActivityManager { + enum EDiscordResult(DISCORD_API* register_command)(struct IDiscordActivityManager* manager, + const char* command); + enum EDiscordResult(DISCORD_API* register_steam)(struct IDiscordActivityManager* manager, + uint32_t steam_id); + void(DISCORD_API* update_activity)(struct IDiscordActivityManager* manager, + struct DiscordActivity* activity, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + void(DISCORD_API* clear_activity)(struct IDiscordActivityManager* manager, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + void(DISCORD_API* send_request_reply)(struct IDiscordActivityManager* manager, + DiscordUserId user_id, + enum EDiscordActivityJoinRequestReply reply, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + void(DISCORD_API* send_invite)(struct IDiscordActivityManager* manager, + DiscordUserId user_id, + enum EDiscordActivityActionType type, + const char* content, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + void(DISCORD_API* accept_invite)(struct IDiscordActivityManager* manager, + DiscordUserId user_id, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); +}; + +struct IDiscordRelationshipEvents { + void(DISCORD_API* on_refresh)(void* event_data); + void(DISCORD_API* on_relationship_update)(void* event_data, + struct DiscordRelationship* relationship); +}; + +struct IDiscordRelationshipManager { + void(DISCORD_API* filter)(struct IDiscordRelationshipManager* manager, + void* filter_data, + bool(DISCORD_API* filter)(void* filter_data, + struct DiscordRelationship* relationship)); + enum EDiscordResult(DISCORD_API* count)(struct IDiscordRelationshipManager* manager, + int32_t* count); + enum EDiscordResult(DISCORD_API* get)(struct IDiscordRelationshipManager* manager, + DiscordUserId user_id, + struct DiscordRelationship* relationship); + enum EDiscordResult(DISCORD_API* get_at)(struct IDiscordRelationshipManager* manager, + uint32_t index, + struct DiscordRelationship* relationship); +}; + +struct IDiscordLobbyEvents { + void(DISCORD_API* on_lobby_update)(void* event_data, int64_t lobby_id); + void(DISCORD_API* on_lobby_delete)(void* event_data, int64_t lobby_id, uint32_t reason); + void(DISCORD_API* on_member_connect)(void* event_data, int64_t lobby_id, int64_t user_id); + void(DISCORD_API* on_member_update)(void* event_data, int64_t lobby_id, int64_t user_id); + void(DISCORD_API* on_member_disconnect)(void* event_data, int64_t lobby_id, int64_t user_id); + void(DISCORD_API* on_lobby_message)(void* event_data, + int64_t lobby_id, + int64_t user_id, + uint8_t* data, + uint32_t data_length); + void(DISCORD_API* on_speaking)(void* event_data, + int64_t lobby_id, + int64_t user_id, + bool speaking); + void(DISCORD_API* 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(DISCORD_API* get_lobby_create_transaction)( + struct IDiscordLobbyManager* manager, + struct IDiscordLobbyTransaction** transaction); + enum EDiscordResult(DISCORD_API* get_lobby_update_transaction)( + struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + struct IDiscordLobbyTransaction** transaction); + enum EDiscordResult(DISCORD_API* get_member_update_transaction)( + struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordUserId user_id, + struct IDiscordLobbyMemberTransaction** transaction); + void(DISCORD_API* create_lobby)(struct IDiscordLobbyManager* manager, + struct IDiscordLobbyTransaction* transaction, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result, + struct DiscordLobby* lobby)); + void(DISCORD_API* update_lobby)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + struct IDiscordLobbyTransaction* transaction, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + void(DISCORD_API* delete_lobby)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + void(DISCORD_API* connect_lobby)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordLobbySecret secret, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result, + struct DiscordLobby* lobby)); + void(DISCORD_API* connect_lobby_with_activity_secret)( + struct IDiscordLobbyManager* manager, + DiscordLobbySecret activity_secret, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result, + struct DiscordLobby* lobby)); + void(DISCORD_API* disconnect_lobby)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + enum EDiscordResult(DISCORD_API* get_lobby)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + struct DiscordLobby* lobby); + enum EDiscordResult(DISCORD_API* get_lobby_activity_secret)( + struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordLobbySecret* secret); + enum EDiscordResult(DISCORD_API* get_lobby_metadata_value)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordMetadataKey key, + DiscordMetadataValue* value); + enum EDiscordResult(DISCORD_API* get_lobby_metadata_key)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + int32_t index, + DiscordMetadataKey* key); + enum EDiscordResult(DISCORD_API* lobby_metadata_count)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + int32_t* count); + enum EDiscordResult(DISCORD_API* member_count)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + int32_t* count); + enum EDiscordResult(DISCORD_API* get_member_user_id)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + int32_t index, + DiscordUserId* user_id); + enum EDiscordResult(DISCORD_API* get_member_user)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordUserId user_id, + struct DiscordUser* user); + enum EDiscordResult(DISCORD_API* get_member_metadata_value)( + struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordUserId user_id, + DiscordMetadataKey key, + DiscordMetadataValue* value); + enum EDiscordResult(DISCORD_API* get_member_metadata_key)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordUserId user_id, + int32_t index, + DiscordMetadataKey* key); + enum EDiscordResult(DISCORD_API* member_metadata_count)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordUserId user_id, + int32_t* count); + void(DISCORD_API* update_member)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + DiscordUserId user_id, + struct IDiscordLobbyMemberTransaction* transaction, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + void(DISCORD_API* send_lobby_message)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + uint8_t* data, + uint32_t data_length, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + enum EDiscordResult(DISCORD_API* get_search_query)(struct IDiscordLobbyManager* manager, + struct IDiscordLobbySearchQuery** query); + void(DISCORD_API* search)(struct IDiscordLobbyManager* manager, + struct IDiscordLobbySearchQuery* query, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + void(DISCORD_API* lobby_count)(struct IDiscordLobbyManager* manager, int32_t* count); + enum EDiscordResult(DISCORD_API* get_lobby_id)(struct IDiscordLobbyManager* manager, + int32_t index, + DiscordLobbyId* lobby_id); + void(DISCORD_API* connect_voice)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + void(DISCORD_API* disconnect_voice)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + enum EDiscordResult(DISCORD_API* connect_network)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id); + enum EDiscordResult(DISCORD_API* disconnect_network)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id); + enum EDiscordResult(DISCORD_API* flush_network)(struct IDiscordLobbyManager* manager); + enum EDiscordResult(DISCORD_API* open_network_channel)(struct IDiscordLobbyManager* manager, + DiscordLobbyId lobby_id, + uint8_t channel_id, + bool reliable); + enum EDiscordResult(DISCORD_API* 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(DISCORD_API* on_message)(void* event_data, + DiscordNetworkPeerId peer_id, + DiscordNetworkChannelId channel_id, + uint8_t* data, + uint32_t data_length); + void(DISCORD_API* on_route_update)(void* event_data, const char* route_data); +}; + +struct IDiscordNetworkManager { + /** + * Get the local peer ID for this process. + */ + void(DISCORD_API* get_peer_id)(struct IDiscordNetworkManager* manager, + DiscordNetworkPeerId* peer_id); + /** + * Send pending network messages. + */ + enum EDiscordResult(DISCORD_API* flush)(struct IDiscordNetworkManager* manager); + /** + * Open a connection to a remote peer. + */ + enum EDiscordResult(DISCORD_API* open_peer)(struct IDiscordNetworkManager* manager, + DiscordNetworkPeerId peer_id, + const char* route_data); + /** + * Update the route data for a connected peer. + */ + enum EDiscordResult(DISCORD_API* update_peer)(struct IDiscordNetworkManager* manager, + DiscordNetworkPeerId peer_id, + const char* route_data); + /** + * Close the connection to a remote peer. + */ + enum EDiscordResult(DISCORD_API* close_peer)(struct IDiscordNetworkManager* manager, + DiscordNetworkPeerId peer_id); + /** + * Open a message channel to a connected peer. + */ + enum EDiscordResult(DISCORD_API* open_channel)(struct IDiscordNetworkManager* manager, + DiscordNetworkPeerId peer_id, + DiscordNetworkChannelId channel_id, + bool reliable); + /** + * Close a message channel to a connected peer. + */ + enum EDiscordResult(DISCORD_API* 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(DISCORD_API* send_message)(struct IDiscordNetworkManager* manager, + DiscordNetworkPeerId peer_id, + DiscordNetworkChannelId channel_id, + uint8_t* data, + uint32_t data_length); +}; + +struct IDiscordOverlayEvents { + void(DISCORD_API* on_toggle)(void* event_data, bool locked); +}; + +struct IDiscordOverlayManager { + void(DISCORD_API* is_enabled)(struct IDiscordOverlayManager* manager, bool* enabled); + void(DISCORD_API* is_locked)(struct IDiscordOverlayManager* manager, bool* locked); + void(DISCORD_API* set_locked)(struct IDiscordOverlayManager* manager, + bool locked, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + void(DISCORD_API* open_activity_invite)( + struct IDiscordOverlayManager* manager, + enum EDiscordActivityActionType type, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, enum EDiscordResult result)); + void(DISCORD_API* open_guild_invite)(struct IDiscordOverlayManager* manager, + const char* code, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + void(DISCORD_API* open_voice_settings)(struct IDiscordOverlayManager* manager, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + enum EDiscordResult(DISCORD_API* init_drawing_dxgi)(struct IDiscordOverlayManager* manager, + IDXGISwapChain* swapchain, + bool use_message_forwarding); + void(DISCORD_API* on_present)(struct IDiscordOverlayManager* manager); + void(DISCORD_API* forward_message)(struct IDiscordOverlayManager* manager, MSG* message); + void(DISCORD_API* key_event)(struct IDiscordOverlayManager* manager, + bool down, + const char* key_code, + enum EDiscordKeyVariant variant); + void(DISCORD_API* char_event)(struct IDiscordOverlayManager* manager, const char* character); + void(DISCORD_API* mouse_button_event)(struct IDiscordOverlayManager* manager, + uint8_t down, + int32_t click_count, + enum EDiscordMouseButton which, + int32_t x, + int32_t y); + void(DISCORD_API* mouse_motion_event)(struct IDiscordOverlayManager* manager, + int32_t x, + int32_t y); + void(DISCORD_API* ime_commit_text)(struct IDiscordOverlayManager* manager, const char* text); + void(DISCORD_API* ime_set_composition)(struct IDiscordOverlayManager* manager, + const char* text, + struct DiscordImeUnderline* underlines, + uint32_t underlines_length, + int32_t from, + int32_t to); + void(DISCORD_API* ime_cancel_composition)(struct IDiscordOverlayManager* manager); + void(DISCORD_API* set_ime_composition_range_callback)( + struct IDiscordOverlayManager* manager, + void* on_ime_composition_range_changed_data, + void(DISCORD_API* on_ime_composition_range_changed)( + void* on_ime_composition_range_changed_data, + int32_t from, + int32_t to, + struct DiscordRect* bounds, + uint32_t bounds_length)); + void(DISCORD_API* set_ime_selection_bounds_callback)( + struct IDiscordOverlayManager* manager, + void* on_ime_selection_bounds_changed_data, + void(DISCORD_API* on_ime_selection_bounds_changed)(void* on_ime_selection_bounds_changed_data, + struct DiscordRect anchor, + struct DiscordRect focus, + bool is_anchor_first)); + bool(DISCORD_API* is_point_inside_click_zone)(struct IDiscordOverlayManager* manager, + int32_t x, + int32_t y); +}; + +typedef void* IDiscordStorageEvents; + +struct IDiscordStorageManager { + enum EDiscordResult(DISCORD_API* read)(struct IDiscordStorageManager* manager, + const char* name, + uint8_t* data, + uint32_t data_length, + uint32_t* read); + void(DISCORD_API* read_async)(struct IDiscordStorageManager* manager, + const char* name, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result, + uint8_t* data, + uint32_t data_length)); + void(DISCORD_API* read_async_partial)(struct IDiscordStorageManager* manager, + const char* name, + uint64_t offset, + uint64_t length, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result, + uint8_t* data, + uint32_t data_length)); + enum EDiscordResult(DISCORD_API* write)(struct IDiscordStorageManager* manager, + const char* name, + uint8_t* data, + uint32_t data_length); + void(DISCORD_API* write_async)(struct IDiscordStorageManager* manager, + const char* name, + uint8_t* data, + uint32_t data_length, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + enum EDiscordResult(DISCORD_API* delete_)(struct IDiscordStorageManager* manager, + const char* name); + enum EDiscordResult(DISCORD_API* exists)(struct IDiscordStorageManager* manager, + const char* name, + bool* exists); + void(DISCORD_API* count)(struct IDiscordStorageManager* manager, int32_t* count); + enum EDiscordResult(DISCORD_API* stat)(struct IDiscordStorageManager* manager, + const char* name, + struct DiscordFileStat* stat); + enum EDiscordResult(DISCORD_API* stat_at)(struct IDiscordStorageManager* manager, + int32_t index, + struct DiscordFileStat* stat); + enum EDiscordResult(DISCORD_API* get_path)(struct IDiscordStorageManager* manager, + DiscordPath* path); +}; + +struct IDiscordStoreEvents { + void(DISCORD_API* on_entitlement_create)(void* event_data, + struct DiscordEntitlement* entitlement); + void(DISCORD_API* on_entitlement_delete)(void* event_data, + struct DiscordEntitlement* entitlement); +}; + +struct IDiscordStoreManager { + void(DISCORD_API* fetch_skus)(struct IDiscordStoreManager* manager, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + void(DISCORD_API* count_skus)(struct IDiscordStoreManager* manager, int32_t* count); + enum EDiscordResult(DISCORD_API* get_sku)(struct IDiscordStoreManager* manager, + DiscordSnowflake sku_id, + struct DiscordSku* sku); + enum EDiscordResult(DISCORD_API* get_sku_at)(struct IDiscordStoreManager* manager, + int32_t index, + struct DiscordSku* sku); + void(DISCORD_API* fetch_entitlements)(struct IDiscordStoreManager* manager, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + void(DISCORD_API* count_entitlements)(struct IDiscordStoreManager* manager, int32_t* count); + enum EDiscordResult(DISCORD_API* get_entitlement)(struct IDiscordStoreManager* manager, + DiscordSnowflake entitlement_id, + struct DiscordEntitlement* entitlement); + enum EDiscordResult(DISCORD_API* get_entitlement_at)(struct IDiscordStoreManager* manager, + int32_t index, + struct DiscordEntitlement* entitlement); + enum EDiscordResult(DISCORD_API* has_sku_entitlement)(struct IDiscordStoreManager* manager, + DiscordSnowflake sku_id, + bool* has_entitlement); + void(DISCORD_API* start_purchase)(struct IDiscordStoreManager* manager, + DiscordSnowflake sku_id, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); +}; + +struct IDiscordVoiceEvents { + void(DISCORD_API* on_settings_update)(void* event_data); +}; + +struct IDiscordVoiceManager { + enum EDiscordResult(DISCORD_API* get_input_mode)(struct IDiscordVoiceManager* manager, + struct DiscordInputMode* input_mode); + void(DISCORD_API* set_input_mode)(struct IDiscordVoiceManager* manager, + struct DiscordInputMode input_mode, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, + enum EDiscordResult result)); + enum EDiscordResult(DISCORD_API* is_self_mute)(struct IDiscordVoiceManager* manager, + bool* mute); + enum EDiscordResult(DISCORD_API* set_self_mute)(struct IDiscordVoiceManager* manager, + bool mute); + enum EDiscordResult(DISCORD_API* is_self_deaf)(struct IDiscordVoiceManager* manager, + bool* deaf); + enum EDiscordResult(DISCORD_API* set_self_deaf)(struct IDiscordVoiceManager* manager, + bool deaf); + enum EDiscordResult(DISCORD_API* is_local_mute)(struct IDiscordVoiceManager* manager, + DiscordSnowflake user_id, + bool* mute); + enum EDiscordResult(DISCORD_API* set_local_mute)(struct IDiscordVoiceManager* manager, + DiscordSnowflake user_id, + bool mute); + enum EDiscordResult(DISCORD_API* get_local_volume)(struct IDiscordVoiceManager* manager, + DiscordSnowflake user_id, + uint8_t* volume); + enum EDiscordResult(DISCORD_API* set_local_volume)(struct IDiscordVoiceManager* manager, + DiscordSnowflake user_id, + uint8_t volume); +}; + +struct IDiscordAchievementEvents { + void(DISCORD_API* on_user_achievement_update)(void* event_data, + struct DiscordUserAchievement* user_achievement); +}; + +struct IDiscordAchievementManager { + void(DISCORD_API* set_user_achievement)( + struct IDiscordAchievementManager* manager, + DiscordSnowflake achievement_id, + uint8_t percent_complete, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, enum EDiscordResult result)); + void(DISCORD_API* fetch_user_achievements)( + struct IDiscordAchievementManager* manager, + void* callback_data, + void(DISCORD_API* callback)(void* callback_data, enum EDiscordResult result)); + void(DISCORD_API* count_user_achievements)(struct IDiscordAchievementManager* manager, + int32_t* count); + enum EDiscordResult(DISCORD_API* get_user_achievement)( + struct IDiscordAchievementManager* manager, + DiscordSnowflake user_achievement_id, + struct DiscordUserAchievement* user_achievement); + enum EDiscordResult(DISCORD_API* get_user_achievement_at)( + struct IDiscordAchievementManager* manager, + int32_t index, + struct DiscordUserAchievement* user_achievement); +}; + +typedef void* IDiscordCoreEvents; + +struct IDiscordCore { + void(DISCORD_API* destroy)(struct IDiscordCore* core); + enum EDiscordResult(DISCORD_API* run_callbacks)(struct IDiscordCore* core); + void(DISCORD_API* set_log_hook)(struct IDiscordCore* core, + enum EDiscordLogLevel min_level, + void* hook_data, + void(DISCORD_API* hook)(void* hook_data, + enum EDiscordLogLevel level, + const char* message)); + struct IDiscordApplicationManager*(DISCORD_API* get_application_manager)( + struct IDiscordCore* core); + struct IDiscordUserManager*(DISCORD_API* get_user_manager)(struct IDiscordCore* core); + struct IDiscordImageManager*(DISCORD_API* get_image_manager)(struct IDiscordCore* core); + struct IDiscordActivityManager*(DISCORD_API* get_activity_manager)(struct IDiscordCore* core); + struct IDiscordRelationshipManager*(DISCORD_API* get_relationship_manager)( + struct IDiscordCore* core); + struct IDiscordLobbyManager*(DISCORD_API* get_lobby_manager)(struct IDiscordCore* core); + struct IDiscordNetworkManager*(DISCORD_API* get_network_manager)(struct IDiscordCore* core); + struct IDiscordOverlayManager*(DISCORD_API* get_overlay_manager)(struct IDiscordCore* core); + struct IDiscordStorageManager*(DISCORD_API* get_storage_manager)(struct IDiscordCore* core); + struct IDiscordStoreManager*(DISCORD_API* get_store_manager)(struct IDiscordCore* core); + struct IDiscordVoiceManager*(DISCORD_API* get_voice_manager)(struct IDiscordCore* core); + struct IDiscordAchievementManager*(DISCORD_API* 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 DISCORD_API DiscordCreate(DiscordVersion version, + struct DiscordCreateParams* params, + struct IDiscordCore** result); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Minecraft.Client/Windows64/ExtraLibs/discordsdk/image_manager.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/image_manager.cpp new file mode 100644 index 00000000..03b1db49 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/image_manager.h b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/image_manager.h new file mode 100644 index 00000000..b096b171 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/lobby_manager.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/lobby_manager.cpp new file mode 100644 index 00000000..3a95b1a0 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/lobby_manager.cpp @@ -0,0 +1,554 @@ +#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 DISCORD_CALLBACK OnLobbyUpdate(void* callbackData, int64_t lobbyId) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->LobbyManager(); + module.OnLobbyUpdate(lobbyId); + } + + static void DISCORD_CALLBACK 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 DISCORD_CALLBACK 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 DISCORD_CALLBACK 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 DISCORD_CALLBACK 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 DISCORD_CALLBACK 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 DISCORD_CALLBACK 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 DISCORD_CALLBACK 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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/lobby_manager.h b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/lobby_manager.h new file mode 100644 index 00000000..96380cbf --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/network_manager.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/network_manager.cpp new file mode 100644 index 00000000..36031b32 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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 DISCORD_CALLBACK 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 DISCORD_CALLBACK 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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/network_manager.h b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/network_manager.h new file mode 100644 index 00000000..e374670a --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/overlay_manager.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/overlay_manager.cpp new file mode 100644 index 00000000..f4b1fba7 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/overlay_manager.cpp @@ -0,0 +1,229 @@ +#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 DISCORD_CALLBACK 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); +} + +Result OverlayManager::InitDrawingDxgi(IDXGISwapChain* swapchain, bool useMessageForwarding) +{ + auto result = + internal_->init_drawing_dxgi(internal_, swapchain, (useMessageForwarding ? 1 : 0)); + return static_cast(result); +} + +void OverlayManager::OnPresent() +{ + internal_->on_present(internal_); +} + +void OverlayManager::ForwardMessage(MSG* message) +{ + internal_->forward_message(internal_, message); +} + +void OverlayManager::KeyEvent(bool down, char const* keyCode, KeyVariant variant) +{ + internal_->key_event(internal_, + (down ? 1 : 0), + const_cast(keyCode), + static_cast(variant)); +} + +void OverlayManager::CharEvent(char const* character) +{ + internal_->char_event(internal_, const_cast(character)); +} + +void OverlayManager::MouseButtonEvent(std::uint8_t down, + std::int32_t clickCount, + MouseButton which, + std::int32_t x, + std::int32_t y) +{ + internal_->mouse_button_event( + internal_, down, clickCount, static_cast(which), x, y); +} + +void OverlayManager::MouseMotionEvent(std::int32_t x, std::int32_t y) +{ + internal_->mouse_motion_event(internal_, x, y); +} + +void OverlayManager::ImeCommitText(char const* text) +{ + internal_->ime_commit_text(internal_, const_cast(text)); +} + +void OverlayManager::ImeSetComposition(char const* text, + ImeUnderline* underlines, + std::uint32_t underlinesLength, + std::int32_t from, + std::int32_t to) +{ + internal_->ime_set_composition(internal_, + const_cast(text), + reinterpret_cast(underlines), + underlinesLength, + from, + to); +} + +void OverlayManager::ImeCancelComposition() +{ + internal_->ime_cancel_composition(internal_); +} + +void OverlayManager::SetImeCompositionRangeCallback( + std::function + onImeCompositionRangeChanged) +{ + static auto wrapper = [](void* callbackData, + int32_t from, + int32_t to, + DiscordRect* bounds, + uint32_t boundsLength) -> void { + std::unique_ptr> cb( + reinterpret_cast*>( + callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(from, to, reinterpret_cast(bounds), boundsLength); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function( + std::move(onImeCompositionRangeChanged))); + internal_->set_ime_composition_range_callback(internal_, cb.release(), wrapper); +} + +void OverlayManager::SetImeSelectionBoundsCallback( + std::function onImeSelectionBoundsChanged) +{ + static auto wrapper = + [](void* callbackData, DiscordRect anchor, DiscordRect focus, bool isAnchorFirst) -> void { + std::unique_ptr> cb( + reinterpret_cast*>(callbackData)); + if (!cb || !(*cb)) { + return; + } + (*cb)(*reinterpret_cast(&anchor), + *reinterpret_cast(&focus), + (isAnchorFirst != 0)); + }; + std::unique_ptr> cb{}; + cb.reset(new std::function(std::move(onImeSelectionBoundsChanged))); + internal_->set_ime_selection_bounds_callback(internal_, cb.release(), wrapper); +} + +bool OverlayManager::IsPointInsideClickZone(std::int32_t x, std::int32_t y) +{ + auto result = internal_->is_point_inside_click_zone(internal_, x, y); + return (result != 0); +} + +} // namespace discord diff --git a/Minecraft.Client/Windows64/ExtraLibs/discordsdk/overlay_manager.h b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/overlay_manager.h new file mode 100644 index 00000000..5f73a367 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/overlay_manager.h @@ -0,0 +1,57 @@ +#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); + Result InitDrawingDxgi(IDXGISwapChain* swapchain, bool useMessageForwarding); + void OnPresent(); + void ForwardMessage(MSG* message); + void KeyEvent(bool down, char const* keyCode, KeyVariant variant); + void CharEvent(char const* character); + void MouseButtonEvent(std::uint8_t down, + std::int32_t clickCount, + MouseButton which, + std::int32_t x, + std::int32_t y); + void MouseMotionEvent(std::int32_t x, std::int32_t y); + void ImeCommitText(char const* text); + void ImeSetComposition(char const* text, + ImeUnderline* underlines, + std::uint32_t underlinesLength, + std::int32_t from, + std::int32_t to); + void ImeCancelComposition(); + void SetImeCompositionRangeCallback( + std::function + onImeCompositionRangeChanged); + void SetImeSelectionBoundsCallback( + std::function onImeSelectionBoundsChanged); + bool IsPointInsideClickZone(std::int32_t x, std::int32_t y); + + 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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/relationship_manager.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/relationship_manager.cpp new file mode 100644 index 00000000..dce874ea --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/relationship_manager.cpp @@ -0,0 +1,91 @@ +#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 DISCORD_CALLBACK OnRefresh(void* callbackData) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->RelationshipManager(); + module.OnRefresh(); + } + + static void DISCORD_CALLBACK 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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/relationship_manager.h b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/relationship_manager.h new file mode 100644 index 00000000..e9cd0161 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/storage_manager.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/storage_manager.cpp new file mode 100644 index 00000000..fbf9ca75 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/storage_manager.h b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/storage_manager.h new file mode 100644 index 00000000..5d6d17b1 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/store_manager.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/store_manager.cpp new file mode 100644 index 00000000..40c7e656 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/store_manager.cpp @@ -0,0 +1,162 @@ +#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 DISCORD_CALLBACK OnEntitlementCreate(void* callbackData, + DiscordEntitlement* entitlement) + { + auto* core = reinterpret_cast(callbackData); + if (!core) { + return; + } + + auto& module = core->StoreManager(); + module.OnEntitlementCreate(*reinterpret_cast(entitlement)); + } + + static void DISCORD_CALLBACK 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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/store_manager.h b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/store_manager.h new file mode 100644 index 00000000..8e0df8ac --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/types.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/types.cpp new file mode 100644 index 00000000..b60dded0 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/types.cpp @@ -0,0 +1,879 @@ +#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 ActivityParty::SetPrivacy(ActivityPartyPrivacy privacy) +{ + internal_.privacy = static_cast(privacy); +} + +ActivityPartyPrivacy ActivityParty::GetPrivacy() const +{ + return static_cast(internal_.privacy); +} + +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 Activity::SetSupportedPlatforms(std::uint32_t supportedPlatforms) +{ + internal_.supported_platforms = supportedPlatforms; +} + +std::uint32_t Activity::GetSupportedPlatforms() const +{ + return internal_.supported_platforms; +} + +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 ImeUnderline::SetFrom(std::int32_t from) +{ + internal_.from = from; +} + +std::int32_t ImeUnderline::GetFrom() const +{ + return internal_.from; +} + +void ImeUnderline::SetTo(std::int32_t to) +{ + internal_.to = to; +} + +std::int32_t ImeUnderline::GetTo() const +{ + return internal_.to; +} + +void ImeUnderline::SetColor(std::uint32_t color) +{ + internal_.color = color; +} + +std::uint32_t ImeUnderline::GetColor() const +{ + return internal_.color; +} + +void ImeUnderline::SetBackgroundColor(std::uint32_t backgroundColor) +{ + internal_.background_color = backgroundColor; +} + +std::uint32_t ImeUnderline::GetBackgroundColor() const +{ + return internal_.background_color; +} + +void ImeUnderline::SetThick(bool thick) +{ + internal_.thick = thick; +} + +bool ImeUnderline::GetThick() const +{ + return internal_.thick != 0; +} + +void Rect::SetLeft(std::int32_t left) +{ + internal_.left = left; +} + +std::int32_t Rect::GetLeft() const +{ + return internal_.left; +} + +void Rect::SetTop(std::int32_t top) +{ + internal_.top = top; +} + +std::int32_t Rect::GetTop() const +{ + return internal_.top; +} + +void Rect::SetRight(std::int32_t right) +{ + internal_.right = right; +} + +std::int32_t Rect::GetRight() const +{ + return internal_.right; +} + +void Rect::SetBottom(std::int32_t bottom) +{ + internal_.bottom = bottom; +} + +std::int32_t Rect::GetBottom() const +{ + return internal_.bottom; +} + +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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/types.h b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/types.h new file mode 100644 index 00000000..76c43117 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/types.h @@ -0,0 +1,567 @@ +#pragma once + +#include "ffi.h" +#include "event.h" +#ifdef _WIN32 +#include +#include +#endif + +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, + DrawingInitFailed = 44, +}; + +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 ActivityPartyPrivacy { + Private = 0, + Public = 1, +}; + +enum class ActivityType { + Playing, + Streaming, + Listening, + Watching, +}; + +enum class ActivityActionType { + Join = 1, + Spectate, +}; + +enum class ActivitySupportedPlatformFlags { + Desktop = 1, + Android = 2, + iOS = 4, +}; + +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 KeyVariant { + Normal, + Right, + Left, +}; + +enum class MouseButton { + Left, + Middle, + Right, +}; + +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; +#ifdef __APPLE__ +using IDXGISwapChain = void; +#endif +#ifdef __linux__ +using IDXGISwapChain = void; +#endif +#ifdef __APPLE__ +using MSG = void; +#endif +#ifdef __linux__ +using MSG = void; +#endif +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; + void SetPrivacy(ActivityPartyPrivacy privacy); + ActivityPartyPrivacy GetPrivacy() 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; + void SetSupportedPlatforms(std::uint32_t supportedPlatforms); + std::uint32_t GetSupportedPlatforms() 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 ImeUnderline final { +public: + void SetFrom(std::int32_t from); + std::int32_t GetFrom() const; + void SetTo(std::int32_t to); + std::int32_t GetTo() const; + void SetColor(std::uint32_t color); + std::uint32_t GetColor() const; + void SetBackgroundColor(std::uint32_t backgroundColor); + std::uint32_t GetBackgroundColor() const; + void SetThick(bool thick); + bool GetThick() const; + +private: + DiscordImeUnderline internal_; +}; + +class Rect final { +public: + void SetLeft(std::int32_t left); + std::int32_t GetLeft() const; + void SetTop(std::int32_t top); + std::int32_t GetTop() const; + void SetRight(std::int32_t right); + std::int32_t GetRight() const; + void SetBottom(std::int32_t bottom); + std::int32_t GetBottom() const; + +private: + DiscordRect 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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/user_manager.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/user_manager.cpp new file mode 100644 index 00000000..ddb6d5ca --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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 DISCORD_CALLBACK 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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/user_manager.h b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/user_manager.h new file mode 100644 index 00000000..d85de1b5 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/voice_manager.cpp b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/voice_manager.cpp new file mode 100644 index 00000000..014ceb3f --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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 DISCORD_CALLBACK 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/Minecraft.Client/Windows64/ExtraLibs/discordsdk/voice_manager.h b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/voice_manager.h new file mode 100644 index 00000000..95b20e99 --- /dev/null +++ b/Minecraft.Client/Windows64/ExtraLibs/discordsdk/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/Minecraft.Client/Windows64/Windows64_Launcher.cpp b/Minecraft.Client/Windows64/Windows64_Launcher.cpp index 0a9a4b96..53321936 100644 --- a/Minecraft.Client/Windows64/Windows64_Launcher.cpp +++ b/Minecraft.Client/Windows64/Windows64_Launcher.cpp @@ -20,84 +20,76 @@ #include #include -#include "./ExtraLibs/discordrpc/discord_rpc.h" +#include "./ExtraLibs/discordsdk/discord.h" float g_sleepPercentage = 100; int g_autosaveInterval = 120; +std::string g_discordUserId = ""; + bool g_doBoatBreak = true; +discord::Core* g_discordCore = nullptr; -DWORD WINAPI DiscordRPCThreadFunc(LPVOID lpParam) { - DiscordEventHandlers handlers; - memset(&handlers, 0, sizeof(handlers)); +DWORD WINAPI DiscordCallbackThreadFunc(LPVOID lpParam) { + auto result = discord::Core::Create(1424889204110004316LL, DiscordCreateFlags_NoRequireDiscord, &g_discordCore); - const char* applicationId = "1424889204110004316"; - Discord_Initialize(applicationId, &handlers, 1, NULL); - - DiscordRichPresence presence; - memset(&presence, 0, sizeof(presence)); - presence.startTimestamp = time(0); - static std::string detailsStr = "Playing as " + Windows64Launcher::GetUsername(); - presence.details = detailsStr.c_str(); - presence.button1Label = "Join The Discord"; - presence.button1Url = "https://discord.gg/u9f67jaWyP"; - presence.button2Label = "Download On Github"; - presence.button2Url = "https://github.com/mclemp/MCLEClient"; - presence.largeImageKey = "MCLE"; - presence.largeImageText = "MCLE"; - - Discord_UpdatePresence(&presence); - - const char* lastSmallImageKey = (const char*)1; + if (result != discord::Result::Ok || !g_discordCore) { + return 1; + } while (true) { - Discord_RunCallbacks(); + g_discordCore->RunCallbacks(); + Sleep(100); + } - const char* newSmallImageKey = nullptr; - const char* newSmallImageText = nullptr; + return 0; +} +DWORD WINAPI DiscordRPCThreadFunc(LPVOID lpParam) { + while (!g_discordCore) { + Sleep(100); + } + + discord::Activity activity{}; + activity.GetTimestamps().SetStart(time(0)); + static std::string detailsStr = "Playing as " + Windows64Launcher::GetUsername(); + activity.SetDetails(detailsStr.c_str()); + activity.GetAssets().SetLargeImage("MCLE"); + activity.GetAssets().SetLargeText("MCLE"); + g_discordCore->ActivityManager().UpdateActivity(activity, [](discord::Result r) {}); + + while (true) { Minecraft* minecraft = Minecraft::GetInstance(); - if (minecraft && minecraft->player) - { - switch (minecraft->player->dimension) - { + if (minecraft && minecraft->player) { + discord::Activity updatedActivity{}; + updatedActivity.SetDetails(detailsStr.c_str()); + + switch (minecraft->player->dimension) { case -1: - newSmallImageKey = "nether"; - newSmallImageText = "In The Nether"; + updatedActivity.GetAssets().SetSmallImage("nether"); + updatedActivity.GetAssets().SetSmallText("In The Nether"); break; case 0: - newSmallImageKey = "overworld"; - newSmallImageText = "In The Overworld"; + updatedActivity.GetAssets().SetSmallImage("overworld"); + updatedActivity.GetAssets().SetSmallText("In The Overworld"); break; case 1: - newSmallImageKey = "end"; - newSmallImageText = "In The End"; + updatedActivity.GetAssets().SetSmallImage("end"); + updatedActivity.GetAssets().SetSmallText("In The End"); break; - default: - newSmallImageKey = ""; - newSmallImageText = ""; - break; - } - } + } - if (newSmallImageKey != lastSmallImageKey) - { - presence.smallImageKey = newSmallImageKey; - presence.smallImageText = newSmallImageText; - lastSmallImageKey = newSmallImageKey; - Discord_UpdatePresence(&presence); + g_discordCore->ActivityManager().UpdateActivity(updatedActivity, [](discord::Result r) {}); } Sleep(2000); } - Discord_Shutdown(); return 0; } - -static ATOM RegisterLauncherClass(HINSTANCE hInstance); +static ATOM RegisterLauncherClass(HINSTANCE hInstance); static BOOL InitWindow(HINSTANCE hInstance); HWND launcher_HWND = NULL; @@ -111,6 +103,7 @@ HWND hBtnLaunch; HWND hBtnLogout; HWND hBtnDiscord; +HWND hBtnDiscordLogin; HWND hBtnRegister; HWND hBtnLogin; @@ -125,12 +118,14 @@ HWND hLoginUsernameLabel; std::string username = ""; std::string authenticationToken = ""; -bool startedThread = false; +bool startedCallbackThread = false; +bool startedRPCThread = false; bool offlinemode = false; bool Windows64Launcher::IsInOfflineMode() { return offlinemode; } void onSuccessfulLogin(); +void onAccountLogout(); void onLoginFailed(); void AttemptFullLoginFlow(); @@ -194,14 +189,36 @@ void onSuccessfulLogin() { ShowWindow(hBtnRegister, SW_HIDE); ShowWindow(hBtnLogin, SW_HIDE); - if (!startedThread) { + ShowWindow(hBtnDiscordLogin, SW_HIDE); + + if (!startedRPCThread) { HANDLE hThread = CreateThread(NULL, 0, DiscordRPCThreadFunc, NULL, 0, NULL); CloseHandle(hThread); - startedThread = true; + startedRPCThread = true; } } +void onAccountLogout() { + Windows64Launcher::SaveAuthenticationData("", username); + + ShowWindow(hBtnLaunch, SW_HIDE); + ShowWindow(hBtnOffline, SW_HIDE); + + ShowWindow(hBtnLogout, SW_HIDE); + ShowWindow(hLoginUsernameLabel, SW_HIDE); + + ShowWindow(hUsernameLabel, SW_SHOW); + ShowWindow(hUsernameEdit, SW_SHOW); + ShowWindow(hPasswordLabel, SW_SHOW); + ShowWindow(hPasswordEdit, SW_SHOW); + + ShowWindow(hBtnRegister, SW_SHOW); + ShowWindow(hBtnLogin, SW_SHOW); + + ShowWindow(hBtnDiscordLogin, SW_SHOW); +} + void onLoginFailed() { ShowWindow(hBtnLaunch, SW_HIDE); ShowWindow(hBtnOffline, SW_HIDE); @@ -218,9 +235,14 @@ void onLoginFailed() { ShowWindow(hBtnLogin, SW_SHOW); } - - LRESULT OnWindowCreation(HWND hWnd) { + if (!startedCallbackThread) { + HANDLE hThread = CreateThread(NULL, 0, DiscordCallbackThreadFunc, NULL, 0, NULL); + CloseHandle(hThread); + + startedCallbackThread = true; + } + hBottomBar = CreateWindowW(L"STATIC", nullptr, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hWnd, nullptr, nullptr, nullptr); hStatusText = CreateWindowW(L"STATIC", L"Version: " L"" LAUNCHER_VERSION, WS_CHILD | WS_VISIBLE, 10, 10, 200, 20, hBottomBar, nullptr, nullptr, nullptr); @@ -235,6 +257,8 @@ LRESULT OnWindowCreation(HWND hWnd) { hBtnDiscord = CreateWindowW(L"BUTTON", L"Discord", WS_CHILD | WS_VISIBLE, 0, 0, 80, 25, hWnd, (HMENU)6, nullptr, nullptr); + hBtnDiscordLogin = CreateWindowW(L"BUTTON", L"Discord Login", WS_CHILD | WS_VISIBLE, 0, 0, 80, 25, hWnd, (HMENU)7, nullptr, nullptr); + hUsernameLabel = CreateWindowW(L"STATIC", L"Username:", WS_CHILD | WS_VISIBLE, 0, 0, 80, 20, hWnd, nullptr, nullptr, nullptr); hUsernameEdit = CreateWindowW(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 0, 0, 180, 25, hWnd, nullptr, nullptr, nullptr); hPasswordLabel = CreateWindowW(L"STATIC", L"Password:", WS_CHILD | WS_VISIBLE, 0, 0, 80, 20, hWnd, nullptr, nullptr, nullptr); @@ -242,7 +266,6 @@ LRESULT OnWindowCreation(HWND hWnd) { hLoginUsernameLabel = CreateWindowW(L"STATIC", L"Welcome: Placeholder", WS_CHILD | WS_VISIBLE, 0, 0, 300, 20, hWnd, nullptr, nullptr, nullptr); - return 0; } @@ -259,6 +282,9 @@ LRESULT OnWindowSize(int width, int height) { MoveWindow(hBtnDiscord, centerX, 125, labelWidth, 20, TRUE); + MoveWindow(hBtnDiscord, centerX - 5, 125, 75, 20, TRUE); + MoveWindow(hBtnDiscordLogin, centerX + 75, 125, 95, 20, TRUE); + // Username MoveWindow(hUsernameLabel, centerX - labelWidth + 50, startY - 5, labelWidth, 20, TRUE); MoveWindow(hUsernameEdit, centerX + 50, startY - 8, inputWidth, inputHeight, TRUE); @@ -393,6 +419,24 @@ LRESULT OnAccountLogin() { return 0; } +LRESULT OnDiscordLogin() { + if (!g_discordCore) { + MessageBoxW(launcher_HWND, L"Discord is not running.", L"Discord Login", MB_OK); + return 0; + } + + g_discordCore->ApplicationManager().GetOAuth2Token([](discord::Result res, discord::OAuth2Token const& token) { + if (res != discord::Result::Ok) { + PostMessageA(launcher_HWND, WM_APP + 2, 0, 0); + return; + } + std::string t = token.GetAccessToken(); + PostMessageA(launcher_HWND, WM_APP + 1, 0, (LPARAM)new std::string(t)); + }); + + return 0; +} + LRESULT OnCommandReceived(HWND hWnd, int type) { switch (type) { case 1: // Launch @@ -412,22 +456,51 @@ LRESULT OnCommandReceived(HWND hWnd, int type) { OnAccountLogin(); break; case 5: //Logout - Windows64Launcher::SaveAuthenticationData("", username); - onLoginFailed(); + onAccountLogout(); break; case 6: //Discord - { - ShellExecute(0, 0, "https://discord.gg/xjc9JW4Bfp", 0, 0 , SW_SHOW ); - } - break; + ShellExecute(0, 0, "https://discord.gg/xjc9JW4Bfp", 0, 0, SW_SHOW); + break; + case 7: //Discord Login + OnDiscordLogin(); + break; } return 0; } LRESULT CALLBACK WndProc_Launcher(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - switch (message) { + case WM_APP + 1: { // Discord token received — on main thread + std::string* token = reinterpret_cast(lParam); + + int response = Windows64Launcher::API_AttemptDiscordLogin(*token, authenticationToken); + delete token; + + if (response == 0) { + Windows64Launcher::SaveAuthenticationData(authenticationToken, username); + AttemptFullLoginFlow(); + } + else if (response == 1111) { + MessageBoxW(launcher_HWND, L"Invalid Username / Password", L"Login Failed", MB_OK); + } + else if (response == 2222) { + MessageBoxW(launcher_HWND, L"You Have Been Banned", L"Login Failed", MB_OK); + } + else if (response == 3333) { + MessageBoxW(launcher_HWND, L"Invalid OAuth token", L"Discord Login", MB_OK); + } + else if (response == 4444) { + MessageBoxW(launcher_HWND, L"Discord isnt linked to any account", L"Discord Login", MB_OK); + } + else { + MessageBoxW(launcher_HWND, std::wstring(L"Unknown Error: " + std::to_wstring(response)).c_str(), L"Discord Login", MB_OK); + } + return 0; + } + case WM_APP + 2: + MessageBoxW(hWnd, L"Failed to get Discord token.\nMake sure Discord is open.", L"Discord Login", MB_OK); + return 0; case WM_COMMAND: return OnCommandReceived(hWnd, LOWORD(wParam)); case WM_SIZE: @@ -637,6 +710,27 @@ int Windows64Launcher::API_AttemptAccountLogin(const std::string _username, cons return 0; } +int Windows64Launcher::API_AttemptDiscordLogin(const std::string& ticket, std::string& tokenOut) { + std::vector headers; + headers.push_back(L"Content-Type: text/plain"); + + HttpResponse response = WinsockNetLayer::DoWinHttpRequest(L"/discordLogin", L"POST", ticket, headers); + + if (response.status == 0) return -1; + if (response.status != 200) return (20000 + response.status); + if (response.body.find('-') == std::string::npos) return stoi(response.body); + + std::string body = response.body.erase(0, 1); + size_t colonPos = body.find(':'); + if (colonPos == std::string::npos) return -2; + + username = body.substr(0, colonPos); + authenticationToken = body.substr(colonPos + 1); + tokenOut = authenticationToken; + + return 0; +} + static std::string ExtractJsonString(const std::string& json, const std::string& key) { std::string search = "\"" + key + "\""; size_t pos = json.find(search); diff --git a/Minecraft.Client/Windows64/Windows64_Launcher.h b/Minecraft.Client/Windows64/Windows64_Launcher.h index 5913c4b8..4836ca93 100644 --- a/Minecraft.Client/Windows64/Windows64_Launcher.h +++ b/Minecraft.Client/Windows64/Windows64_Launcher.h @@ -23,15 +23,10 @@ public: static int API_GetAccountInfo(const std::string token); static int API_AttemptAccountRegister(const std::string username, const std::string password, std::string& tokenOut); static int API_AttemptAccountLogin(const std::string username, const std::string password, std::string& tokenOut); + static int API_AttemptDiscordLogin(const std::string& accessToken, std::string& tokenOut); static bool IsInOfflineMode(); - static std::vector GetBannedUsersList(); - static void SaveBannedUsersList(std::vector bannedUsers); - static const std::string& GetAuthenticationToken(); static const std::string& GetUsername(); - - static void CheckForUpdates(); - }; \ No newline at end of file diff --git a/Minecraft.Client/cmake/sources/Windows.cmake b/Minecraft.Client/cmake/sources/Windows.cmake index 95a40868..bc944cb1 100644 --- a/Minecraft.Client/cmake/sources/Windows.cmake +++ b/Minecraft.Client/cmake/sources/Windows.cmake @@ -355,15 +355,23 @@ set(_MINECRAFT_CLIENT_WINDOWS64_LAUNCHER ) source_group("Windows64/Launcher" FILES ${_MINECRAFT_CLIENT_WINDOWS64_LAUNCHER}) -set(_MINECRAFT_CLIENT_WINDOWS64_DISCORDRPC - "${BASE_DIR}/Extralibs/discordrpc/discord_register_win.cpp" - "${BASE_DIR}/Extralibs/discordrpc/connection_win.cpp" - "${BASE_DIR}/Extralibs/discordrpc/rpc_connection.cpp" - "${BASE_DIR}/Extralibs/discordrpc/serialization.cpp" - "${BASE_DIR}/Extralibs/discordrpc/discord_rpc.cpp" - "${BASE_DIR}/Extralibs/discordrpc/dllmain.cpp" +set(_MINECRAFT_CLIENT_WINDOWS64_DISCORDSDK + "${BASE_DIR}/ExtraLibs/discordsdk/achievement_manager.cpp" + "${BASE_DIR}/ExtraLibs/discordsdk/activity_manager.cpp" + "${BASE_DIR}/ExtraLibs/discordsdk/application_manager.cpp" + "${BASE_DIR}/ExtraLibs/discordsdk/core.cpp" + "${BASE_DIR}/ExtraLibs/discordsdk/image_manager.cpp" + "${BASE_DIR}/ExtraLibs/discordsdk/lobby_manager.cpp" + "${BASE_DIR}/ExtraLibs/discordsdk/network_manager.cpp" + "${BASE_DIR}/ExtraLibs/discordsdk/overlay_manager.cpp" + "${BASE_DIR}/ExtraLibs/discordsdk/relationship_manager.cpp" + "${BASE_DIR}/ExtraLibs/discordsdk/storage_manager.cpp" + "${BASE_DIR}/ExtraLibs/discordsdk/store_manager.cpp" + "${BASE_DIR}/ExtraLibs/discordsdk/types.cpp" + "${BASE_DIR}/ExtraLibs/discordsdk/user_manager.cpp" + "${BASE_DIR}/ExtraLibs/discordsdk/voice_manager.cpp" ) -source_group("Windows64/Discordrpc" FILES ${_MINECRAFT_CLIENT_WINDOWS64_DISCORDRPC}) +source_group("Windows64/discordsdk" FILES ${_MINECRAFT_CLIENT_WINDOWS64_DISCORDSDK}) set(_MINECRAFT_CLIENT_WINDOWS_WINDOWS64_4JLIBS_INC "${BASE_DIR}/4JLibs/inc/4J_Input.h" @@ -499,7 +507,7 @@ set(MINECRAFT_CLIENT_WINDOWS ${_MINECRAFT_CLIENT_WINDOWS_WINDOWS} ${_MINECRAFT_CLIENT_WINDOWS_WINDOWS64} ${_MINECRAFT_CLIENT_WINDOWS64_LAUNCHER} - ${_MINECRAFT_CLIENT_WINDOWS64_DISCORDRPC} + ${_MINECRAFT_CLIENT_WINDOWS64_DISCORDSDK} ${_MINECRAFT_CLIENT_WINDOWS_WINDOWS64_4JLIBS_INC} ${_MINECRAFT_CLIENT_WINDOWS_WINDOWS64_GAMECONFIG} ${_MINECRAFT_CLIENT_WINDOWS_WINDOWS64_IGGY_GDRAW}