Skip to content

Commit

Permalink
Discord RPC Support
Browse files Browse the repository at this point in the history
  • Loading branch information
justin-ys committed Dec 29, 2023
1 parent 7c9767f commit e9fcb4f
Show file tree
Hide file tree
Showing 11 changed files with 394 additions and 12 deletions.
32 changes: 27 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
CXX=g++
CPPFLAGS=-std=c++2a -Iinclude -Igame/include -Ilib/include -DMA_NO_PULSEAUDIO
LDLIBS=
LDLIBS=-Llib/bin
SOURCES=$(wildcard graphics/*.cpp logging/*.cpp models/*.cpp level/*.cpp audio/*.cpp game/*.cpp game/entities/*.cpp game/UI/*.cpp util/*.cpp main.cpp)
OBJS=$(patsubst %.cpp, build/%.o, $(SOURCES))
VER=vA1
USE_DISCORD=1

ifndef PDCURSES_BACKEND
ifeq ($(OS),Windows_NT)
Expand All @@ -24,25 +25,46 @@ endif
ifeq ($(USE_NCURSES), 1)
LDLIBS+= -lncursesw
else
LDLIBS+= -Llib/bin -lpdcurses
LDLIBS+= -lpdcurses
endif

ifndef PDCURSES_BACKEND
$(error "OS not detected or supported - please specify PDCurses backend (wincon, x11, sdl2))
endif

ifeq ($(USE_DISCORD), 1)
$(shell mkdir -p lib/bin)
$(shell mkdir -p lib/include)
ifeq ($(UNAME_S),Linux)
$(shell cp -u lib/discord-rpc-linux/linux-dynamic/include/*.h lib/include)
$(shell cp -u lib/discord-rpc-linux/linux-dynamic/lib/libdiscord-rpc.so lib/bin)
LDLIBS+= -ldiscord-rpc
CPPFLAGS+= -DUSE_DISCORD
else
USE_DISCORD=0
endif
endif

$(shell mkdir -p lib/include)
$(shell cp lib/miniaudio/miniaudio.h lib/include/miniaudio.h)

build: build-pdcurses
build: $(OBJS)
cp lib/miniaudio/miniaudio.h lib/include/miniaudio.h
$(CXX) $(CPPFLAGS) -o Spylike-$(VER) $(OBJS) $(LDLIBS)
$(CXX) $(CPPFLAGS) -o Spylike-$(VER) $(OBJS) $(LDLIBS) -Wl,-rpath=lib/bin

build/%.o: %.cpp
mkdir -p $(@D)
$(CXX) $(CPPFLAGS) -c -o $@ $(LDLIBS) $^

debug: CPPFLAGS+= -g -O0
debug: CPPFLAGS+= -g -O0 -v
debug: build

clean:
rm -rf lib/bin/*
rm -rf lib/include/*
rm -rf build/*
rm -rf lib/src/*

build-pdcurses:
cd lib && mkdir -p bin
cd lib && mkdir -p include
Expand Down
39 changes: 34 additions & 5 deletions game/game.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
#include <iostream>
#include <cmath>
#include <vector>
#include <string>
#include <memory>
#include <unistd.h>
#include <string>
#include <cstring>

#include "rendering.h"
#include "scheduling.h"
#include "camera.h"
Expand All @@ -14,11 +21,10 @@
#include "obstacle.h"
#include "game.h"
#include "geometry.h"
#include <vector>
#include <string>
#include <memory>
#include <unistd.h>
#include <string>

#ifdef USE_DISCORD
#include "discord_rpc.h"
#endif

extern SpylikeLogger LOGGER;

Expand All @@ -28,6 +34,20 @@ std::string formatSeconds(int seconds) {
return std::to_string(minutes) + ":" + std::to_string(seconds);
}

GameManager::GameManager() {
#ifdef USE_DISCORD
memset(&handlers, 0, sizeof(handlers));
handlers.ready = handleDiscordReady;
handlers.disconnected = handleDiscordDisconnected;
handlers.errored = handleDiscordError;
handlers.joinGame = handleDiscordJoin;
handlers.spectateGame = handleDiscordSpectate;
handlers.joinRequest = handleDiscordJoinRequest;
Discord_Initialize(DISCORD_CLIENT_ID, &handlers, 1, NULL);
#endif
}


void GameManager::RunLevelTask::update() {
auto& theMap = manager.map;
manager.camera->clearScreen();
Expand Down Expand Up @@ -120,6 +140,15 @@ void GameManager::loadLevel(Level level) {
map->registerEntity(entPair.first, entPair.second);
}
if (!audioManager->isPlaying()) audioManager->playMusic("1-1.wav", 0.25);
#ifdef USE_DISCORD
DiscordRichPresence discordPresence;
memset(&discordPresence, 0, sizeof(discordPresence));
discordPresence.state = level.title.c_str();
discordPresence.details = "Playing a level";
discordPresence.largeImageKey = "rg_logo";
Discord_UpdatePresence(&discordPresence);
Discord_RunCallbacks();
#endif
}

// Note: You must close any active menus, before showing a new one.
Expand Down
32 changes: 31 additions & 1 deletion game/include/game.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
#include <iostream>
#include <memory>

#ifdef USE_DISCORD
#include "discord_rpc.h"
const char* const DISCORD_CLIENT_ID="1189761699511812186";
#endif

extern SpylikeLogger LOGGER;

inline Level load_from_file(std::string path) {
Expand Down Expand Up @@ -84,11 +89,16 @@ inline Level load_from_file(std::string path) {
}
entities[ent] = Coordinate(entX, entY);
}
return Level(levelType, width, height, entities);
std::string filename = path.substr(path.find_last_of("/\\") + 1);
std::string title = filename.substr(0, filename.find(".spm"));
return Level(title, levelType, width, height, entities);
}

class GameManager : public EventHandler, public std::enable_shared_from_this<GameManager> {
bool paused;
#ifdef USE_DISCORD
DiscordEventHandlers handlers;
#endif
FrameScheduler scheduler = FrameScheduler(20);
NcursesTerminalScreen screen = NcursesTerminalScreen(80, 30);
std::shared_ptr<EventManager> eventManager;
Expand Down Expand Up @@ -127,7 +137,27 @@ class GameManager : public EventHandler, public std::enable_shared_from_this<Gam
StartupTask(GameManager& manager) : ScheduledTask("StartupTask"), manager{manager} {}
void update() override;
};

#ifdef USE_DISCORD
static void handleDiscordReady(const DiscordUser* connectedUser)
{
std::string uID = std::string(connectedUser->userId);
LOGGER.log("Discord RPC connected (User ID: " + uID + ")", DEBUG);
}

static void handleDiscordDisconnected(int errcode, const char* message) {}

static void handleDiscordError(int errcode, const char* message) {}

static void handleDiscordJoin(const char* secret) {}

static void handleDiscordSpectate(const char* secret) {}

static void handleDiscordJoinRequest(const DiscordUser* request) {}
#endif

public:
GameManager();
void loadLevel(Level level);
void pause();
void quit();
Expand Down
3 changes: 2 additions & 1 deletion include/levelmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,12 @@ class LevelMap : public std::enable_shared_from_this<LevelMap> {
};

struct Level {
std::string title;
WorldType worldType;
int width;
int height;
std::map<std::shared_ptr<TileEntity>, Coordinate> entities;
Level(WorldType wt, int w, int h, std::map<std::shared_ptr<TileEntity>, Coordinate> entities) : worldType{wt}, width{w}, height{h}, entities{entities} {}
Level(std::string title, WorldType wt, int w, int h, std::map<std::shared_ptr<TileEntity>, Coordinate> entities) : title{title}, worldType{wt}, width{w}, height{h}, entities{entities} {}
};

#endif
26 changes: 26 additions & 0 deletions lib/discord-rpc-linux/linux-dynamic/include/discord_register.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#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
124 changes: 124 additions & 0 deletions lib/discord-rpc-linux/linux-dynamic/include/discord_rpc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#pragma once
#include <stdint.h>

// 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 DiscordButton {
const char* label;
const char* url;
} DiscordButton;

typedef struct DiscordRichPresence {
const char* state; /* max 128 bytes */
const char* details; /* max 128 bytes */
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;
const DiscordButton* buttons;
} DiscordRichPresence;

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

