diff --git a/.gitmodules b/.gitmodules index 0c80b257d..31a5e06d0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -67,3 +67,6 @@ [submodule "src/external/unicorn-src"] path = src/external/unicorn-src url = https://github.com/unicorn-engine/unicorn.git +[submodule "src/external/discord-rpc"] + path = src/external/discord-rpc + url = https://github.com/discordapp/discord-rpc diff --git a/CMakeLists.txt b/CMakeLists.txt index 63e050bb6..2d8730a06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) option(USE_GDBSTUB "Build Vita3K with GDB Debugger." OFF) +option(USE_DISCORD_RICH_PRESENCE "Build Vita3K with Discord Rich Presence" OFF) find_program(CCACHE_PROGRAM ccache) if(CCACHE_PROGRAM) @@ -33,6 +34,10 @@ macro(pre_configure_boost) message("Using Boost_LIBRARY_DIRS: ${BOOST_LIBRARYDIR}") endmacro(pre_configure_boost) +if (CI) + set(USE_DISCORD_RICH_PRESENCE ON) +endif() + if(NOT CI) pre_configure_boost() endif() diff --git a/src/emulator/CMakeLists.txt b/src/emulator/CMakeLists.txt index 7ec3ed349..efd080566 100644 --- a/src/emulator/CMakeLists.txt +++ b/src/emulator/CMakeLists.txt @@ -49,6 +49,10 @@ if (USE_GDBSTUB) add_definitions(-DUSE_GDBSTUB) endif() +if (USE_DISCORD_RICH_PRESENCE) + add_definitions(-DUSE_DISCORD_RICH_PRESENCE) +endif() + add_subdirectory(app) add_subdirectory(audio) add_subdirectory(cpu) @@ -77,7 +81,7 @@ add_subdirectory(gui) add_executable(emulator MACOSX_BUNDLE main.cpp performance.cpp) -target_link_libraries(emulator PRIVATE app gui host sdl2 shader util) +target_link_libraries(emulator PRIVATE app discord-rpc gui host sdl2 shader util) if(LINUX) target_link_libraries(emulator PRIVATE stdc++fs) endif() diff --git a/src/emulator/app/CMakeLists.txt b/src/emulator/app/CMakeLists.txt index 20fc93b63..6554ebc64 100644 --- a/src/emulator/app/CMakeLists.txt +++ b/src/emulator/app/CMakeLists.txt @@ -3,15 +3,17 @@ add_library( STATIC include/app/app_config.h include/app/app_functions.h + include/app/discord.h include/app/screen_render.h src/app_config.cpp src/app_init.cpp src/app_private.h src/app_sfo.cpp src/app.cpp + src/discord.cpp src/screen_render.cpp ) target_include_directories(app PUBLIC include) target_link_libraries(app PUBLIC glutil host util) -target_link_libraries(app PRIVATE ${Boost_LIBRARIES} audio glbinding-aux gui io kernel microprofile rtc sdl2 spdlog yaml-cpp) +target_link_libraries(app PRIVATE ${Boost_LIBRARIES} audio discord-rpc glbinding-aux gui io kernel microprofile rtc sdl2 spdlog yaml-cpp) diff --git a/src/emulator/app/include/app/discord.h b/src/emulator/app/include/app/discord.h new file mode 100644 index 000000000..a1185e729 --- /dev/null +++ b/src/emulator/app/include/app/discord.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +namespace discord { +void init(const std::string &application_id = "570296795943403530"); + +void shutdown(); + +void update_init_status(bool discord_rich_presence, bool *discord_rich_presence_old); + +void update_presence(const std::string &state = "", const std::string &details = "Idle", bool reset_timer = true); +} // namespace discord diff --git a/src/emulator/app/src/app.cpp b/src/emulator/app/src/app.cpp index 1d9305370..c2674ee26 100644 --- a/src/emulator/app/src/app.cpp +++ b/src/emulator/app/src/app.cpp @@ -41,6 +41,10 @@ #include #endif +#ifdef USE_DISCORD_RICH_PRESENCE +#include +#endif + #include #include @@ -336,7 +340,6 @@ ExitCode load_app(Ptr &entry_point, HostState &host, const std::wstr error_dialog(message, host.window.get()); return ModuleLoadFailed; } - if (!host.cfg.show_gui) { auto &imgui_render = host.display.imgui_render; @@ -349,6 +352,11 @@ ExitCode load_app(Ptr &entry_point, HostState &host, const std::wstr server_open(host); #endif +#ifdef USE_DISCORD_RICH_PRESENCE + if (host.cfg.discord_rich_presence) + discord::update_presence(host.io.title_id, host.game_title); +#endif + return Success; } diff --git a/src/emulator/app/src/app_config.cpp b/src/emulator/app/src/app_config.cpp index 5185d7986..63b108068 100644 --- a/src/emulator/app/src/app_config.cpp +++ b/src/emulator/app/src/app_config.cpp @@ -122,6 +122,7 @@ ExitCode serialize_config(Config &cfg, fs::path output_path) { config_file_emit_single(emitter, "log-level", cfg.log_level); config_file_emit_single(emitter, "pref-path", cfg.pref_path); config_file_emit_vector(emitter, "lle-modules", cfg.lle_modules); + config_file_emit_single(emitter, "discord-rich-presence", cfg.discord_rich_presence); config_file_emit_optional_single(emitter, "wait-for-debugger", cfg.wait_for_debugger); emitter << YAML::EndMap; @@ -167,6 +168,7 @@ static ExitCode parse(Config &cfg, fs::path load_path, const std::string &root_p get_yaml_value(config_node, "background-alpha", &cfg.background_alpha, 0.300f); get_yaml_value(config_node, "log-level", &cfg.log_level, static_cast(spdlog::level::trace)); get_yaml_value(config_node, "pref-path", &cfg.pref_path, root_pref_path); + get_yaml_value(config_node, "discord-rich-presence", &cfg.discord_rich_presence, true); get_yaml_value_optional(config_node, "wait-for-debugger", &cfg.wait_for_debugger); if (!fs::exists(cfg.pref_path) && !cfg.pref_path.empty()) { diff --git a/src/emulator/app/src/app_init.cpp b/src/emulator/app/src/app_init.cpp index 3b248a68d..0c38e268c 100644 --- a/src/emulator/app/src/app_init.cpp +++ b/src/emulator/app/src/app_init.cpp @@ -31,6 +31,10 @@ #include #include +#ifdef USE_DISCORD_RICH_PRESENCE +#include +#endif + #include #include #include @@ -174,6 +178,12 @@ bool init(HostState &state, Config cfg, const Root &root_paths) { return false; } +#ifdef USE_DISCORD_RICH_PRESENCE + discord::init(); + if (cfg.discord_rich_presence) { + discord::update_presence(""); + } +#endif update_viewport(state); // Try adaptive vsync first, falling back to regular vsync. diff --git a/src/emulator/app/src/discord.cpp b/src/emulator/app/src/discord.cpp new file mode 100644 index 000000000..fcd517518 --- /dev/null +++ b/src/emulator/app/src/discord.cpp @@ -0,0 +1,44 @@ +#ifdef USE_DISCORD_RICH_PRESENCE +#include +#include +#include + +// Credits to the RPCS3 Project + +namespace discord { +void init(const std::string &application_id) { + DiscordEventHandlers handlers = {}; + Discord_Initialize(application_id.c_str(), &handlers, 1, NULL); +} + +void shutdown() { + Discord_Shutdown(); +} + +void update_init_status(bool discord_rich_presence, bool *discord_rich_presence_old) { + if (*discord_rich_presence_old != discord_rich_presence) { + if (discord_rich_presence) { + discord::init(); + discord::update_presence("", "Idle"); + } else { + discord::shutdown(); + } + *discord_rich_presence_old = discord_rich_presence; + } +} + +void update_presence(const std::string &state, const std::string &details, bool reset_timer) { + DiscordRichPresence discord_presence = {}; + discord_presence.details = details.c_str(); + discord_presence.state = state.c_str(); + discord_presence.largeImageKey = "vita3k-logo"; + discord_presence.largeImageText = "Vita3K is the world's first functional PlayStation Vita emulator"; + + if (reset_timer) { + discord_presence.startTimestamp = time(0); + } + + Discord_UpdatePresence(&discord_presence); +} +} // namespace discord +#endif diff --git a/src/emulator/gui/include/gui/functions.h b/src/emulator/gui/include/gui/functions.h index ec42dc10d..44d568422 100644 --- a/src/emulator/gui/include/gui/functions.h +++ b/src/emulator/gui/include/gui/functions.h @@ -47,5 +47,4 @@ void draw_reinstall_dialog(HostState &host, GenericDialogState *status); namespace ImGui { bool vector_getter(void *vec, int idx, const char **out_text); - } diff --git a/src/emulator/gui/src/settings_dialog.cpp b/src/emulator/gui/src/settings_dialog.cpp index 9208b9ea1..9cab90dda 100644 --- a/src/emulator/gui/src/settings_dialog.cpp +++ b/src/emulator/gui/src/settings_dialog.cpp @@ -213,6 +213,10 @@ void draw_settings_dialog(HostState &host) { ImGui::Checkbox("Game Background", &host.cfg.show_game_background); if (ImGui::IsItemHovered()) ImGui::SetTooltip("Uncheck the box to disable viewing Game background."); + ImGui::SameLine(); + ImGui::Checkbox("Discord Rich Presence", &host.cfg.discord_rich_presence); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("Enables Discord Rich Presence to show what game you're playing on discord"); ImGui::Spacing(); ImGui::SliderInt("Game Icon Size \nSelect your preferred icon size.", &host.cfg.icon_size, 16, 128); ImGui::Spacing(); diff --git a/src/emulator/host/include/host/config.h b/src/emulator/host/include/host/config.h index 0aef99596..8731850a7 100644 --- a/src/emulator/host/include/host/config.h +++ b/src/emulator/host/include/host/config.h @@ -53,4 +53,5 @@ struct Config { std::string background_image = {}; float background_alpha = 0.300f; int icon_size = 64; + bool discord_rich_presence = true; }; diff --git a/src/emulator/main.cpp b/src/emulator/main.cpp index 921e37031..5584bd524 100644 --- a/src/emulator/main.cpp +++ b/src/emulator/main.cpp @@ -31,6 +31,10 @@ #include #endif +#ifdef USE_DISCORD_RICH_PRESENCE +#include +#endif + #include #include @@ -104,12 +108,17 @@ int main(int argc, char *argv[]) { gui::init(host); + auto discord_rich_presence_old = host.cfg.discord_rich_presence; + // Application not provided via argument, show game selector while (run_type == app::AppRunType::Unknown) { if (app::handle_events(host)) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gui::draw_begin(host); +#ifdef USE_DISCORD_RICH_PRESENCE + discord::update_init_status(host.cfg.discord_rich_presence, &discord_rich_presence_old); +#endif gui::draw_ui(host); gui::draw_game_selector(host); @@ -154,6 +163,9 @@ int main(int argc, char *argv[]) { app::set_window_title(host); } +#ifdef USE_DISCORD_RICH_PRESENCE + discord::shutdown(); +#endif #ifdef USE_GDBSTUB server_close(host); diff --git a/src/external/CMakeLists.txt b/src/external/CMakeLists.txt index 73ef7d266..d7c819984 100644 --- a/src/external/CMakeLists.txt +++ b/src/external/CMakeLists.txt @@ -145,6 +145,16 @@ target_link_libraries(yaml INTERFACE yaml-cpp) add_library(rpcs3 INTERFACE) target_include_directories(rpcs3 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/rpcs3/include") +add_library(discord-rpc INTERFACE) +target_include_directories(discord-rpc INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/discord-rpc/include") +if(APPLE) + target_link_libraries(discord-rpc INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/discord-rpc-lib/libdiscord-rpc-mac.a") +elseif(WIN32) + target_link_libraries(discord-rpc INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/discord-rpc-lib/discord-rpc.lib") +elseif(UNIX) + target_link_libraries(discord-rpc INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/discord-rpc-lib/libdiscord-rpc-linux.a") +endif() + option(ENABLE_SPVREMAPPER "Enables building of SPVRemapper" OFF) option(ENABLE_GLSLANG_BINARIES "Builds glslangValidator and spirv-remap" OFF) option(ENABLE_AMD_EXTENSIONS "Enables support of AMD-specific extensions" OFF) diff --git a/src/external/discord-rpc b/src/external/discord-rpc new file mode 160000 index 000000000..34ce3ac80 --- /dev/null +++ b/src/external/discord-rpc @@ -0,0 +1 @@ +Subproject commit 34ce3ac80306f8d3cb56d3efdcd4725288742db9 diff --git a/src/external/discord-rpc-lib/discord-rpc.lib b/src/external/discord-rpc-lib/discord-rpc.lib new file mode 100644 index 000000000..1f3e825ee Binary files /dev/null and b/src/external/discord-rpc-lib/discord-rpc.lib differ diff --git a/src/external/discord-rpc-lib/libdiscord-rpc-linux.a b/src/external/discord-rpc-lib/libdiscord-rpc-linux.a new file mode 100644 index 000000000..8b5a2cc5b Binary files /dev/null and b/src/external/discord-rpc-lib/libdiscord-rpc-linux.a differ diff --git a/src/external/discord-rpc-lib/libdiscord-rpc-mac.a b/src/external/discord-rpc-lib/libdiscord-rpc-mac.a new file mode 100644 index 000000000..c83261fad Binary files /dev/null and b/src/external/discord-rpc-lib/libdiscord-rpc-mac.a differ