mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-03 16:02:26 +00:00
[09/04/2024] Added Discord Presence Integration. Discord displays "In ShadPS4" along with elapsed time when a user is executing shadps4.exe in their computer.
This commit is contained in:
parent
b7e0df34a7
commit
0920b12d6c
151
presence/discord.cpp
Normal file
151
presence/discord.cpp
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
#include "discord.h"
|
||||||
|
#include "discord_rpc.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor for the Discord class.
|
||||||
|
* @author Kevin Mora (morkev)
|
||||||
|
*
|
||||||
|
* Initializes the Discord class with the provided launch code (Discord application ID)
|
||||||
|
* and sets the application_running_ flag to false.
|
||||||
|
*
|
||||||
|
* @param launch_code The Discord application client ID.
|
||||||
|
*/
|
||||||
|
Discord::Discord(const std::string &launch_code)
|
||||||
|
: launch_code_(launch_code), application_running_(false), time_of_start_(0) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the Discord RPC connection.
|
||||||
|
*
|
||||||
|
* Sets up the event handlers for Discord Rich Presence and connects to Discord
|
||||||
|
* using the provided launch code.
|
||||||
|
*/
|
||||||
|
void Discord::Initialize() {
|
||||||
|
DiscordEventHandlers handlers{};
|
||||||
|
Discord_Initialize(launch_code_.c_str(), &handlers, 1, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Shuts down the Discord RPC connection.
|
||||||
|
*
|
||||||
|
* Terminates the connection to Discord and cleans up any active presence.
|
||||||
|
*/
|
||||||
|
void Discord::Shutdown() {
|
||||||
|
Discord_Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if a process with the given name is running on the system.
|
||||||
|
*
|
||||||
|
* This function iterates over all running processes to check if a process
|
||||||
|
* named `process_name` (e.g., `shadps4.exe`) is running.
|
||||||
|
*
|
||||||
|
* @param process_name The name of the process to check for.
|
||||||
|
* @return true if the process is running, false otherwise.
|
||||||
|
*/
|
||||||
|
bool Discord::IsProcessRunning(const std::string &process_name) {
|
||||||
|
for (const auto &entry : std::filesystem::directory_iterator("/proc")) {
|
||||||
|
try {
|
||||||
|
std::string pid = entry.path().filename();
|
||||||
|
std::string cmd_path = "/proc/" + pid + "/comm";
|
||||||
|
std::ifstream cmd_file(cmd_path);
|
||||||
|
std::string cmd;
|
||||||
|
std::getline(cmd_file, cmd);
|
||||||
|
if (cmd == process_name) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieves the current presence data for Discord.
|
||||||
|
*
|
||||||
|
* Determines the state, large image, and large image text based on whether
|
||||||
|
* `shadps4.exe` is running. If the process is found, it updates the status
|
||||||
|
* to indicate the application is running.
|
||||||
|
*
|
||||||
|
* @param state Reference to the string where the current state will be stored (e.g., "In ShadPS4").
|
||||||
|
* @param large_image Reference to the string where the large image key will be stored.
|
||||||
|
* @param large_text Reference to the string where the large image's tooltip text will be stored.
|
||||||
|
*/
|
||||||
|
void Discord::GetData(std::string &state, std::string &large_image, std::string &large_text) {
|
||||||
|
if (IsProcessRunning("shadps4.exe")) {
|
||||||
|
state = "In ShadPS4";
|
||||||
|
large_image = "shadps4";
|
||||||
|
large_text = "ShadPS4";
|
||||||
|
} else {
|
||||||
|
state = "Unknown";
|
||||||
|
large_image = "default";
|
||||||
|
large_text = "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Updates the Discord Rich Presence with the latest status.
|
||||||
|
*
|
||||||
|
* If the application `shadps4.exe` is running, this method updates the start time
|
||||||
|
* and sends the current state, large image, and text to Discord.
|
||||||
|
* If the application is closed, it clears the presence from Discord.
|
||||||
|
*/
|
||||||
|
void Discord::UpdatePresence() {
|
||||||
|
std::string state, large_image, large_text;
|
||||||
|
GetData(state, large_image, large_text);
|
||||||
|
|
||||||
|
DiscordRichPresence presence{};
|
||||||
|
presence.state = state.c_str();
|
||||||
|
presence.large_image_key = large_image.c_str();
|
||||||
|
presence.large_image_text = large_text.c_str();
|
||||||
|
presence.start_timestamp = time_of_start_;
|
||||||
|
|
||||||
|
if (state != "Unknown") {
|
||||||
|
Discord_UpdatePresence(&presence);
|
||||||
|
std::cout << "Discord Rich Presence updated.\n";
|
||||||
|
} else {
|
||||||
|
Discord_ClearPresence();
|
||||||
|
std::cout << "Application closed. Presence cleared.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Runs the main loop for updating Discord Rich Presence.
|
||||||
|
*
|
||||||
|
* Continuously checks if the `shadps4.exe` process is running and updates the Discord
|
||||||
|
* status accordingly. This function handles the timing of updates and stops the timer
|
||||||
|
* when the application is closed.
|
||||||
|
*/
|
||||||
|
void Discord::Run() {
|
||||||
|
Initialize();
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
std::string state, large_image, large_text;
|
||||||
|
GetData(state, large_image, large_text);
|
||||||
|
|
||||||
|
if (state != "Unknown") {
|
||||||
|
if (!application_running_) {
|
||||||
|
application_running_ = true;
|
||||||
|
time_of_start_ = std::time(nullptr); // Set start time when the application starts
|
||||||
|
}
|
||||||
|
UpdatePresence();
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(10)); // Check every 10 seconds
|
||||||
|
} else {
|
||||||
|
if (application_running_) {
|
||||||
|
application_running_ = false;
|
||||||
|
std::cout << "Application stopped.\n";
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(1)); // Faster check if app is not running
|
||||||
|
}
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
std::cerr << "Error: " << e.what() << ". Retrying...\n";
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Shutdown();
|
||||||
|
}
|
64
presence/discord.h
Normal file
64
presence/discord.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#ifndef DISCORD_H
|
||||||
|
#define DISCORD_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "discord_rpc.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class Discord
|
||||||
|
* @brief Manages Discord Rich Presence for the shadPS4 Emulator.
|
||||||
|
* @author Kevin Mora (morkev)
|
||||||
|
*
|
||||||
|
* The Discord class is responsible for managing Discord Rich Presence updates,
|
||||||
|
* detecting if the `shadps4.exe` process is running, and updating Discord status accordingly.
|
||||||
|
* It also handles connecting and disconnecting from the Discord RPC service.
|
||||||
|
*
|
||||||
|
* @param launch_code_ Discord application client ID.
|
||||||
|
* @param application_running_ Tracks if the application (`shadps4.exe`) is running.
|
||||||
|
* @param time_of_start_ Tracks the time when the application starts for presence timestamping.
|
||||||
|
*/
|
||||||
|
class Discord {
|
||||||
|
private:
|
||||||
|
std::string launch_code_;
|
||||||
|
bool application_running_;
|
||||||
|
time_t time_of_start_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if a specific process is running on the system.
|
||||||
|
*
|
||||||
|
* This method searches for a running process by its name.
|
||||||
|
*
|
||||||
|
* @param process_name The name of the process to check (e.g., `shadps4.exe`).
|
||||||
|
* @return true if the process is running, false otherwise.
|
||||||
|
*/
|
||||||
|
bool IsProcessRunning(const std::string &process_name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieves the current status and presence data for Discord.
|
||||||
|
*
|
||||||
|
* This method sets the status, large image, and text details based on whether
|
||||||
|
* `shadps4.exe` is currently running.
|
||||||
|
*
|
||||||
|
* @param state Output parameter for the current state (e.g., "In ShadPS4").
|
||||||
|
* @param large_image Output parameter for the large image to display (e.g., "shadps4").
|
||||||
|
* @param large_text Output parameter for the large image's text (e.g., "ShadPS4").
|
||||||
|
*/
|
||||||
|
void GetData(std::string &state, std::string &large_image, std::string &large_text);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Constructor for the Discord class.
|
||||||
|
*
|
||||||
|
* Initializes the Discord class with the specified launch code for Discord RPC.
|
||||||
|
*
|
||||||
|
* @param launch_code Discord application client ID.
|
||||||
|
*/
|
||||||
|
explicit Discord(const std::string &launch_code);
|
||||||
|
|
||||||
|
void UpdatePresence();
|
||||||
|
void Run();
|
||||||
|
void Initialize();
|
||||||
|
void Shutdown();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
116
presence/discord_rpc.h
Normal file
116
presence/discord_rpc.h
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#ifndef DISCORD_RPC_H
|
||||||
|
#define DISCORD_RPC_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct DiscordRichPresence
|
||||||
|
* @brief Struct representing Discord Rich Presence data.
|
||||||
|
* @autor Kevin Mora (morkev)
|
||||||
|
*
|
||||||
|
* This struct holds various fields that define the Discord Rich Presence status,
|
||||||
|
* including the state, timestamps, images, party information, and secrets for joining/spectating games.
|
||||||
|
*
|
||||||
|
* @param state The main status text for the Rich Presence (e.g., "In ShadPS4").
|
||||||
|
* @param details Additional details for the Rich Presence.
|
||||||
|
* @param start_timestamp The start time for the current activity (Unix timestamp).
|
||||||
|
* @param end_timestamp The end time for the current activity (Unix timestamp).
|
||||||
|
* @param large_image_key The key for the large image shown in Discord.
|
||||||
|
* @param large_image_text The tooltip text for the large image.
|
||||||
|
* @param small_image_key The key for the small image shown in Discord.
|
||||||
|
* @param small_image_text The tooltip text for the small image.
|
||||||
|
* @param party_id Unique identifier for the player's party.
|
||||||
|
* @param party_size The number of people in the party.
|
||||||
|
* @param party_max The maximum size of the party.
|
||||||
|
* @param match_secret Secret for joining a multiplayer match.
|
||||||
|
* @param join_secret Secret for joining a friend's game.
|
||||||
|
* @param spectate_secret Secret for spectating a friend's game.
|
||||||
|
* @param instance Whether or not the game is an instance.
|
||||||
|
*/
|
||||||
|
typedef struct DiscordRichPresence {
|
||||||
|
const char* state;
|
||||||
|
const char* details;
|
||||||
|
int64_t start_timestamp;
|
||||||
|
int64_t end_timestamp;
|
||||||
|
const char* large_image_key;
|
||||||
|
const char* large_image_text;
|
||||||
|
const char* small_image_key;
|
||||||
|
const char* small_image_text;
|
||||||
|
const char* party_id;
|
||||||
|
int party_size;
|
||||||
|
int party_max;
|
||||||
|
const char* match_secret;
|
||||||
|
const char* join_secret;
|
||||||
|
const char* spectate_secret;
|
||||||
|
int8_t instance;
|
||||||
|
} DiscordRichPresence;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct DiscordEventHandlers
|
||||||
|
* @brief Struct representing event handlers for Discord Rich Presence.
|
||||||
|
*
|
||||||
|
* This struct defines function pointers for various Discord RPC events,
|
||||||
|
* such as when the presence is ready, when the connection is disconnected,
|
||||||
|
* and when there are errors or game join requests.
|
||||||
|
*
|
||||||
|
* @param ready Callback function when Discord RPC is ready.
|
||||||
|
* @param disconnected Callback function when Discord RPC is disconnected.
|
||||||
|
* @param errored Callback function for handling errors.
|
||||||
|
* @param join_game Callback function for when a join game request is received.
|
||||||
|
* @param spectate_game Callback function for when a spectate game request is received.
|
||||||
|
* @param join_request Callback function for handling a join request.
|
||||||
|
*/
|
||||||
|
typedef struct DiscordEventHandlers {
|
||||||
|
void (*ready)(void);
|
||||||
|
void (*disconnected)(int errcode, const char* message);
|
||||||
|
void (*errored)(int errcode, const char* message);
|
||||||
|
void (*join_game)(const char* join_secret);
|
||||||
|
void (*spectate_game)(const char* spectate_secret);
|
||||||
|
void (*join_request)(const char* join_request);
|
||||||
|
} DiscordEventHandlers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the Discord Rich Presence.
|
||||||
|
*
|
||||||
|
* This function sets up the Discord Rich Presence with the provided application ID,
|
||||||
|
* event handlers, and optional Steam ID.
|
||||||
|
*
|
||||||
|
* @param application_id The Discord application ID.
|
||||||
|
* @param handlers Pointer to the Discord event handlers.
|
||||||
|
* @param auto_register Whether or not to auto-register the presence.
|
||||||
|
* @param optional_steam_id Optional Steam ID for Steam integration.
|
||||||
|
*/
|
||||||
|
void Discord_Initialize(
|
||||||
|
const char* application_id, DiscordEventHandlers* handlers,
|
||||||
|
int auto_register, const char* optional_steam_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Shuts down the Discord Rich Presence.
|
||||||
|
*
|
||||||
|
* This function disconnects the Rich Presence from Discord and shuts it down.
|
||||||
|
*/
|
||||||
|
void Discord_Shutdown(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Updates the Discord Rich Presence with new information.
|
||||||
|
*
|
||||||
|
* This function updates the current Rich Presence data (e.g., state, timestamps, images).
|
||||||
|
*
|
||||||
|
* @param presence Pointer to a `DiscordRichPresence` struct containing the new data.
|
||||||
|
*/
|
||||||
|
void Discord_UpdatePresence(const DiscordRichPresence* presence);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears the current Discord Rich Presence.
|
||||||
|
*
|
||||||
|
* This function removes any active Rich Presence information from Discord.
|
||||||
|
*/
|
||||||
|
void Discord_ClearPresence(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user