typedef struct DiscordEventHandlers {
void (*ready)(const DiscordUser* user);
void (*disconnected)(int errorCode, const char* message);
void (*errored)(int errorCode, const char* message);
void (*debug)(char isOut, const char* opcodeName, const char* message, uint32_t messageLength);
void (*joinGame)(const char* joinSecret);
void (*spectateGame)(const char* spectateSecret);
void (*joinRequest)(const DiscordUser* user);
void (*invited)(/* DISCORD_ACTIVITY_ACTION_TYPE_ */ int8_t type,
const DiscordUser* user,
const DiscordRichPresence* activity,
const char* sessionId,
const char* channelId,
const char* messageId);
} 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

#define DISCORD_ACTIVITY_ACTION_TYPE_JOIN 1
#define DISCORD_ACTIVITY_ACTION_TYPE_SPECTATE 2

#define DISCORD_ACTIVITY_TYPE_PLAYING 0
#define DISCORD_ACTIVITY_TYPE_STREAMING 1
#define DISCORD_ACTIVITY_TYPE_LISTENING 2
#define DISCORD_ACTIVITY_TYPE_WATCHING 3
#define DISCORD_ACTIVITY_TYPE_CUSTOM 4
#define DISCORD_ACTIVITY_TYPE_COMPETING 5

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_AcceptInvite(const char* userId,
/* DISCORD_ACTIVITY_ACTION_TYPE_ */ int8_t type,
const char* sessionId,
const char* channelId,
const char* messageId);

DISCORD_EXPORT void Discord_OpenActivityInvite(/* DISCORD_ACTIVITY_ACTION_TYPE_ */ int8_t type);
DISCORD_EXPORT void Discord_OpenGuildInvite(const char* code);

DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* handlers);

#ifdef __cplusplus
} /* extern "C" */
#endif
Binary file not shown.
26 changes: 26 additions & 0 deletions lib/discord-rpc-linux/linux-static/include/discord_register.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#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
Loading

0 comments on commit e9fcb4f

Please sign in to comment.