mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-05-19 01:44:53 +00:00
added discord rpc (#1178)
* added discord rpc
* linting issues
* Revert "linting issues"
This reverts commit 55f4e39506
.
* fix clang-format issues
* removed wrong rpc submodule
* added correct rpc submodule
* Moved cmake instructions to correct files.
* added minor suggestions from pr
* Added an option to enable/disable RPC, added rpc to emulator.cpp making it work on nonqt builds
* typo & minor stuff
* Changed getInstance implementation with Singleton class.
* Update discord_rpc_handler.cpp
discord id
* fixed ci clangformat errors
---------
Co-authored-by: georgemoralis <giorgosmrls@gmail.com>
This commit is contained in:
parent
aba803bd04
commit
3e7137cc6b
14 changed files with 133 additions and 50 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -95,3 +95,6 @@
|
||||||
path = externals/pugixml
|
path = externals/pugixml
|
||||||
url = https://github.com/zeux/pugixml.git
|
url = https://github.com/zeux/pugixml.git
|
||||||
shallow = true
|
shallow = true
|
||||||
|
[submodule "externals/discord-rpc"]
|
||||||
|
path = externals/discord-rpc
|
||||||
|
url = https://github.com/shadps4-emu/ext-discord-rpc
|
||||||
|
|
|
@ -374,6 +374,8 @@ set(COMMON src/common/logging/backend.cpp
|
||||||
src/common/debug.h
|
src/common/debug.h
|
||||||
src/common/decoder.cpp
|
src/common/decoder.cpp
|
||||||
src/common/decoder.h
|
src/common/decoder.h
|
||||||
|
src/common/discord_rpc_handler.cpp
|
||||||
|
src/common/discord_rpc_handler.h
|
||||||
src/common/elf_info.h
|
src/common/elf_info.h
|
||||||
src/common/endian.h
|
src/common/endian.h
|
||||||
src/common/enum.h
|
src/common/enum.h
|
||||||
|
@ -858,3 +860,6 @@ if (UNIX AND NOT APPLE)
|
||||||
target_link_libraries(shadps4 PRIVATE ${OPENSSL_LIBRARIES})
|
target_link_libraries(shadps4 PRIVATE ${OPENSSL_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Discord RPC
|
||||||
|
target_link_libraries(shadps4 PRIVATE discord-rpc)
|
||||||
|
|
5
externals/CMakeLists.txt
vendored
5
externals/CMakeLists.txt
vendored
|
@ -184,5 +184,10 @@ if (NOT TARGET pugixml::pugixml)
|
||||||
add_subdirectory(pugixml)
|
add_subdirectory(pugixml)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Discord RPC
|
||||||
|
set(BUILD_EXAMPLES OFF)
|
||||||
|
add_subdirectory(discord-rpc/)
|
||||||
|
target_include_directories(discord-rpc INTERFACE discord-rpc/include)
|
||||||
|
|
||||||
# GCN Headers
|
# GCN Headers
|
||||||
add_subdirectory(gcn)
|
add_subdirectory(gcn)
|
1
externals/discord-rpc
vendored
Submodule
1
externals/discord-rpc
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 80d35b5f86adc6557d0384771119cf167495dbae
|
|
@ -34,6 +34,7 @@ static bool isNeo = false;
|
||||||
static bool isFullscreen = false;
|
static bool isFullscreen = false;
|
||||||
static bool playBGM = false;
|
static bool playBGM = false;
|
||||||
static int BGMvolume = 50;
|
static int BGMvolume = 50;
|
||||||
|
static bool enableDiscordRPC = false;
|
||||||
static u32 screenWidth = 1280;
|
static u32 screenWidth = 1280;
|
||||||
static u32 screenHeight = 720;
|
static u32 screenHeight = 720;
|
||||||
static s32 gpuId = -1; // Vulkan physical device index. Set to negative for auto select
|
static s32 gpuId = -1; // Vulkan physical device index. Set to negative for auto select
|
||||||
|
@ -98,6 +99,10 @@ int getBGMvolume() {
|
||||||
return BGMvolume;
|
return BGMvolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool getEnableDiscordRPC() {
|
||||||
|
return enableDiscordRPC;
|
||||||
|
}
|
||||||
|
|
||||||
s16 getCursorState() {
|
s16 getCursorState() {
|
||||||
return cursorState;
|
return cursorState;
|
||||||
}
|
}
|
||||||
|
@ -266,6 +271,10 @@ void setBGMvolume(int volume) {
|
||||||
BGMvolume = volume;
|
BGMvolume = volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setEnableDiscordRPC(bool enable) {
|
||||||
|
enableDiscordRPC = enable;
|
||||||
|
}
|
||||||
|
|
||||||
void setCursorState(s16 newCursorState) {
|
void setCursorState(s16 newCursorState) {
|
||||||
cursorState = newCursorState;
|
cursorState = newCursorState;
|
||||||
}
|
}
|
||||||
|
@ -452,6 +461,7 @@ void load(const std::filesystem::path& path) {
|
||||||
isFullscreen = toml::find_or<bool>(general, "Fullscreen", false);
|
isFullscreen = toml::find_or<bool>(general, "Fullscreen", false);
|
||||||
playBGM = toml::find_or<bool>(general, "playBGM", false);
|
playBGM = toml::find_or<bool>(general, "playBGM", false);
|
||||||
BGMvolume = toml::find_or<int>(general, "BGMvolume", 50);
|
BGMvolume = toml::find_or<int>(general, "BGMvolume", 50);
|
||||||
|
enableDiscordRPC = toml::find_or<bool>(general, "enableDiscordRPC", true);
|
||||||
logFilter = toml::find_or<std::string>(general, "logFilter", "");
|
logFilter = toml::find_or<std::string>(general, "logFilter", "");
|
||||||
logType = toml::find_or<std::string>(general, "logType", "sync");
|
logType = toml::find_or<std::string>(general, "logType", "sync");
|
||||||
userName = toml::find_or<std::string>(general, "userName", "shadPS4");
|
userName = toml::find_or<std::string>(general, "userName", "shadPS4");
|
||||||
|
@ -557,6 +567,7 @@ void save(const std::filesystem::path& path) {
|
||||||
data["General"]["Fullscreen"] = isFullscreen;
|
data["General"]["Fullscreen"] = isFullscreen;
|
||||||
data["General"]["playBGM"] = playBGM;
|
data["General"]["playBGM"] = playBGM;
|
||||||
data["General"]["BGMvolume"] = BGMvolume;
|
data["General"]["BGMvolume"] = BGMvolume;
|
||||||
|
data["General"]["enableDiscordRPC"] = enableDiscordRPC;
|
||||||
data["General"]["logFilter"] = logFilter;
|
data["General"]["logFilter"] = logFilter;
|
||||||
data["General"]["logType"] = logType;
|
data["General"]["logType"] = logType;
|
||||||
data["General"]["userName"] = userName;
|
data["General"]["userName"] = userName;
|
||||||
|
@ -614,6 +625,7 @@ void setDefaultValues() {
|
||||||
isFullscreen = false;
|
isFullscreen = false;
|
||||||
playBGM = false;
|
playBGM = false;
|
||||||
BGMvolume = 50;
|
BGMvolume = 50;
|
||||||
|
enableDiscordRPC = true;
|
||||||
cursorState = HideCursorState::Idle;
|
cursorState = HideCursorState::Idle;
|
||||||
cursorHideTimeout = 5;
|
cursorHideTimeout = 5;
|
||||||
screenWidth = 1280;
|
screenWidth = 1280;
|
||||||
|
|
|
@ -18,6 +18,7 @@ bool isNeoMode();
|
||||||
bool isFullscreenMode();
|
bool isFullscreenMode();
|
||||||
bool getPlayBGM();
|
bool getPlayBGM();
|
||||||
int getBGMvolume();
|
int getBGMvolume();
|
||||||
|
bool getEnableDiscordRPC();
|
||||||
|
|
||||||
s16 getCursorState();
|
s16 getCursorState();
|
||||||
int getCursorHideTimeout();
|
int getCursorHideTimeout();
|
||||||
|
@ -57,6 +58,7 @@ void setScreenHeight(u32 height);
|
||||||
void setFullscreenMode(bool enable);
|
void setFullscreenMode(bool enable);
|
||||||
void setPlayBGM(bool enable);
|
void setPlayBGM(bool enable);
|
||||||
void setBGMvolume(int volume);
|
void setBGMvolume(int volume);
|
||||||
|
void setEnableDiscordRPC(bool enable);
|
||||||
void setCursorState(s16 cursorState);
|
void setCursorState(s16 cursorState);
|
||||||
void setCursorHideTimeout(int newcursorHideTimeout);
|
void setCursorHideTimeout(int newcursorHideTimeout);
|
||||||
void setLanguage(u32 language);
|
void setLanguage(u32 language);
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <ctime>
|
|
||||||
#include "common/discord.h"
|
|
||||||
|
|
||||||
namespace Discord {
|
|
||||||
|
|
||||||
void RPC::init() {
|
|
||||||
DiscordEventHandlers handlers{};
|
|
||||||
Discord_Initialize("1139939140494971051", &handlers, 1, nullptr);
|
|
||||||
|
|
||||||
startTimestamp = time(nullptr);
|
|
||||||
enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RPC::update(Discord::RPCStatus status, const std::string& game) {
|
|
||||||
DiscordRichPresence rpc{};
|
|
||||||
|
|
||||||
if (status == Discord::RPCStatus::Playing) {
|
|
||||||
rpc.details = "Playing a game";
|
|
||||||
rpc.state = game.c_str();
|
|
||||||
} else {
|
|
||||||
rpc.details = "Idle";
|
|
||||||
}
|
|
||||||
|
|
||||||
rpc.largeImageKey = "shadps4";
|
|
||||||
rpc.largeImageText = "ShadPS4 is a PS4 emulator";
|
|
||||||
rpc.startTimestamp = startTimestamp;
|
|
||||||
|
|
||||||
Discord_UpdatePresence(&rpc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RPC::stop() {
|
|
||||||
if (enabled) {
|
|
||||||
enabled = false;
|
|
||||||
Discord_ClearPresence();
|
|
||||||
Discord_Shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Discord
|
|
57
src/common/discord_rpc_handler.cpp
Normal file
57
src/common/discord_rpc_handler.cpp
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <ctime>
|
||||||
|
#include "src/common/discord_rpc_handler.h"
|
||||||
|
|
||||||
|
namespace DiscordRPCHandler {
|
||||||
|
|
||||||
|
void RPC::init() {
|
||||||
|
DiscordEventHandlers handlers{};
|
||||||
|
|
||||||
|
Discord_Initialize("1138176975865909360", &handlers, 1, nullptr);
|
||||||
|
startTimestamp = time(nullptr);
|
||||||
|
rpcEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPC::setStatusIdling() {
|
||||||
|
DiscordRichPresence rpc{};
|
||||||
|
rpc.largeImageKey = "https://github.com/shadps4-emu/shadPS4/raw/main/.github/shadps4.png";
|
||||||
|
rpc.largeImageText = "shadPS4 is a PS4 emulator";
|
||||||
|
rpc.startTimestamp = startTimestamp;
|
||||||
|
rpc.details = "Idle";
|
||||||
|
|
||||||
|
status = RPCStatus::Idling;
|
||||||
|
Discord_UpdatePresence(&rpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPC::setStatusPlaying(const std::string& game_name, const std::string& game_id) {
|
||||||
|
DiscordRichPresence rpc{};
|
||||||
|
|
||||||
|
rpc.details = "Playing";
|
||||||
|
rpc.state = game_name.c_str();
|
||||||
|
std::string largeImageUrl =
|
||||||
|
"https://store.playstation.com/store/api/chihiro/00_09_000/titlecontainer/US/en/999/" +
|
||||||
|
game_id + "_00/image";
|
||||||
|
rpc.largeImageKey = largeImageUrl.c_str();
|
||||||
|
rpc.largeImageText = game_name.c_str();
|
||||||
|
rpc.startTimestamp = startTimestamp;
|
||||||
|
|
||||||
|
status = RPCStatus::Playing;
|
||||||
|
Discord_UpdatePresence(&rpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RPC::shutdown() {
|
||||||
|
if (rpcEnabled) {
|
||||||
|
rpcEnabled = false;
|
||||||
|
Discord_ClearPresence();
|
||||||
|
Discord_Shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RPC::getRPCEnabled() {
|
||||||
|
return rpcEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace DiscordRPCHandler
|
|
@ -7,7 +7,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <discord_rpc.h>
|
#include <discord_rpc.h>
|
||||||
|
|
||||||
namespace Discord {
|
namespace DiscordRPCHandler {
|
||||||
|
|
||||||
enum class RPCStatus {
|
enum class RPCStatus {
|
||||||
Idling,
|
Idling,
|
||||||
|
@ -16,12 +16,15 @@ enum class RPCStatus {
|
||||||
|
|
||||||
class RPC {
|
class RPC {
|
||||||
std::uint64_t startTimestamp;
|
std::uint64_t startTimestamp;
|
||||||
bool enabled = false;
|
bool rpcEnabled = false;
|
||||||
|
RPCStatus status;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void init();
|
void init();
|
||||||
void update(RPCStatus status, const std::string& title);
|
void setStatusIdling();
|
||||||
void stop();
|
void setStatusPlaying(const std::string& game_name, const std::string& game_id);
|
||||||
|
void shutdown();
|
||||||
|
bool getRPCEnabled();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Discord
|
} // namespace DiscordRPCHandler
|
|
@ -11,6 +11,7 @@
|
||||||
#include "common/memory_patcher.h"
|
#include "common/memory_patcher.h"
|
||||||
#endif
|
#endif
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/discord_rpc_handler.h"
|
||||||
#include "common/elf_info.h"
|
#include "common/elf_info.h"
|
||||||
#include "common/ntapi.h"
|
#include "common/ntapi.h"
|
||||||
#include "common/path_util.h"
|
#include "common/path_util.h"
|
||||||
|
@ -210,6 +211,15 @@ void Emulator::Run(const std::filesystem::path& file) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Discord RPC
|
||||||
|
if (Config::getEnableDiscordRPC()) {
|
||||||
|
auto* rpc = Common::Singleton<DiscordRPCHandler::RPC>::Instance();
|
||||||
|
if (rpc->getRPCEnabled() == false) {
|
||||||
|
rpc->init();
|
||||||
|
}
|
||||||
|
rpc->setStatusPlaying(game_info.title, id);
|
||||||
|
}
|
||||||
|
|
||||||
// start execution
|
// start execution
|
||||||
std::jthread mainthread =
|
std::jthread mainthread =
|
||||||
std::jthread([this](std::stop_token stop_token) { linker->Execute(); });
|
std::jthread([this](std::stop_token stop_token) { linker->Execute(); });
|
||||||
|
|
|
@ -69,6 +69,14 @@ bool MainWindow::Init() {
|
||||||
QString statusMessage =
|
QString statusMessage =
|
||||||
"Games: " + QString::number(numGames) + " (" + QString::number(duration.count()) + "ms)";
|
"Games: " + QString::number(numGames) + " (" + QString::number(duration.count()) + "ms)";
|
||||||
statusBar->showMessage(statusMessage);
|
statusBar->showMessage(statusMessage);
|
||||||
|
|
||||||
|
// Initialize Discord RPC
|
||||||
|
if (Config::getEnableDiscordRPC()) {
|
||||||
|
auto* rpc = Common::Singleton<DiscordRPCHandler::RPC>::Instance();
|
||||||
|
rpc->init();
|
||||||
|
rpc->setStatusIdling();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "background_music_player.h"
|
#include "background_music_player.h"
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
|
#include "common/discord_rpc_handler.h"
|
||||||
#include "common/path_util.h"
|
#include "common/path_util.h"
|
||||||
#include "core/file_format/psf.h"
|
#include "core/file_format/psf.h"
|
||||||
#include "core/file_sys/fs.h"
|
#include "core/file_sys/fs.h"
|
||||||
|
|
|
@ -165,6 +165,17 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidge
|
||||||
BackgroundMusicPlayer::getInstance().setVolume(val);
|
BackgroundMusicPlayer::getInstance().setVolume(val);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(ui->discordRPCCheckbox, &QCheckBox::stateChanged, this, [](int val) {
|
||||||
|
Config::setEnableDiscordRPC(val);
|
||||||
|
auto* rpc = Common::Singleton<DiscordRPCHandler::RPC>::Instance();
|
||||||
|
if (val == Qt::Checked) {
|
||||||
|
rpc->init();
|
||||||
|
rpc->setStatusIdling();
|
||||||
|
} else {
|
||||||
|
rpc->shutdown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
connect(ui->backButtonBehaviorComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
connect(ui->backButtonBehaviorComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||||
this, [this](int index) {
|
this, [this](int index) {
|
||||||
if (index >= 0 && index < ui->backButtonBehaviorComboBox->count()) {
|
if (index >= 0 && index < ui->backButtonBehaviorComboBox->count()) {
|
||||||
|
@ -273,6 +284,7 @@ void SettingsDialog::LoadValuesFromConfig() {
|
||||||
ui->nullGpuCheckBox->setChecked(Config::nullGpu());
|
ui->nullGpuCheckBox->setChecked(Config::nullGpu());
|
||||||
ui->playBGMCheckBox->setChecked(Config::getPlayBGM());
|
ui->playBGMCheckBox->setChecked(Config::getPlayBGM());
|
||||||
ui->BGMVolumeSlider->setValue((Config::getBGMvolume()));
|
ui->BGMVolumeSlider->setValue((Config::getBGMvolume()));
|
||||||
|
ui->discordRPCCheckbox->setChecked(Config::getEnableDiscordRPC());
|
||||||
ui->fullscreenCheckBox->setChecked(Config::isFullscreenMode());
|
ui->fullscreenCheckBox->setChecked(Config::isFullscreenMode());
|
||||||
ui->showSplashCheckBox->setChecked(Config::showSplash());
|
ui->showSplashCheckBox->setChecked(Config::showSplash());
|
||||||
ui->ps4proCheckBox->setChecked(Config::isNeoMode());
|
ui->ps4proCheckBox->setChecked(Config::isNeoMode());
|
||||||
|
|
|
@ -148,6 +148,13 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="discordRPCCheckbox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable Discord Rich Presence</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue