diff --git a/CMakeLists.txt b/CMakeLists.txt index 347198ab2..c6317417b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,6 +90,7 @@ option(CLIENT "Compile client" ON) option(DOWNLOAD_GTEST "Download and compile GTest" ${AUTO_DEPENDENCIES_DEFAULT}) option(STEAM "Build the Steam release version" OFF) option(DISCORD "Enable Discord rich presence support" OFF) +option(DISCORD_DYNAMIC "Enable discovering Discord rich presence libraries at runtime (Linux only)" OFF) option(PREFER_BUNDLED_LIBS "Prefer bundled libraries over system libraries" ${AUTO_DEPENDENCIES_DEFAULT}) option(DEV "Don't generate stuff necessary for packaging" OFF) @@ -267,8 +268,6 @@ endfunction() function(set_own_rpath TARGET) if(NOT TARGET_OS STREQUAL "windows" AND NOT TARGET_OS STREQUAL "mac") if(CMAKE_VERSION VERSION_GREATER 3.14 OR CMAKE_VERSION VERSION_EQUAL 3.14) - set_property(TARGET ${TARGET} PROPERTY BUILD_RPATH_USE_ORIGIN TRUE) - elseif(CMAKE_VERSION VERSION_GREATER 3.8 OR CMAKE_VERSION VERSION_EQUAL 3.8) set_property(TARGET ${TARGET} PROPERTY BUILD_RPATH "$ORIGIN") endif() set_property(TARGET ${TARGET} PROPERTY INSTALL_RPATH "$ORIGIN/../lib/ddnet") @@ -276,7 +275,7 @@ function(set_own_rpath TARGET) endfunction() if(NOT TARGET_OS STREQUAL "windows" AND NOT TARGET_OS STREQUAL "mac" AND CMAKE_VERSION VERSION_LESS 3.8) - if((CLIENT AND STEAM) OR ANTIBOT) + if((CLIENT AND (STEAM OR DISCORD_DYNAMIC)) OR ANTIBOT) message(STATUS "Can't set BUILD_RPATH in CMake before 3.8, pass -Wl,-rpath,'$ORIGIN' manually if you wish to emulate this. Or just install a newer version of CMake...") endif() endif() @@ -487,11 +486,17 @@ endif() if(UPNP AND NOT(MINIUPNPC_FOUND)) message(SEND_ERROR "You must install miniupnpc to compile the DDNet server with UPnP support") endif() - if(DISCORD AND NOT(DISCORDSDK_FOUND)) message(SEND_ERROR "You must install the Discord SDK to compile the DDNet client with Discord support") endif() - +if(DISCORD_DYNAMIC) + if(TARGET_OS STREQUAL "windows" OR TARGET_OS STREQUAL "mac") + message(SEND_ERROR "Dynamically loading the Discord SDK is only supported on Linux") + endif() + if(NOT DISCORD) + message(SEND_ERROR "You must enable the DISCORD flag if you want to link the Discord SDK") + endif() +endif() if(CLIENT AND NOT(FREETYPE_FOUND)) message(SEND_ERROR "You must install Freetype to compile the DDNet client") endif() @@ -1642,12 +1647,11 @@ add_library(engine-shared EXCLUDE_FROM_ALL OBJECT ${ENGINE_INTERFACE} ${ENGINE_S add_library(game-shared EXCLUDE_FROM_ALL OBJECT ${GAME_SHARED} ${GAME_GENERATED_SHARED}) list(APPEND TARGETS_OWN engine-shared game-shared) -if(DISCORD) +if(DISCORD AND NOT DISCORD_DYNAMIC) add_library(discord-shared SHARED IMPORTED) set_target_properties(discord-shared PROPERTIES IMPORTED_LOCATION "${DISCORDSDK_LIBRARIES}" IMPORTED_IMPLIB "${DISCORDSDK_LIBRARIES}" - INTERFACE_INCLUDE_DIRECTORIES "${DISCORDSDK_INCLUDE_DIRS}" ) endif() @@ -1861,7 +1865,11 @@ if(CLIENT) ) if(DISCORD) - list(APPEND LIBS_CLIENT discord-shared) + if(NOT DISCORD_DYNAMIC) + list(APPEND LIBS_CLIENT discord-shared) + else() + list(APPEND LIBS_CLIENT ${CMAKE_DL_LIBS}) + endif() endif() if(TARGET_OS STREQUAL "windows") @@ -1905,7 +1913,7 @@ if(CLIENT) ${PLATFORM_CLIENT_INCLUDE_DIRS} ) - if(STEAMAPI_KIND STREQUAL SHARED) + if(STEAMAPI_KIND STREQUAL SHARED OR DISCORD_DYNAMIC) set_own_rpath(${TARGET_CLIENT}) endif() @@ -2687,6 +2695,9 @@ foreach(target ${TARGETS_OWN}) endif() if(DISCORD) target_compile_definitions(${target} PRIVATE CONF_DISCORD) + if(DISCORD_DYNAMIC) + target_compile_definitions(${target} PRIVATE CONF_DISCORD_DYNAMIC) + endif() endif() if(VERSION) target_compile_definitions(${target} PRIVATE GAME_RELEASE_VERSION="${VERSION}") diff --git a/src/engine/client/discord.cpp b/src/engine/client/discord.cpp index dcd2b07de..a740db567 100644 --- a/src/engine/client/discord.cpp +++ b/src/engine/client/discord.cpp @@ -3,6 +3,26 @@ #if defined(CONF_DISCORD) #include +typedef enum EDiscordResult (*FDiscordCreate)(DiscordVersion, struct DiscordCreateParams *, struct IDiscordCore **); + +#if defined(CONF_DISCORD_DYNAMIC) +#include +FDiscordCreate GetDiscordCreate() +{ + void *pSdk = dlopen("discord_game_sdk.so", RTLD_NOW); + if(!pSdk) + { + return nullptr; + } + return (FDiscordCreate)dlsym(pSdk, "DiscordCreate"); +} +#else +FDiscordCreate GetDiscordCreate() +{ + return DiscordCreate; +} +#endif + class CDiscord : public IDiscord { IDiscordCore *m_pCore; @@ -10,7 +30,7 @@ class CDiscord : public IDiscord IDiscordActivityManager *m_pActivityManager; public: - bool Init() + bool Init(FDiscordCreate pfnDiscordCreate) { m_pCore = 0; mem_zero(&m_ActivityEvents, sizeof(m_ActivityEvents)); @@ -23,7 +43,7 @@ public: Params.flags = EDiscordCreateFlags::DiscordCreateFlags_NoRequireDiscord; Params.event_data = this; Params.activity_events = &m_ActivityEvents; - int Error = DiscordCreate(DISCORD_VERSION, &Params, &m_pCore); + int Error = pfnDiscordCreate(DISCORD_VERSION, &Params, &m_pCore); if(Error != DiscordResult_Ok) { dbg_msg("discord", "error initializing discord instance, error=%d", Error); @@ -55,8 +75,13 @@ public: IDiscord *CreateDiscordImpl() { + FDiscordCreate pfnDiscordCreate = GetDiscordCreate(); + if(!pfnDiscordCreate) + { + return 0; + } CDiscord *pDiscord = new CDiscord(); - if(pDiscord->Init()) + if(pDiscord->Init(pfnDiscordCreate)) { delete pDiscord; return 0;