From d85556a063b8af88424420e2364d9460c931ae40 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Sun, 19 Apr 2026 22:27:29 -0700 Subject: [PATCH 1/4] Use vendored SDL on ubuntu for libusb (#448) --- CMakePresets.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakePresets.json b/CMakePresets.json index 89c78818f9..92799249a9 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -358,7 +358,10 @@ "inherits": [ "relwithdebinfo", "ci" - ] + ], + "cacheVariables": { + "AURORA_SDL3_PROVIDER": "vendor" + } }, { "name": "x-linux-ci-gcc", From e3761784af86f918c94a074bcef6e47124a1b6de Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 20 Apr 2026 00:21:09 -0700 Subject: [PATCH 2/4] rich presence --- CMakeLists.txt | 42 ++++++++++ files.cmake | 1 + include/dusk/discord_presence.hpp | 18 +++++ src/dusk/discord_presence.cpp | 122 ++++++++++++++++++++++++++++++ src/m_Do/m_Do_main.cpp | 16 ++++ 5 files changed, 199 insertions(+) create mode 100644 include/dusk/discord_presence.hpp create mode 100644 src/dusk/discord_presence.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c99133738b..37340576cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -316,6 +316,48 @@ if (DUSK_MOVIE_SUPPORT) list(APPEND GAME_COMPILE_DEFS MOVIE_SUPPORT=1) endif () +option(DUSK_ENABLE_DISCORD_RPC "Enable Discord Rich Presence support" ON) +if (DUSK_ENABLE_DISCORD_RPC AND NOT ANDROID AND NOT IOS AND NOT TVOS) + + FetchContent_Populate(discord_rpc + URL https://github.com/discord/discord-rpc/archive/refs/tags/v3.4.0.tar.gz + URL_HASH SHA256=e13427019027acd187352dacba6c65953af66fdf3c35fcf38fc40b454a9d7855 + DOWNLOAD_EXTRACT_TIMESTAMP TRUE + ) + # RapidJSON is a git submodule absent from the discord-rpc tarball; fetch separately. + FetchContent_Populate(rapidjson + URL https://github.com/Tencent/rapidjson/archive/refs/tags/v1.1.0.tar.gz + URL_HASH SHA256=bf7ced29704a1e696fbccf2a2b4ea068e7774fa37f6d7dd4039d0787f8bed98e + DOWNLOAD_EXTRACT_TIMESTAMP TRUE + ) + + if (NOT TARGET discord-rpc) + set(_drpc ${discord_rpc_SOURCE_DIR}/src) + set(_drpc_src + ${_drpc}/discord_rpc.cpp + ${_drpc}/rpc_connection.cpp + ${_drpc}/serialization.cpp + ) + if (WIN32) + list(APPEND _drpc_src ${_drpc}/connection_win.cpp ${_drpc}/discord_register_win.cpp) + elseif (APPLE) + list(APPEND _drpc_src ${_drpc}/connection_unix.cpp ${_drpc}/discord_register_osx.cpp) + else () + list(APPEND _drpc_src ${_drpc}/connection_unix.cpp ${_drpc}/discord_register_linux.cpp) + endif () + add_library(discord-rpc STATIC ${_drpc_src}) + target_include_directories(discord-rpc PUBLIC + ${discord_rpc_SOURCE_DIR}/include + ${rapidjson_SOURCE_DIR}/include + ) + if (UNIX) + target_link_libraries(discord-rpc PUBLIC pthread) + endif () + endif () + list(APPEND GAME_LIBS discord-rpc) + list(APPEND GAME_COMPILE_DEFS DUSK_DISCORD_RPC=1) +endif () + # Edit & Continue if (MSVC) if ("${CMAKE_MSVC_DEBUG_INFORMATION_FORMAT}" STREQUAL "" AND CMAKE_BUILD_TYPE STREQUAL "Debug") diff --git a/files.cmake b/files.cmake index d43e98bf42..e929ec85b0 100644 --- a/files.cmake +++ b/files.cmake @@ -1387,4 +1387,5 @@ set(DUSK_FILES src/dusk/OSContext.cpp src/dusk/OSThread.cpp src/dusk/OSMutex.cpp + src/dusk/discord_presence.cpp ) diff --git a/include/dusk/discord_presence.hpp b/include/dusk/discord_presence.hpp new file mode 100644 index 0000000000..899b2ad5f9 --- /dev/null +++ b/include/dusk/discord_presence.hpp @@ -0,0 +1,18 @@ +#pragma once + +#ifdef DUSK_DISCORD_RPC + +namespace dusk { +namespace discord { + +void Initialize(); + +void RunCallbacks(); + +void UpdatePresence(); + +void Shutdown(); +} +} + +#endif // DUSK_DISCORD_RPC diff --git a/src/dusk/discord_presence.cpp b/src/dusk/discord_presence.cpp new file mode 100644 index 0000000000..3b12075c8b --- /dev/null +++ b/src/dusk/discord_presence.cpp @@ -0,0 +1,122 @@ +#ifdef DUSK_DISCORD_RPC + +#include "dusk/discord_presence.hpp" +#include "dusk/logging.h" +#include "dusk/main.h" +#include "dusk/map_loader_definitions.h" +#include "d/d_com_inf_game.h" +#include "discord_rpc.h" +#include "fmt/format.h" + +#include +#include +#include + +namespace dusk { +namespace discord { + +static int64_t g_startTime = 0; +static bool g_initialized = false; +static const char* APPLICATION_ID = "1495632471994405035"; + +static void OnReady(const DiscordUser* user) { + DuskLog.info("Discord: Connected as {}", user->username); +} + +static void OnDisconnected(int errorCode, const char* message) { + DuskLog.warn("Discord: Disconnected ({}: {})", errorCode, message); +} + +static void OnError(int errorCode, const char* message) { + DuskLog.warn("Discord: Error ({}: {})", errorCode, message); +} + +static const char* LookupMapName(const char* mapFile) { + if (!mapFile || mapFile[0] == '\0') return nullptr; + for (const auto& region : gameRegions) { + for (const auto& map : region.maps) { + if (map.mapFile && strcmp(mapFile, map.mapFile) == 0) { + return map.mapName; + } + } + } + return nullptr; +} + +void Initialize() { + g_startTime = static_cast( + std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch() + ).count() + ); + + DiscordEventHandlers handlers{}; + handlers.ready = OnReady; + handlers.disconnected = OnDisconnected; + handlers.errored = OnError; + Discord_Initialize(APPLICATION_ID, &handlers, 0, nullptr); + g_initialized = true; + + DuskLog.info("Discord Rich Presence initialized"); +} + +void RunCallbacks() { + if (!g_initialized) return; + Discord_RunCallbacks(); +} + +void UpdatePresence() { + if (!g_initialized) return; + + static auto lastUpdate = std::chrono::steady_clock::time_point{}; + const auto now = std::chrono::steady_clock::now(); + if (now - lastUpdate < std::chrono::seconds(15)) return; + lastUpdate = now; + + static std::string detailsBuf; + static std::string stateBuf; + + DiscordRichPresence presence{}; + presence.startTimestamp = g_startTime; + presence.largeImageKey = "icon"; + presence.largeImageText = "Dusk"; + + if (dusk::IsGameLaunched) { + const char* stageName = dComIfGp_getLastPlayStageName(); + + // stageName is empty until a room is actually entered + if (stageName[0] != '\0') { + const char* locationName = LookupMapName(stageName); + + if (locationName) { + detailsBuf = locationName; + } + else { + detailsBuf = "Twilight Princess"; + } + + presence.details = detailsBuf.c_str(); + + stateBuf = fmt::format(FMT_STRING("{}/{} \u2665 | {} Rupees"), + dComIfGs_getLife() / 4, dComIfGs_getMaxLife() / 5, dComIfGs_getRupee()); + + presence.state = stateBuf.c_str(); + } + } + + Discord_UpdatePresence(&presence); + DuskLog.debug("Discord Rich Presence sent"); +} + +void Shutdown() { + if (!g_initialized) return; + Discord_ClearPresence(); + Discord_Shutdown(); + g_initialized = false; + DuskLog.info("Discord Rich Presence shut down"); +} + +} // namespace discord +} // namespace dusk + +#endif // DUSK_DISCORD_RPC diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index cde7014411..c597ad2804 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -70,6 +70,7 @@ #include "dusk/config.hpp" #include "dusk/settings.h" #include "dusk/imgui/ImGuiConsole.hpp" +#include "dusk/discord_presence.hpp" #include "tracy/Tracy.hpp" #include "f_pc/f_pc_draw.h" @@ -289,6 +290,11 @@ void main01(void) { aurora_end_frame(); FrameMark; + +#ifdef DUSK_DISCORD_RPC + dusk::discord::RunCallbacks(); + dusk::discord::UpdatePresence(); +#endif } while (dusk::IsRunning); exit:; @@ -531,6 +537,10 @@ int game_main(int argc, char* argv[]) { auroraInfo = aurora_initialize(argc, argv, &config); +#ifdef DUSK_DISCORD_RPC + dusk::discord::Initialize(); +#endif + VISetWindowTitle( fmt::format("Dusk {} [{}]", DUSK_WC_DESCRIBE, dusk::backend_name(auroraInfo.backend)) .c_str()); @@ -564,6 +574,9 @@ int game_main(int argc, char* argv[]) { // pre game launch ui main loop if (!launchUILoop()) { dusk::ShutdownCrashReporting(); +#ifdef DUSK_DISCORD_RPC + dusk::discord::Shutdown(); +#endif aurora_shutdown(); return 0; } @@ -611,6 +624,9 @@ int game_main(int argc, char* argv[]) { // Notifies all CVs and causes threads to exit OSResetSystem(OS_RESET_SHUTDOWN, 0, 0); +#ifdef DUSK_DISCORD_RPC + dusk::discord::Shutdown(); +#endif aurora_shutdown(); return 0; From 10d9a818c2f54b12ae384874041beb46a389366e Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 20 Apr 2026 00:31:41 -0700 Subject: [PATCH 3/4] fix apple ci? --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 37340576cb..e8132a98fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -341,7 +341,7 @@ if (DUSK_ENABLE_DISCORD_RPC AND NOT ANDROID AND NOT IOS AND NOT TVOS) if (WIN32) list(APPEND _drpc_src ${_drpc}/connection_win.cpp ${_drpc}/discord_register_win.cpp) elseif (APPLE) - list(APPEND _drpc_src ${_drpc}/connection_unix.cpp ${_drpc}/discord_register_osx.cpp) + list(APPEND _drpc_src ${_drpc}/connection_unix.cpp ${_drpc}/discord_register_osx.m) else () list(APPEND _drpc_src ${_drpc}/connection_unix.cpp ${_drpc}/discord_register_linux.cpp) endif () From 6ca6ea806534d46248854ba83bde82bd88f66607 Mon Sep 17 00:00:00 2001 From: TakaRikka Date: Mon, 20 Apr 2026 04:16:35 -0700 Subject: [PATCH 4/4] fix crawl arrow direction with mirror mode --- src/d/actor/d_a_alink_crawl.inc | 38 ++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/d/actor/d_a_alink_crawl.inc b/src/d/actor/d_a_alink_crawl.inc index 4a657c1de8..2dbf88d3e1 100644 --- a/src/d/actor/d_a_alink_crawl.inc +++ b/src/d/actor/d_a_alink_crawl.inc @@ -37,18 +37,40 @@ void daAlink_c::setCrawlMoveDirectionArrow() { } if (field_0x3198 & 4) { - if (!bvar) { - direction |= data_80452F38; - } else { - direction |= data_80452F39; + #if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + if (!bvar) { + direction |= data_80452F39; + } else { + direction |= data_80452F38; + } + } else + #endif + { + if (!bvar) { + direction |= data_80452F38; + } else { + direction |= data_80452F39; + } } } if (field_0x3198 & 8) { - if (!bvar) { - direction |= data_80452F39; - } else { - direction |= data_80452F38; + #if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + if (!bvar) { + direction |= data_80452F38; + } else { + direction |= data_80452F39; + } + } else + #endif + { + if (!bvar) { + direction |= data_80452F39; + } else { + direction |= data_80452F38; + } } }