diff --git a/command.c b/command.c index 0f0ad1969d..166618703a 100644 --- a/command.c +++ b/command.c @@ -1834,9 +1834,6 @@ void command_playlist_update_write( **/ bool command_event(enum event_command cmd, void *data) { -#ifdef HAVE_DISCORD - static bool discord_inited = false; -#endif bool boolean = false; switch (cmd) @@ -2986,26 +2983,24 @@ TODO: Add a setting for these tweaks */ if (!settings->bools.discord_enable) return false; - if (discord_inited) + if (discord_is_ready()) return true; discord_init(); - discord_inited = true; } #endif break; case CMD_EVENT_DISCORD_DEINIT: #ifdef HAVE_DISCORD - if (!discord_inited) + if (!discord_is_ready()) return false; discord_shutdown(); - discord_inited = false; #endif break; case CMD_EVENT_DISCORD_UPDATE: #ifdef HAVE_DISCORD - if (!data || !discord_inited) + if (!data || !discord_is_ready()) return false; { diff --git a/deps/discord-rpc/examples/button-clicker/Assets/DiscordRpc.cs b/deps/discord-rpc/examples/button-clicker/Assets/DiscordRpc.cs index dec1ade0f5..af82c1c231 100644 --- a/deps/discord-rpc/examples/button-clicker/Assets/DiscordRpc.cs +++ b/deps/discord-rpc/examples/button-clicker/Assets/DiscordRpc.cs @@ -129,20 +129,20 @@ public class DiscordRpc FreeMem(); } - _presence.state = StrToPtr(state, 128); - _presence.details = StrToPtr(details, 128); + _presence.state = StrToPtr(state); + _presence.details = StrToPtr(details); _presence.startTimestamp = startTimestamp; _presence.endTimestamp = endTimestamp; - _presence.largeImageKey = StrToPtr(largeImageKey, 32); - _presence.largeImageText = StrToPtr(largeImageText, 128); - _presence.smallImageKey = StrToPtr(smallImageKey, 32); - _presence.smallImageText = StrToPtr(smallImageText, 128); - _presence.partyId = StrToPtr(partyId, 128); + _presence.largeImageKey = StrToPtr(largeImageKey); + _presence.largeImageText = StrToPtr(largeImageText); + _presence.smallImageKey = StrToPtr(smallImageKey); + _presence.smallImageText = StrToPtr(smallImageText); + _presence.partyId = StrToPtr(partyId); _presence.partySize = partySize; _presence.partyMax = partyMax; - _presence.matchSecret = StrToPtr(matchSecret, 128); - _presence.joinSecret = StrToPtr(joinSecret, 128); - _presence.spectateSecret = StrToPtr(spectateSecret, 128); + _presence.matchSecret = StrToPtr(matchSecret); + _presence.joinSecret = StrToPtr(joinSecret); + _presence.spectateSecret = StrToPtr(spectateSecret); _presence.instance = instance; return _presence; @@ -152,16 +152,18 @@ public class DiscordRpc /// Returns a pointer to a representation of the given string with a size of maxbytes /// /// String to convert - /// Max number of bytes to use /// Pointer to the UTF-8 representation of - private IntPtr StrToPtr(string input, int maxbytes) + private IntPtr StrToPtr(string input) { if (string.IsNullOrEmpty(input)) return IntPtr.Zero; - var convstr = StrClampBytes(input, maxbytes); - var convbytecnt = Encoding.UTF8.GetByteCount(convstr); - var buffer = Marshal.AllocHGlobal(convbytecnt); + var convbytecnt = Encoding.UTF8.GetByteCount(input); + var buffer = Marshal.AllocHGlobal(convbytecnt + 1); + for (int i = 0; i < convbytecnt + 1; i++) + { + Marshal.WriteByte(buffer, i , 0); + } _buffers.Add(buffer); - Marshal.Copy(Encoding.UTF8.GetBytes(convstr), 0, buffer, convbytecnt); + Marshal.Copy(Encoding.UTF8.GetBytes(input), 0, buffer, convbytecnt); return buffer; } @@ -181,30 +183,6 @@ public class DiscordRpc return Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(str)); } - /// - /// Clamp the string to the given byte length preserving null termination - /// - /// string to clamp - /// max bytes the resulting string should have (including null termination) - /// null terminated string with a byte length less or equal to - private static string StrClampBytes(string toclamp, int maxbytes) - { - var str = StrToUtf8NullTerm(toclamp); - var strbytes = Encoding.UTF8.GetBytes(str); - - if (strbytes.Length <= maxbytes) - { - return str; - } - - var newstrbytes = new byte[] { }; - Array.Copy(strbytes, 0, newstrbytes, 0, maxbytes - 1); - newstrbytes[newstrbytes.Length - 1] = 0; - newstrbytes[newstrbytes.Length - 2] = 0; - - return Encoding.UTF8.GetString(newstrbytes); - } - /// /// Free the allocated memory for conversion to /// diff --git a/deps/discord-rpc/examples/unrealstatus/Plugins/discordrpc/Source/DiscordRpc/Public/DiscordRpcBlueprint.h b/deps/discord-rpc/examples/unrealstatus/Plugins/discordrpc/Source/DiscordRpc/Public/DiscordRpcBlueprint.h index 2d6521124b..17e2f9b29e 100644 --- a/deps/discord-rpc/examples/unrealstatus/Plugins/discordrpc/Source/DiscordRpc/Public/DiscordRpcBlueprint.h +++ b/deps/discord-rpc/examples/unrealstatus/Plugins/discordrpc/Source/DiscordRpc/Public/DiscordRpcBlueprint.h @@ -24,6 +24,16 @@ struct FDiscordUserData { FString avatar; }; +/** +* Valid response codes for Respond function +*/ +UENUM(BlueprintType) +enum class EDiscordJoinResponseCodes : uint8 +{ + DISCORD_REPLY_NO UMETA(DisplayName="No"), + DISCORD_REPLY_YES UMETA(DisplayName="Yes"), + DISCORD_REPLY_IGNORE UMETA(DisplayName="Ignore") +}; DECLARE_LOG_CATEGORY_EXTERN(Discord, Log, All); diff --git a/deps/discord-rpc/src/discord_register_linux.cpp b/deps/discord-rpc/src/discord_register_linux.cpp index b10f96db66..09911dcc6c 100644 --- a/deps/discord-rpc/src/discord_register_linux.cpp +++ b/deps/discord-rpc/src/discord_register_linux.cpp @@ -33,9 +33,11 @@ extern "C" DISCORD_EXPORT void Discord_Register(const char* applicationId, const char exePath[1024]; if (!command || !command[0]) { - if (readlink("/proc/self/exe", exePath, sizeof(exePath)) <= 0) { + ssize_t size = readlink("/proc/self/exe", exePath, sizeof(exePath)); + if (size <= 0 || size >= (ssize_t)sizeof(exePath)) { return; } + exePath[size] = '\0'; command = exePath; } diff --git a/deps/discord-rpc/src/discord_rpc.cpp b/deps/discord-rpc/src/discord_rpc.cpp index dedb3f1539..2e44c939ce 100644 --- a/deps/discord-rpc/src/discord_rpc.cpp +++ b/deps/discord-rpc/src/discord_rpc.cpp @@ -89,10 +89,11 @@ public: keepRunning.store(true); ioThread = std::thread([&]() { const std::chrono::duration maxWait{500LL}; + Discord_UpdateConnection(); while (keepRunning.load()) { - Discord_UpdateConnection(); std::unique_lock lock(waitForIOMutex); waitForIOActivity.wait_for(lock, maxWait); + Discord_UpdateConnection(); } }); } diff --git a/discord/discord.c b/discord/discord.c index 0efe85e036..9d534dd1d9 100644 --- a/discord/discord.c +++ b/discord/discord.c @@ -37,25 +37,104 @@ #include "../cheevos/cheevos.h" #endif -static int FrustrationLevel = 0; +#ifdef HAVE_MENU +#include "../../menu/widgets/menu_input_dialog.h" +#include "../../menu/menu_cbs.h" +#endif + +#include +#include "../network/net_http_special.h" +#include "../tasks/tasks_internal.h" +#include +#include +#include "../file_path_special.h" static int64_t start_time = 0; static int64_t pause_time = 0; static int64_t ellapsed_time = 0; static bool discord_ready = false; +static bool discord_avatar_ready = false; static unsigned discord_status = 0; struct netplay_room *room; +static char user_id[128]; +static char user_name[128]; +static char user_avatar[PATH_MAX_LENGTH]; + +static char cdn_url[] = "https://cdn.discordapp.com/avatars"; + DiscordRichPresence discord_presence; +char* discord_get_own_username(void) +{ + return user_name; +} + +char* discord_get_own_avatar(void) +{ + return user_avatar; +} + +bool discord_avatar_is_ready() +{ + return discord_avatar_ready; +} + +void discord_avatar_set_ready(bool ready) +{ + discord_avatar_ready = ready; +} + +bool discord_is_ready() +{ + return discord_ready; +} + +static bool discord_download_avatar(const char* user_id, const char* avatar_id) +{ + static char url[PATH_MAX_LENGTH]; + static char url_encoded[PATH_MAX_LENGTH]; + static char full_path[PATH_MAX_LENGTH]; + + static char buf[PATH_MAX_LENGTH]; + + file_transfer_t *transf = NULL; + + fill_pathname_application_special(buf, + sizeof(buf), + APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_DISCORD_AVATARS); + fill_pathname_join(full_path, buf, avatar_id, sizeof(full_path)); + strlcpy(user_avatar, avatar_id, sizeof(user_avatar)); + + if(filestream_exists(full_path)) + return true; + else + { + snprintf(url, sizeof(url), "%s/%s/%s.png", cdn_url, user_id, avatar_id); + net_http_urlencode_full(url_encoded, url, sizeof(url_encoded)); + snprintf(buf, sizeof(buf), "%s.png", avatar_id); + + transf = (file_transfer_t*)calloc(1, sizeof(*transf)); + transf->enum_idx = MENU_ENUM_LABEL_CB_DISCORD_AVATAR; + strlcpy(transf->path, buf, sizeof(transf->path)); + + RARCH_LOG("[Discord] downloading avatar from: %s\n", url_encoded); + task_push_http_transfer(url_encoded, true, NULL, cb_generic_download, transf); + + return false; + } +} + static void handle_discord_ready(const DiscordUser* connectedUser) { + strlcpy(user_name, connectedUser->username, sizeof(user_name)); RARCH_LOG("[Discord] connected to user: %s#%s - avatar id: %s\n", connectedUser->username, connectedUser->discriminator, connectedUser->userId); + discord_download_avatar(connectedUser->userId, connectedUser->avatar); } static void handle_discord_disconnected(int errcode, const char* message) @@ -93,14 +172,55 @@ static void handle_discord_spectate(const char* secret) RARCH_LOG("[Discord] spectate (%s)\n", secret); } +static void handle_discord_join_response(void *ignore, const char *line) +{ + /* To-Do: needs in-game widgets + if (strstr(line, "yes")) + Discord_Respond(user_id, DISCORD_REPLY_YES); + + + +#ifdef HAVE_MENU + menu_input_dialog_end(); + rarch_menu_running_finished(); +#endif +*/ +} + static void handle_discord_join_request(const DiscordUser* request) { - int response = -1; - char yn[4]; - RARCH_LOG("[Discord] join request from %s#%s - %s\n", + static char url[PATH_MAX_LENGTH]; + static char url_encoded[PATH_MAX_LENGTH]; + static char filename[PATH_MAX_LENGTH]; + char buf[PATH_MAX_LENGTH]; + + RARCH_LOG("[Discord] join request from %s#%s - %s %s\n", request->username, request->discriminator, - request->userId); + request->userId, + request->avatar); + + discord_download_avatar(request->userId, request->avatar); + +#ifdef HAVE_MENU + menu_input_ctx_line_t line; + /* To-Do: needs in-game widgets + rarch_menu_running(); + */ + + memset(&line, 0, sizeof(line)); + snprintf(buf, sizeof(buf), "%s %s?", msg_hash_to_str(MSG_DISCORD_CONNECTION_REQUEST), request->username); + line.label = buf; + line.label_setting = "no_setting"; + line.cb = handle_discord_join_response; + + /* To-Do: needs in-game widgets + To-Do: bespoke dialog, should show while in-game and have a hotkey to accept + To-Do: show avatar of the user connecting + if (!menu_input_dialog_start(&line)) + return; + */ +#endif } void discord_update(enum discord_presence presence) @@ -192,10 +312,11 @@ void discord_update(enum discord_presence presence) room->gamename, room->gamecrc, room->corename); RARCH_LOG("%s\n", join_secret); discord_presence.joinSecret = strdup(join_secret); - discord_presence.spectateSecret = "SPECSPECSPEC"; - discord_presence.partyId = party_id; + /* discord_presence.spectateSecret = "SPECSPECSPEC"; */ + discord_presence.partyId = strdup(party_id); discord_presence.partyMax = 0; discord_presence.partySize = 0; + RARCH_LOG("[Discord] joining: \n Secret: %s\n Party: %s\n", discord_presence.joinSecret, discord_presence.partyId); break; case DISCORD_PRESENCE_NETPLAY_HOSTING_STOPPED: case DISCORD_PRESENCE_NETPLAY_CLIENT: @@ -226,13 +347,14 @@ void discord_init(void) handlers.spectateGame = handle_discord_spectate; handlers.joinRequest = handle_discord_join_request; - /* To-Do: Add the arguments RetroArch was started with to the register URI*/ - const char command[256] = "retroarch"; - Discord_Initialize(settings->arrays.discord_app_id, &handlers, 0, NULL); - Discord_Register(settings->arrays.discord_app_id, NULL); - discord_ready = true; + char command[PATH_MAX_LENGTH]; + strlcpy(command, get_retroarch_launch_arguments(), sizeof(command)); + + RARCH_LOG("[Discord] registering startup command: %s\n", command); + Discord_Register(settings->arrays.discord_app_id, command); + discord_ready = true; } void discord_shutdown(void) diff --git a/discord/discord.h b/discord/discord.h index 8148482d54..34505dae59 100644 --- a/discord/discord.h +++ b/discord/discord.h @@ -55,4 +55,14 @@ void discord_update(enum discord_presence presence); void discord_run_callbacks(); +bool discord_is_ready(); + +void discord_avatar_set_ready(bool ready); + +bool discord_avatar_is_ready(); + +char* discord_get_own_username(void); + +char* discord_get_own_avatar(void); + #endif /* __RARCH_DISCORD_H */ diff --git a/file_path_special.c b/file_path_special.c index fa6c3690a8..70769b97da 100644 --- a/file_path_special.c +++ b/file_path_special.c @@ -338,6 +338,31 @@ void fill_pathname_application_special(char *s, } #endif break; + case APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_DISCORD_AVATARS: + { + char *s1 = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); + char *s2 = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); + settings_t *settings = config_get_ptr(); + + s1[0] = s2[0] = '\0'; + + fill_pathname_join(s1, + settings->paths.directory_thumbnails, + "discord", + len); + fill_pathname_join(s2, + s1, "avatars", + PATH_MAX_LENGTH * sizeof(char) + ); + fill_pathname_slash(s2, + PATH_MAX_LENGTH * sizeof(char) + ); + strlcpy(s, s2, len); + free(s1); + free(s2); + } + break; + case APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES: { char *s1 = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); diff --git a/file_path_special.h b/file_path_special.h index 16455f2486..d98a6b3971 100644 --- a/file_path_special.h +++ b/file_path_special.h @@ -111,7 +111,8 @@ enum application_special_type APPLICATION_SPECIAL_DIRECTORY_ASSETS_ZARCH, APPLICATION_SPECIAL_DIRECTORY_ASSETS_ZARCH_FONT, APPLICATION_SPECIAL_DIRECTORY_ASSETS_ZARCH_ICONS, - APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES + APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES, + APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_DISCORD_AVATARS }; /** diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 12f37dd898..9e374066b5 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -133,6 +133,10 @@ MSG_HASH( MSG_NETPLAY_ENTER_PASSWORD, "Enter netplay server password:" ) +MSG_HASH( + MSG_DISCORD_CONNECTION_REQUEST, + "Do you want to allow connection from user:" + ) MSG_HASH( MSG_NETPLAY_INCORRECT_PASSWORD, "Incorrect password" diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index d411d205f9..1443aa5f0e 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -26,6 +26,10 @@ #include "../../config.h" #endif +#ifdef HAVE_DISCORD +#include "../../discord/discord.h" +#endif + #include "../../config.def.h" #include "../../config.def.keybinds.h" #include "../../wifi/wifi_driver.h" @@ -3343,7 +3347,7 @@ static void cb_generic_dir_download(void *task_data, } /* expects http_transfer_t*, file_transfer_t* */ -static void cb_generic_download(void *task_data, +void cb_generic_download(void *task_data, void *user_data, const char *err) { char output_path[PATH_MAX_LENGTH]; @@ -3359,6 +3363,7 @@ static void cb_generic_download(void *task_data, goto finish; output_path[0] = '\0'; + char buf[PATH_MAX_LENGTH];; /* we have to determine dir_path at the time of writting or else * we'd run into races when the user changes the setting during an @@ -3423,6 +3428,14 @@ static void cb_generic_download(void *task_data, case MENU_ENUM_LABEL_CB_LAKKA_DOWNLOAD: dir_path = LAKKA_UPDATE_DIR; break; + case MENU_ENUM_LABEL_CB_DISCORD_AVATAR: + { + fill_pathname_application_special(buf, + PATH_MAX_LENGTH * sizeof(char), + APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_DISCORD_AVATARS); + dir_path = buf; + break; + } default: RARCH_WARN("Unknown transfer type '%s' bailing out.\n", msg_hash_to_str(transf->enum_idx)); @@ -3495,6 +3508,10 @@ finish: RARCH_ERR("Download of '%s' failed: %s\n", (transf ? transf->path: "unknown"), err); } +#ifdef HAVE_DISCORD + else if (transf->enum_idx == MENU_ENUM_LABEL_CB_DISCORD_AVATAR) + discord_avatar_set_ready(true); +#endif if (data) { diff --git a/menu/drivers/ozone/ozone.c b/menu/drivers/ozone/ozone.c index fa9fd08a87..8e062ecaa3 100644 --- a/menu/drivers/ozone/ozone.c +++ b/menu/drivers/ozone/ozone.c @@ -23,6 +23,10 @@ #include "ozone_texture.h" #include "ozone_sidebar.h" +#ifdef HAVE_DISCORD +#include "discord/discord.h" +#endif + #include #include #include @@ -348,14 +352,37 @@ static void ozone_context_reset(void *data, bool is_threaded) for (i = 0; i < OZONE_TEXTURE_LAST; i++) { char filename[PATH_MAX_LENGTH]; - strlcpy(filename, OZONE_TEXTURES_FILES[i], sizeof(filename)); +#ifdef HAVE_DISCORD + if (i == OZONE_TEXTURE_DISCORD_OWN_AVATAR) + strlcpy(filename, discord_get_own_avatar(), sizeof(filename)); + else +#endif + strlcpy(filename, OZONE_TEXTURES_FILES[i], sizeof(filename)); + strlcat(filename, ".png", sizeof(filename)); - if (!menu_display_reset_textures_list(filename, ozone->png_path, &ozone->textures[i], TEXTURE_FILTER_MIPMAP_LINEAR)) + +#ifdef HAVE_DISCORD + if (i == OZONE_TEXTURE_DISCORD_OWN_AVATAR && discord_avatar_is_ready()) { - ozone->has_all_assets = false; - RARCH_WARN("[OZONE] Asset missing: %s%s%s\n", ozone->png_path, path_default_slash(), filename); + char buf[PATH_MAX_LENGTH]; + fill_pathname_application_special(buf, + sizeof(buf), + APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_DISCORD_AVATARS); + if (!menu_display_reset_textures_list(filename, buf, &ozone->textures[i], TEXTURE_FILTER_MIPMAP_LINEAR)) + RARCH_WARN("[OZONE] Asset missing: %s%s%s\n", ozone->png_path, path_default_slash(), filename); } + else + { +#endif + if (!menu_display_reset_textures_list(filename, ozone->png_path, &ozone->textures[i], TEXTURE_FILTER_MIPMAP_LINEAR)) + { + ozone->has_all_assets = false; + RARCH_WARN("[OZONE] Asset missing: %s%s%s\n", ozone->png_path, path_default_slash(), filename); + } +#ifdef HAVE_DISCORD + } +#endif } /* Sidebar textures */ @@ -930,7 +957,12 @@ static void ozone_draw_header(ozone_handle_t *ozone, video_frame_info_t *video_i /* Icon */ menu_display_blend_begin(video_info); - ozone_draw_icon(video_info, 60, 60, ozone->textures[OZONE_TEXTURE_RETROARCH], 47, 14, video_info->width, video_info->height, 0, 1, ozone->theme->entries_icon); +#ifdef HAVE_DISCORD + if (discord_avatar_is_ready()) + ozone_draw_icon(video_info, 60, 60, ozone->textures[OZONE_TEXTURE_DISCORD_OWN_AVATAR], 47, 14, video_info->width, video_info->height, 0, 1, ozone->theme->entries_icon); + else +#endif + ozone_draw_icon(video_info, 60, 60, ozone->textures[OZONE_TEXTURE_RETROARCH], 47, 14, video_info->width, video_info->height, 0, 1, ozone->theme->entries_icon); menu_display_blend_end(video_info); /* Battery */ @@ -1117,6 +1149,16 @@ static void ozone_frame(void *data, video_frame_info_t *video_info) bool draw_osk = menu_input_dialog_get_display_kb(); static bool draw_osk_old = false; +#ifdef HAVE_DISCORD + static bool reset = false; + + if (discord_avatar_is_ready() && !reset) + { + ozone_context_reset(data, false); + reset = true; + } +#endif + menu_animation_ctx_entry_t entry; if (!ozone) diff --git a/menu/drivers/ozone/ozone_texture.h b/menu/drivers/ozone/ozone_texture.h index 5441732378..e049b0ef4a 100644 --- a/menu/drivers/ozone/ozone_texture.h +++ b/menu/drivers/ozone/ozone_texture.h @@ -28,7 +28,9 @@ enum OZONE_TEXTURE { OZONE_TEXTURE_RETROARCH = 0, OZONE_TEXTURE_CURSOR_BORDER, - +#ifdef HAVE_DISCORD + OZONE_TEXTURE_DISCORD_OWN_AVATAR, +#endif OZONE_TEXTURE_LAST }; diff --git a/menu/menu_cbs.h b/menu/menu_cbs.h index 717ca7a302..e762038d44 100644 --- a/menu/menu_cbs.h +++ b/menu/menu_cbs.h @@ -286,6 +286,10 @@ void menu_cbs_init(void *data, int menu_cbs_exit(void); +void cb_generic_download(void *task_data, + void *user_data, const char *err); + + RETRO_END_DECLS #endif diff --git a/msg_hash.h b/msg_hash.h index f61866d90f..8d52407ba1 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -189,6 +189,7 @@ enum msg_hash_enums MSG_RESAMPLER_QUALITY_NORMAL, MSG_RESAMPLER_QUALITY_HIGHER, MSG_RESAMPLER_QUALITY_HIGHEST, + MSG_DISCORD_CONNECTION_REQUEST, MSG_ADDED_TO_FAVORITES, MSG_RESET_CORE_ASSOCIATION, MSG_CORE_ASSOCIATION_RESET, @@ -1933,6 +1934,7 @@ enum msg_hash_enums MENU_ENUM_LABEL_CB_UPDATE_SHADERS_CG, MENU_ENUM_LABEL_CB_UPDATE_SHADERS_GLSL, MENU_ENUM_LABEL_CB_UPDATE_SHADERS_SLANG, + MENU_ENUM_LABEL_CB_DISCORD_AVATAR, /* Sublabels */ MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY, diff --git a/retroarch.c b/retroarch.c index 5e92fec952..6892dfbfd3 100644 --- a/retroarch.c +++ b/retroarch.c @@ -279,6 +279,8 @@ static retro_time_t frame_limit_last_time = 0.0; extern bool input_driver_flushing_input; +static char launch_arguments[4096]; + #ifdef HAVE_DYNAMIC bool retroarch_core_set_on_cmdline(void) { @@ -640,6 +642,15 @@ static void retroarch_parse_input_and_config(int argc, char *argv[]) bool explicit_menu = false; global_t *global = global_get_ptr(); + /* Nasty hack to copy the args into a global so discord can register the same arguments for launch */ + char buf[4096]; + for (unsigned i = 0; i < argc; i++) + { + snprintf(buf, sizeof(buf), "%s %s", launch_arguments, argv[i]); + strlcpy(launch_arguments, buf, sizeof(launch_arguments)); + } + string_trim_whitespace_left(launch_arguments); + const struct option opts[] = { #ifdef HAVE_DYNAMIC { "libretro", 1, NULL, 'L' }, @@ -3667,3 +3678,8 @@ struct retro_system_info *runloop_get_libretro_system_info(void) struct retro_system_info *system = &runloop_system.info; return system; } + +char *get_retroarch_launch_arguments(void) +{ + return launch_arguments; +} \ No newline at end of file diff --git a/retroarch.h b/retroarch.h index 50f481ea6c..86b5d24920 100644 --- a/retroarch.h +++ b/retroarch.h @@ -391,6 +391,8 @@ void rarch_menu_running_finished(void); bool retroarch_is_on_main_thread(void); +char *get_retroarch_launch_arguments(void); + rarch_system_info_t *runloop_get_system_info(void); struct retro_system_info *runloop_get_libretro_system_info(void);