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);