3500: Add Discord rich presence r=def- a=heinrich5991

Continued the work of @edg-l. Supersedes #3472.

## Checklist

- [x] Tested the change ingame
- [x] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test if it works standalone, system.c especially
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: Edgar <git@edgarluque.com>
Co-authored-by: heinrich5991 <heinrich5991@gmail.com>
Co-authored-by: def <dennis@felsin9.de>
This commit is contained in:
bors[bot] 2021-01-31 09:18:06 +00:00 committed by GitHub
commit 697d03e5c3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 182 additions and 1 deletions

View file

@ -89,6 +89,7 @@ option(ANTIBOT "Enable support for a dynamic anticheat library" OFF)
option(CLIENT "Compile client" ON) option(CLIENT "Compile client" ON)
option(DOWNLOAD_GTEST "Download and compile GTest" ${AUTO_DEPENDENCIES_DEFAULT}) option(DOWNLOAD_GTEST "Download and compile GTest" ${AUTO_DEPENDENCIES_DEFAULT})
option(STEAM "Build the Steam release version" OFF) option(STEAM "Build the Steam release version" OFF)
option(DISCORD "Enable Discord rich presence support" OFF)
option(PREFER_BUNDLED_LIBS "Prefer bundled libraries over system libraries" ${AUTO_DEPENDENCIES_DEFAULT}) option(PREFER_BUNDLED_LIBS "Prefer bundled libraries over system libraries" ${AUTO_DEPENDENCIES_DEFAULT})
option(DEV "Don't generate stuff necessary for packaging" OFF) option(DEV "Don't generate stuff necessary for packaging" OFF)
@ -368,6 +369,9 @@ find_package(Pnglite)
find_package(PythonInterp 3) find_package(PythonInterp 3)
find_package(SDL2) find_package(SDL2)
find_package(SQLite3) find_package(SQLite3)
if(DISCORD)
find_package(DiscordSdk)
endif()
if(UNIX) if(UNIX)
# Use -pthread instead of -lpthread to draw dependencies other than libpthread # Use -pthread instead of -lpthread to draw dependencies other than libpthread
set(THREADS_PREFER_PTHREAD_FLAG TRUE) set(THREADS_PREFER_PTHREAD_FLAG TRUE)
@ -455,6 +459,9 @@ show_dependency_status("SDL2" SDL2)
show_dependency_status("SQLite3" SQLite3) show_dependency_status("SQLite3" SQLite3)
show_dependency_status("Wavpack" WAVPACK) show_dependency_status("Wavpack" WAVPACK)
show_dependency_status("Zlib" ZLIB) show_dependency_status("Zlib" ZLIB)
if(DISCORD)
show_dependency_status("DiscordSdk" DiscordSdk)
endif()
if(WEBSOCKETS) if(WEBSOCKETS)
show_dependency_status("Websockets" WEBSOCKETS) show_dependency_status("Websockets" WEBSOCKETS)
endif() endif()
@ -481,6 +488,10 @@ if(UPNP AND NOT(MINIUPNPC_FOUND))
message(SEND_ERROR "You must install miniupnpc to compile the DDNet server with UPnP support") message(SEND_ERROR "You must install miniupnpc to compile the DDNet server with UPnP support")
endif() 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(CLIENT AND NOT(FREETYPE_FOUND)) if(CLIENT AND NOT(FREETYPE_FOUND))
message(SEND_ERROR "You must install Freetype to compile the DDNet client") message(SEND_ERROR "You must install Freetype to compile the DDNet client")
endif() endif()
@ -1332,6 +1343,7 @@ set(COPY_FILES
${SQLite3_COPY_FILES} ${SQLite3_COPY_FILES}
${FFMPEG_COPY_FILES} ${FFMPEG_COPY_FILES}
${WEBSOCKETS_COPY_FILES} ${WEBSOCKETS_COPY_FILES}
${DISCORDSDK_COPY_FILES}
) )
file(COPY ${COPY_FILES} DESTINATION .) file(COPY ${COPY_FILES} DESTINATION .)
@ -1464,6 +1476,7 @@ set_src(ENGINE_INTERFACE GLOB src/engine
config.h config.h
console.h console.h
demo.h demo.h
discord.h
editor.h editor.h
engine.h engine.h
friends.h friends.h
@ -1630,6 +1643,14 @@ 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}) add_library(game-shared EXCLUDE_FROM_ALL OBJECT ${GAME_SHARED} ${GAME_GENERATED_SHARED})
list(APPEND TARGETS_OWN engine-shared game-shared) list(APPEND TARGETS_OWN engine-shared game-shared)
if(DISCORD)
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()
######################################################################## ########################################################################
# CLIENT # CLIENT
@ -1660,6 +1681,7 @@ if(CLIENT)
client.h client.h
demoedit.cpp demoedit.cpp
demoedit.h demoedit.h
discord.cpp
friends.cpp friends.cpp
friends.h friends.h
ghost.cpp ghost.cpp
@ -1837,6 +1859,10 @@ if(CLIENT)
${CMAKE_THREAD_LIBS_INIT} ${CMAKE_THREAD_LIBS_INIT}
) )
if(DISCORD)
list(APPEND LIBS_CLIENT discord-shared)
endif()
if(TARGET_OS STREQUAL "windows") if(TARGET_OS STREQUAL "windows")
set(CLIENT_ICON "other/icons/DDNet.rc") set(CLIENT_ICON "other/icons/DDNet.rc")
if(NOT MINGW) if(NOT MINGW)
@ -1873,6 +1899,7 @@ if(CLIENT)
${SDL2_INCLUDE_DIRS} ${SDL2_INCLUDE_DIRS}
${WAVPACK_INCLUDE_DIRS} ${WAVPACK_INCLUDE_DIRS}
${FFMPEG_INCLUDE_DIRS} ${FFMPEG_INCLUDE_DIRS}
${DISCORDSDK_INCLUDE_DIRS}
${PLATFORM_CLIENT_INCLUDE_DIRS} ${PLATFORM_CLIENT_INCLUDE_DIRS}
) )
@ -2657,6 +2684,9 @@ foreach(target ${TARGETS_OWN})
if(STEAM) if(STEAM)
target_compile_definitions(${target} PRIVATE PLATFORM_SUFFIX="-steam") target_compile_definitions(${target} PRIVATE PLATFORM_SUFFIX="-steam")
endif() endif()
if(DISCORD)
target_compile_definitions(${target} PRIVATE CONF_DISCORD)
endif()
if(VERSION) if(VERSION)
target_compile_definitions(${target} PRIVATE GAME_RELEASE_VERSION="${VERSION}") target_compile_definitions(${target} PRIVATE GAME_RELEASE_VERSION="${VERSION}")
endif() endif()

