Skip to content

Commit

Permalink
start of a discord wrapper woopie
Browse files Browse the repository at this point in the history
  • Loading branch information
DexterHaslem committed Jan 22, 2018
1 parent 5db1982 commit 9e70103
Show file tree
Hide file tree
Showing 4 changed files with 237 additions and 0 deletions.
8 changes: 8 additions & 0 deletions cl_dll/client_scratch-2005.vcproj
Expand Up @@ -335,6 +335,14 @@
RelativePath=".\ff\ff_cdll_client_int.h"
>
</File>
<File
RelativePath=".\ff_discordman.cpp"
>
</File>
<File
RelativePath=".\ff_discordman.h"
>
</File>
<File
RelativePath=".\ff\ff_glyph.cpp"
>
Expand Down
2 changes: 2 additions & 0 deletions cl_dll/ff/c_ff_player.cpp
Expand Up @@ -49,6 +49,7 @@
#include "collisionutils.h" // hlstriker: For player avoidance
#include "history_resource.h" // squeek: For adding grens to the ammo pickups on the right
#include "ff_mathackman.h" // squeek: For mathack manager update in ClientThink
#include "ff_discordman.h" // for discord rich integration

#if defined( CFFPlayer )
#undef CFFPlayer
Expand Down Expand Up @@ -2656,6 +2657,7 @@ void C_FFPlayer::ClientThink( void )
}

_mathackman.Update();
_discord.RunFrame();

BaseClass::ClientThink();
}
Expand Down
139 changes: 139 additions & 0 deletions cl_dll/ff_discordman.cpp
@@ -0,0 +1,139 @@
// wrapper for discord rich presence api
// they provide static libs, dlls and headers to use directly, but to no
// surprise, having to use ancient vc2005 ABI, we cant even link against
// modern DLL stub libs. Also the discord header includes stdint which vc2005
// doesn't even have (lol), so its mostly just manually pulling in the structs
// and loading the library functions manually at runtime.

#include "cbase.h"
#include "ff_discordman.h"
#include <windows.h>
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"


#define DISCORD_LIBRARY_DLL "discord-rpc.dll"
#define DISCORD_APP_ID "404135974801637378"
#define STEAM_ID "253530"

ConVar use_discord("cl_discord", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_USERINFO,
"Enable discord rich presence integration (current, server, map etc)");

CFFDiscordManager _discord;

// runtime entry point nastiness we will hide in here
typedef void (*pDiscord_Initialize)(const char* applicationId,
DiscordEventHandlers* handlers,
int autoRegister,
const char* optionalSteamId);

typedef void (*pDiscord_Shutdown)(void);
typedef void (*pDiscord_RunCallbacks)(void);
typedef void (*pDiscord_UpdatePresence)(const DiscordRichPresence* presence);

pDiscord_Initialize Discord_Initialize = NULL;
pDiscord_Shutdown Discord_Shutdown = NULL;
pDiscord_RunCallbacks Discord_RunCallbacks = NULL;
pDiscord_UpdatePresence Discord_UpdatePresence = NULL;

static HINSTANCE hDiscordDLL;

// NOTE: can not call discord from main menu thread. it will block

CFFDiscordManager::CFFDiscordManager()
{
hDiscordDLL = LoadLibrary(DISCORD_LIBRARY_DLL);
if (!hDiscordDLL)
{
return;
}

Discord_Initialize = (pDiscord_Initialize) GetProcAddress(hDiscordDLL, "Discord_Initialize");
Discord_Shutdown = (pDiscord_Shutdown) GetProcAddress(hDiscordDLL, "Discord_Shutdown");
Discord_RunCallbacks = (pDiscord_RunCallbacks) GetProcAddress(hDiscordDLL, "Discord_RunCallbacks");
Discord_UpdatePresence = (pDiscord_UpdatePresence) GetProcAddress(hDiscordDLL, "Discord_UpdatePresence");

// dont run this yet. it will hang client
// InitializeDiscord();
}

CFFDiscordManager::~CFFDiscordManager()
{
if (hDiscordDLL)
{
// dont bother with clean exit, it will block.
// Discord_Shutdown();
// i mean really, we could just let os handle since our dtor is called at game exit but
FreeLibrary(hDiscordDLL);
}
hDiscordDLL = NULL;
}