View file

@ -0,0 +1,36 @@
set_extra_dirs_lib(DISCORDSDK discord)
find_library(DISCORDSDK_LIBRARY
NAMES discord_game_sdk.dll.lib discord_game_sdk.dylib discord_game_sdk.so
HINTS ${HINTS_DISCORDSDK_LIBDIR}
PATHS ${PATHS_DISCORDSDK_LIBDIR}
${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH}
)
set_extra_dirs_include(DISCORDSDK discord "${DISCORDSDK_LIBRARY}")
find_path(DISCORDSDK_INCLUDEDIR discord_game_sdk.h
HINTS ${HINTS_DISCORDSDK_INCLUDEDIR}
PATHS ${PATHS_DISCORDSDK_INCLUDEDIR}
${CROSSCOMPILING_NO_CMAKE_SYSTEM_PATH}
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(DiscordSdk DEFAULT_MSG DISCORDSDK_LIBRARY DISCORDSDK_INCLUDEDIR)
mark_as_advanced(DISCORDSDK_LIBRARY DISCORDSDK_INCLUDEDIR)
if(DISCORDSDK_FOUND)
is_bundled(DISCORDSDK_BUNDLED "${DISCORDSDK_LIBRARY}")
set(DISCORDSDK_LIBRARIES ${DISCORDSDK_LIBRARY})
set(DISCORDSDK_INCLUDE_DIRS ${DISCORDSDK_INCLUDEDIR})
if(DISCORDSDK_BUNDLED)
if(TARGET_OS STREQUAL "windows")
set(DISCORDSDK_COPY_FILES "${EXTRA_DISCORDSDK_LIBDIR}/discord_game_sdk.dll")
elseif(TARGET_OS STREQUAL "linux")
set(DISCORDSDK_COPY_FILES "${EXTRA_DISCORDSDK_LIBDIR}/discord_game_sdk.so")
elseif(TARGET_OS STREQUAL "mac")
set(DISCORDSDK_COPY_FILES "${EXTRA_DISCORDSDK_LIBDIR}/discord_game_sdk.bundle")
endif()
else()
set(DISCORDSDK_COPY_FILES)
endif()
endif()

@ -1 +1 @@
Subproject commit f757a19a6ee9806e4b8606a543c157a972493052 Subproject commit ae1277e0b38ef9b1c55d2de9dcecd9022ef95f6b

View file

@ -601,10 +601,12 @@ void CClient::SetState(int s)
if(s == IClient::STATE_ONLINE) if(s == IClient::STATE_ONLINE)
{ {
Discord()->SetGameInfo(m_ServerAddress, m_aCurrentMap);
Steam()->SetGameInfo(m_ServerAddress, m_aCurrentMap); Steam()->SetGameInfo(m_ServerAddress, m_aCurrentMap);
} }
else if(Old == IClient::STATE_ONLINE) else if(Old == IClient::STATE_ONLINE)
{ {
Discord()->ClearGameInfo();
Steam()->ClearGameInfo(); Steam()->ClearGameInfo();
} }
} }
@ -2922,6 +2924,7 @@ void CClient::Update()
if(!m_EditorActive) if(!m_EditorActive)
GameClient()->OnUpdate(); GameClient()->OnUpdate();
Discord()->Update();
Steam()->Update(); Steam()->Update();
if(Steam()->GetConnectAddress()) if(Steam()->GetConnectAddress())
{ {
@ -2968,6 +2971,7 @@ void CClient::InitInterfaces()
#if defined(CONF_AUTOUPDATE) #if defined(CONF_AUTOUPDATE)
m_pUpdater = Kernel()->RequestInterface<IUpdater>(); m_pUpdater = Kernel()->RequestInterface<IUpdater>();
#endif #endif
m_pDiscord = Kernel()->RequestInterface<IDiscord>();
m_pSteam = Kernel()->RequestInterface<ISteam>(); m_pSteam = Kernel()->RequestInterface<ISteam>();
m_pStorage = Kernel()->RequestInterface<IStorage>(); m_pStorage = Kernel()->RequestInterface<IStorage>();
@ -4281,6 +4285,7 @@ int main(int argc, const char **argv) // ignore_convention
IEngineTextRender *pEngineTextRender = CreateEngineTextRender(); IEngineTextRender *pEngineTextRender = CreateEngineTextRender();
IEngineMap *pEngineMap = CreateEngineMap(); IEngineMap *pEngineMap = CreateEngineMap();
IEngineMasterServer *pEngineMasterServer = CreateEngineMasterServer(); IEngineMasterServer *pEngineMasterServer = CreateEngineMasterServer();
IDiscord *pDiscord = CreateDiscord();
ISteam *pSteam = CreateSteam(); ISteam *pSteam = CreateSteam();
if(RandInitFailed) if(RandInitFailed)
@ -4314,6 +4319,7 @@ int main(int argc, const char **argv) // ignore_convention
RegisterFail = RegisterFail || !pKernel->RegisterInterface(CreateEditor(), false); RegisterFail = RegisterFail || !pKernel->RegisterInterface(CreateEditor(), false);
RegisterFail = RegisterFail || !pKernel->RegisterInterface(CreateGameClient(), false); RegisterFail = RegisterFail || !pKernel->RegisterInterface(CreateGameClient(), false);
RegisterFail = RegisterFail || !pKernel->RegisterInterface(pStorage); RegisterFail = RegisterFail || !pKernel->RegisterInterface(pStorage);
RegisterFail = RegisterFail || !pKernel->RegisterInterface(pDiscord);
RegisterFail = RegisterFail || !pKernel->RegisterInterface(pSteam); RegisterFail = RegisterFail || !pKernel->RegisterInterface(pSteam);
if(RegisterFail) if(RegisterFail)

View file

@ -14,6 +14,7 @@
#include <engine/client/http.h> #include <engine/client/http.h>
#include <engine/client/serverbrowser.h> #include <engine/client/serverbrowser.h>
#include <engine/client/updater.h> #include <engine/client/updater.h>
#include <engine/discord.h>
#include <engine/editor.h> #include <engine/editor.h>
#include <engine/engine.h> #include <engine/engine.h>
#include <engine/graphics.h> #include <engine/graphics.h>
@ -95,6 +96,7 @@ class CClient : public IClient, public CDemoPlayer::IListener
IConsole *m_pConsole; IConsole *m_pConsole;
IStorage *m_pStorage; IStorage *m_pStorage;
IUpdater *m_pUpdater; IUpdater *m_pUpdater;
IDiscord *m_pDiscord;
ISteam *m_pSteam; ISteam *m_pSteam;
IEngineMasterServer *m_pMasterServer; IEngineMasterServer *m_pMasterServer;
@ -280,6 +282,7 @@ public:
CConfig *Config() { return m_pConfig; } CConfig *Config() { return m_pConfig; }
IStorage *Storage() { return m_pStorage; } IStorage *Storage() { return m_pStorage; }
IUpdater *Updater() { return m_pUpdater; } IUpdater *Updater() { return m_pUpdater; }
IDiscord *Discord() { return m_pDiscord; }
ISteam *Steam() { return m_pSteam; } ISteam *Steam() { return m_pSteam; }
CClient(); CClient();

View file

@ -0,0 +1,88 @@
#include <engine/discord.h>
#if defined(CONF_DISCORD)
#include <discord_game_sdk.h>
class CDiscord : public IDiscord
{
IDiscordCore *m_pCore;
IDiscordActivityEvents m_ActivityEvents;
IDiscordActivityManager *m_pActivityManager;
public:
bool Init()
{
m_pCore = 0;
mem_zero(&m_ActivityEvents, sizeof(m_ActivityEvents));
m_pActivityManager = 0;
DiscordCreateParams Params;
DiscordCreateParamsSetDefault(&Params);
Params.client_id = 752165779117441075; // DDNet
Params.flags = EDiscordCreateFlags::DiscordCreateFlags_NoRequireDiscord;
Params.event_data = this;
Params.activity_events = &m_ActivityEvents;
int Error = DiscordCreate(DISCORD_VERSION, &Params, &m_pCore);
if(Error != DiscordResult_Ok)
{
dbg_msg("discord", "error initializing discord instance, error=%d", Error);
return true;
}
m_pActivityManager = m_pCore->get_activity_manager(m_pCore);
return false;
}
void Update()
{
m_pCore->run_callbacks(m_pCore);
}
void ClearGameInfo()
{
m_pActivityManager->clear_activity(m_pActivityManager, 0, 0);
}
void SetGameInfo(NETADDR ServerAddr, const char *pMapName)
{
DiscordActivity Activity;
mem_zero(&Activity, sizeof(DiscordActivity));
str_copy(Activity.assets.large_image, "ddnet_logo", sizeof(Activity.assets.large_image));
str_copy(Activity.assets.large_text, "DDNet logo", sizeof(Activity.assets.large_text));
Activity.timestamps.start = time_timestamp();
str_copy(Activity.details, pMapName, sizeof(Activity.details));
m_pActivityManager->update_activity(m_pActivityManager, &Activity, 0, 0);
}
};
IDiscord *CreateDiscordImpl()
{
CDiscord *pDiscord = new CDiscord();
if(pDiscord->Init())
{
delete pDiscord;
return 0;
}
return pDiscord;
}
#else
IDiscord *CreateDiscordImpl()
{
return 0;
}
#endif
class CDiscordStub : public IDiscord
{
void Update() {}
void ClearGameInfo() {}
void SetGameInfo(NETADDR ServerAddr, const char *pMapName) {}
};
IDiscord *CreateDiscord()
{
IDiscord *pDiscord = CreateDiscordImpl();
if(pDiscord)
{
return pDiscord;
}
return new CDiscordStub();
}

18
src/engine/discord.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef ENGINE_DISCORD_H
#define ENGINE_DISCORD_H
#include "kernel.h"
class IDiscord : public IInterface
{
MACRO_INTERFACE("discord", 0)
public:
virtual void Update() = 0;
virtual void ClearGameInfo() = 0;
virtual void SetGameInfo(NETADDR ServerAddr, const char *pMapName) = 0;
};
IDiscord *CreateDiscord();
#endif // ENGINE_DISCORD_H