void CFFDiscordManager::RunFrame()
{
if (!use_discord.GetBool())
return;

if (!m_bApiReady)
{
if (!m_bInitializeRequested)
{
InitializeDiscord();
m_bInitializeRequested = true;
}
}

// always run this, otherwise we will chicken & egg waiting for ready
if (Discord_RunCallbacks)
Discord_RunCallbacks();
}

void CFFDiscordManager::OnReady()
{
DevMsg("discord ready");
_discord.m_bApiReady = true;
}

void CFFDiscordManager::OnDiscordError(int errorCode, const char* message)
{
_discord.m_bApiReady = false;
if (Q_strlen(message) < 1024)
{
char buff[1024];
Q_snprintf(buff, 1024, "Discord init failed. code %d - error: %s\n", errorCode, message);
Warning(buff);
}
}

void CFFDiscordManager::InitializeDiscord()
{
DiscordEventHandlers handlers;
memset(&handlers, 0, sizeof(handlers));
handlers.ready = &CFFDiscordManager::OnReady;
handlers.errored = &CFFDiscordManager::OnDiscordError;
// handlers.disconnected = handleDiscordDisconnected;
// handlers.joinGame = handleDiscordJoinGame;
// handlers.spectateGame = handleDiscordSpectateGame;
// handlers.joinRequest = handleDiscordJoinRequest;
Discord_Initialize(DISCORD_APP_ID, &handlers, 1, "");// STEAM_ID);
}

void CFFDiscordManager::SetServer(const char *szName)
{
}

void CFFDiscordManager::SetMapName(const char *szDetails)
{
}

void CFFDiscordManager::SetPlayerCounts(int min, int cur, int max)
{
}

void CFFDiscordManager::SetSmallImage(const char *szName)
{
}

void CFFDiscordManager::SetLargeImage(const char *szName)
{
}
88 changes: 88 additions & 0 deletions cl_dll/ff_discordman.h
@@ -0,0 +1,88 @@
// ff_discordman.h

// lol has stdint which vc2005 doesnt have
//#include "discord-api/discord-rpc.h"
#include <ctime>


// see ff_discordman.cpp for explaination of why all this is here
/*
// needs lib stubs which vc2005 ABI wont link against
__declspec(dllimport) void Discord_Initialize(const char* applicationId,
DiscordEventHandlers* handlers,
int autoRegister,
const char* optionalSteamId);
__declspec(dllimport) void Discord_Shutdown(void);
__declspec(dllimport) void Discord_RunCallbacks(void);
__declspec(dllimport) void Discord_UpdatePresence(const DiscordRichPresence* presence);
*/


typedef struct DiscordRichPresence {
const char* state; /* max 128 bytes */
const char* details; /* max 128 bytes */
unsigned long long startTimestamp; // type modified from stdint
unsigned long long endTimestamp; // type modified from stdint
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 */
unsigned int partySize;
unsigned int partyMax;
const char* matchSecret; /* max 128 bytes */
const char* joinSecret; /* max 128 bytes */
const char* spectateSecret; /* max 128 bytes */
unsigned short instance; // type modified from stdint
} DiscordRichPresence;

typedef struct DiscordJoinRequest {
const char* userId;
const char* username;
const char* discriminator;
const char* avatar;
} DiscordJoinRequest;

typedef struct DiscordEventHandlers {
void (*ready)();
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 DiscordJoinRequest* request);
} DiscordEventHandlers;


class CFFDiscordManager
{
public:
CFFDiscordManager();
~CFFDiscordManager();

void SetServer(const char *szName);
void SetMapName(const char *szDetails);
void SetPlayerCounts(int min, int cur, int max);

void SetSmallImage(const char *szName);
void SetLargeImage(const char *szName);
void RunFrame();

// these have to be static so that discord can use them
// as callbacks :-(
static void OnReady();
static void OnDiscordError(int errorCode, const char* message);
private:

void InitializeDiscord();

// pulled out of here so we dont include windows.h
// including windows.h breaks CFFPlayer with a bunch of nonsense.
//HINSTANCE m_hDiscordDLL;

bool m_bApiReady;
bool m_bInitializeRequested;
DiscordRichPresence *m_pDiscordRichPresence;
};

extern CFFDiscordManager _discord;

0 comments on commit 9e70103

Please sign in to comment.