mirror of
https://github.com/libretro/RetroArch
synced 2025-04-18 14:42:30 +00:00
commit
90baac517d
11
command.c
11
command.c
@ -1834,9 +1834,6 @@ void command_playlist_update_write(
|
|||||||
**/
|
**/
|
||||||
bool command_event(enum event_command cmd, void *data)
|
bool command_event(enum event_command cmd, void *data)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_DISCORD
|
|
||||||
static bool discord_inited = false;
|
|
||||||
#endif
|
|
||||||
bool boolean = false;
|
bool boolean = false;
|
||||||
|
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
@ -2986,26 +2983,24 @@ TODO: Add a setting for these tweaks */
|
|||||||
|
|
||||||
if (!settings->bools.discord_enable)
|
if (!settings->bools.discord_enable)
|
||||||
return false;
|
return false;
|
||||||
if (discord_inited)
|
if (discord_is_ready())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
discord_init();
|
discord_init();
|
||||||
discord_inited = true;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case CMD_EVENT_DISCORD_DEINIT:
|
case CMD_EVENT_DISCORD_DEINIT:
|
||||||
#ifdef HAVE_DISCORD
|
#ifdef HAVE_DISCORD
|
||||||
if (!discord_inited)
|
if (!discord_is_ready())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
discord_shutdown();
|
discord_shutdown();
|
||||||
discord_inited = false;
|
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case CMD_EVENT_DISCORD_UPDATE:
|
case CMD_EVENT_DISCORD_UPDATE:
|
||||||
#ifdef HAVE_DISCORD
|
#ifdef HAVE_DISCORD
|
||||||
if (!data || !discord_inited)
|
if (!data || !discord_is_ready())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -129,20 +129,20 @@ public class DiscordRpc
|
|||||||
FreeMem();
|
FreeMem();
|
||||||
}
|
}
|
||||||
|
|
||||||
_presence.state = StrToPtr(state, 128);
|
_presence.state = StrToPtr(state);
|
||||||
_presence.details = StrToPtr(details, 128);
|
_presence.details = StrToPtr(details);
|
||||||
_presence.startTimestamp = startTimestamp;
|
_presence.startTimestamp = startTimestamp;
|
||||||
_presence.endTimestamp = endTimestamp;
|
_presence.endTimestamp = endTimestamp;
|
||||||
_presence.largeImageKey = StrToPtr(largeImageKey, 32);
|
_presence.largeImageKey = StrToPtr(largeImageKey);
|
||||||
_presence.largeImageText = StrToPtr(largeImageText, 128);
|
_presence.largeImageText = StrToPtr(largeImageText);
|
||||||
_presence.smallImageKey = StrToPtr(smallImageKey, 32);
|
_presence.smallImageKey = StrToPtr(smallImageKey);
|
||||||
_presence.smallImageText = StrToPtr(smallImageText, 128);
|
_presence.smallImageText = StrToPtr(smallImageText);
|
||||||
_presence.partyId = StrToPtr(partyId, 128);
|
_presence.partyId = StrToPtr(partyId);
|
||||||
_presence.partySize = partySize;
|
_presence.partySize = partySize;
|
||||||
_presence.partyMax = partyMax;
|
_presence.partyMax = partyMax;
|
||||||
_presence.matchSecret = StrToPtr(matchSecret, 128);
|
_presence.matchSecret = StrToPtr(matchSecret);
|
||||||
_presence.joinSecret = StrToPtr(joinSecret, 128);
|
_presence.joinSecret = StrToPtr(joinSecret);
|
||||||
_presence.spectateSecret = StrToPtr(spectateSecret, 128);
|
_presence.spectateSecret = StrToPtr(spectateSecret);
|
||||||
_presence.instance = instance;
|
_presence.instance = instance;
|
||||||
|
|
||||||
return _presence;
|
return _presence;
|
||||||
@ -152,16 +152,18 @@ public class DiscordRpc
|
|||||||
/// Returns a pointer to a representation of the given string with a size of maxbytes
|
/// Returns a pointer to a representation of the given string with a size of maxbytes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="input">String to convert</param>
|
/// <param name="input">String to convert</param>
|
||||||
/// <param name="maxbytes">Max number of bytes to use</param>
|
|
||||||
/// <returns>Pointer to the UTF-8 representation of <see cref="input"/></returns>
|
/// <returns>Pointer to the UTF-8 representation of <see cref="input"/></returns>
|
||||||
private IntPtr StrToPtr(string input, int maxbytes)
|
private IntPtr StrToPtr(string input)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(input)) return IntPtr.Zero;
|
if (string.IsNullOrEmpty(input)) return IntPtr.Zero;
|
||||||
var convstr = StrClampBytes(input, maxbytes);
|
var convbytecnt = Encoding.UTF8.GetByteCount(input);
|
||||||
var convbytecnt = Encoding.UTF8.GetByteCount(convstr);
|
var buffer = Marshal.AllocHGlobal(convbytecnt + 1);
|
||||||
var buffer = Marshal.AllocHGlobal(convbytecnt);
|
for (int i = 0; i < convbytecnt + 1; i++)
|
||||||
|
{
|
||||||
|
Marshal.WriteByte(buffer, i , 0);
|
||||||
|
}
|
||||||
_buffers.Add(buffer);
|
_buffers.Add(buffer);
|
||||||
Marshal.Copy(Encoding.UTF8.GetBytes(convstr), 0, buffer, convbytecnt);
|
Marshal.Copy(Encoding.UTF8.GetBytes(input), 0, buffer, convbytecnt);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,30 +183,6 @@ public class DiscordRpc
|
|||||||
return Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(str));
|
return Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clamp the string to the given byte length preserving null termination
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="toclamp">string to clamp</param>
|
|
||||||
/// <param name="maxbytes">max bytes the resulting string should have (including null termination)</param>
|
|
||||||
/// <returns>null terminated string with a byte length less or equal to <see cref="maxbytes"/></returns>
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Free the allocated memory for conversion to <see cref="RichPresenceStruct"/>
|
/// Free the allocated memory for conversion to <see cref="RichPresenceStruct"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -24,6 +24,16 @@ struct FDiscordUserData {
|
|||||||
FString avatar;
|
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);
|
DECLARE_LOG_CATEGORY_EXTERN(Discord, Log, All);
|
||||||
|
|
||||||
|
@ -33,9 +33,11 @@ extern "C" DISCORD_EXPORT void Discord_Register(const char* applicationId, const
|
|||||||
|
|
||||||
char exePath[1024];
|
char exePath[1024];
|
||||||
if (!command || !command[0]) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
exePath[size] = '\0';
|
||||||
command = exePath;
|
command = exePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
3
deps/discord-rpc/src/discord_rpc.cpp
vendored
3
deps/discord-rpc/src/discord_rpc.cpp
vendored
@ -89,10 +89,11 @@ public:
|
|||||||
keepRunning.store(true);
|
keepRunning.store(true);
|
||||||
ioThread = std::thread([&]() {
|
ioThread = std::thread([&]() {
|
||||||
const std::chrono::duration<int64_t, std::milli> maxWait{500LL};
|
const std::chrono::duration<int64_t, std::milli> maxWait{500LL};
|
||||||
|
Discord_UpdateConnection();
|
||||||
while (keepRunning.load()) {
|
while (keepRunning.load()) {
|
||||||
Discord_UpdateConnection();
|
|
||||||
std::unique_lock<std::mutex> lock(waitForIOMutex);
|
std::unique_lock<std::mutex> lock(waitForIOMutex);
|
||||||
waitForIOActivity.wait_for(lock, maxWait);
|
waitForIOActivity.wait_for(lock, maxWait);
|
||||||
|
Discord_UpdateConnection();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -37,25 +37,104 @@
|
|||||||
#include "../cheevos/cheevos.h"
|
#include "../cheevos/cheevos.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int FrustrationLevel = 0;
|
#ifdef HAVE_MENU
|
||||||
|
#include "../../menu/widgets/menu_input_dialog.h"
|
||||||
|
#include "../../menu/menu_cbs.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <net/net_http.h>
|
||||||
|
#include "../network/net_http_special.h"
|
||||||
|
#include "../tasks/tasks_internal.h"
|
||||||
|
#include <streams/file_stream.h>
|
||||||
|
#include <file/file_path.h>
|
||||||
|
#include "../file_path_special.h"
|
||||||
|
|
||||||
static int64_t start_time = 0;
|
static int64_t start_time = 0;
|
||||||
static int64_t pause_time = 0;
|
static int64_t pause_time = 0;
|
||||||
static int64_t ellapsed_time = 0;
|
static int64_t ellapsed_time = 0;
|
||||||
|
|
||||||
static bool discord_ready = false;
|
static bool discord_ready = false;
|
||||||
|
static bool discord_avatar_ready = false;
|
||||||
static unsigned discord_status = 0;
|
static unsigned discord_status = 0;
|
||||||
|
|
||||||
struct netplay_room *room;
|
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;
|
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)
|
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",
|
RARCH_LOG("[Discord] connected to user: %s#%s - avatar id: %s\n",
|
||||||
connectedUser->username,
|
connectedUser->username,
|
||||||
connectedUser->discriminator,
|
connectedUser->discriminator,
|
||||||
connectedUser->userId);
|
connectedUser->userId);
|
||||||
|
discord_download_avatar(connectedUser->userId, connectedUser->avatar);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_discord_disconnected(int errcode, const char* message)
|
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);
|
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)
|
static void handle_discord_join_request(const DiscordUser* request)
|
||||||
{
|
{
|
||||||
int response = -1;
|
static char url[PATH_MAX_LENGTH];
|
||||||
char yn[4];
|
static char url_encoded[PATH_MAX_LENGTH];
|
||||||
RARCH_LOG("[Discord] join request from %s#%s - %s\n",
|
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->username,
|
||||||
request->discriminator,
|
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)
|
void discord_update(enum discord_presence presence)
|
||||||
@ -192,10 +312,11 @@ void discord_update(enum discord_presence presence)
|
|||||||
room->gamename, room->gamecrc, room->corename);
|
room->gamename, room->gamecrc, room->corename);
|
||||||
RARCH_LOG("%s\n", join_secret);
|
RARCH_LOG("%s\n", join_secret);
|
||||||
discord_presence.joinSecret = strdup(join_secret);
|
discord_presence.joinSecret = strdup(join_secret);
|
||||||
discord_presence.spectateSecret = "SPECSPECSPEC";
|
/* discord_presence.spectateSecret = "SPECSPECSPEC"; */
|
||||||
discord_presence.partyId = party_id;
|
discord_presence.partyId = strdup(party_id);
|
||||||
discord_presence.partyMax = 0;
|
discord_presence.partyMax = 0;
|
||||||
discord_presence.partySize = 0;
|
discord_presence.partySize = 0;
|
||||||
|
RARCH_LOG("[Discord] joining: \n Secret: %s\n Party: %s\n", discord_presence.joinSecret, discord_presence.partyId);
|
||||||
break;
|
break;
|
||||||
case DISCORD_PRESENCE_NETPLAY_HOSTING_STOPPED:
|
case DISCORD_PRESENCE_NETPLAY_HOSTING_STOPPED:
|
||||||
case DISCORD_PRESENCE_NETPLAY_CLIENT:
|
case DISCORD_PRESENCE_NETPLAY_CLIENT:
|
||||||
@ -226,13 +347,14 @@ void discord_init(void)
|
|||||||
handlers.spectateGame = handle_discord_spectate;
|
handlers.spectateGame = handle_discord_spectate;
|
||||||
handlers.joinRequest = handle_discord_join_request;
|
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_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)
|
void discord_shutdown(void)
|
||||||
|
@ -55,4 +55,14 @@ void discord_update(enum discord_presence presence);
|
|||||||
|
|
||||||
void discord_run_callbacks();
|
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 */
|
#endif /* __RARCH_DISCORD_H */
|
||||||
|
@ -338,6 +338,31 @@ void fill_pathname_application_special(char *s,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
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:
|
case APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES:
|
||||||
{
|
{
|
||||||
char *s1 = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
char *s1 = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
|
||||||
|
@ -111,7 +111,8 @@ enum application_special_type
|
|||||||
APPLICATION_SPECIAL_DIRECTORY_ASSETS_ZARCH,
|
APPLICATION_SPECIAL_DIRECTORY_ASSETS_ZARCH,
|
||||||
APPLICATION_SPECIAL_DIRECTORY_ASSETS_ZARCH_FONT,
|
APPLICATION_SPECIAL_DIRECTORY_ASSETS_ZARCH_FONT,
|
||||||
APPLICATION_SPECIAL_DIRECTORY_ASSETS_ZARCH_ICONS,
|
APPLICATION_SPECIAL_DIRECTORY_ASSETS_ZARCH_ICONS,
|
||||||
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES
|
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_CHEEVOS_BADGES,
|
||||||
|
APPLICATION_SPECIAL_DIRECTORY_THUMBNAILS_DISCORD_AVATARS
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,6 +133,10 @@ MSG_HASH(
|
|||||||
MSG_NETPLAY_ENTER_PASSWORD,
|
MSG_NETPLAY_ENTER_PASSWORD,
|
||||||
"Enter netplay server password:"
|
"Enter netplay server password:"
|
||||||
)
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MSG_DISCORD_CONNECTION_REQUEST,
|
||||||
|
"Do you want to allow connection from user:"
|
||||||
|
)
|
||||||
MSG_HASH(
|
MSG_HASH(
|
||||||
MSG_NETPLAY_INCORRECT_PASSWORD,
|
MSG_NETPLAY_INCORRECT_PASSWORD,
|
||||||
"Incorrect password"
|
"Incorrect password"
|
||||||
|
@ -26,6 +26,10 @@
|
|||||||
#include "../../config.h"
|
#include "../../config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_DISCORD
|
||||||
|
#include "../../discord/discord.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "../../config.def.h"
|
#include "../../config.def.h"
|
||||||
#include "../../config.def.keybinds.h"
|
#include "../../config.def.keybinds.h"
|
||||||
#include "../../wifi/wifi_driver.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* */
|
/* 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)
|
void *user_data, const char *err)
|
||||||
{
|
{
|
||||||
char output_path[PATH_MAX_LENGTH];
|
char output_path[PATH_MAX_LENGTH];
|
||||||
@ -3359,6 +3363,7 @@ static void cb_generic_download(void *task_data,
|
|||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
output_path[0] = '\0';
|
output_path[0] = '\0';
|
||||||
|
char buf[PATH_MAX_LENGTH];;
|
||||||
|
|
||||||
/* we have to determine dir_path at the time of writting or else
|
/* 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
|
* 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:
|
case MENU_ENUM_LABEL_CB_LAKKA_DOWNLOAD:
|
||||||
dir_path = LAKKA_UPDATE_DIR;
|
dir_path = LAKKA_UPDATE_DIR;
|
||||||
break;
|
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:
|
default:
|
||||||
RARCH_WARN("Unknown transfer type '%s' bailing out.\n",
|
RARCH_WARN("Unknown transfer type '%s' bailing out.\n",
|
||||||
msg_hash_to_str(transf->enum_idx));
|
msg_hash_to_str(transf->enum_idx));
|
||||||
@ -3495,6 +3508,10 @@ finish:
|
|||||||
RARCH_ERR("Download of '%s' failed: %s\n",
|
RARCH_ERR("Download of '%s' failed: %s\n",
|
||||||
(transf ? transf->path: "unknown"), err);
|
(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)
|
if (data)
|
||||||
{
|
{
|
||||||
|
@ -23,6 +23,10 @@
|
|||||||
#include "ozone_texture.h"
|
#include "ozone_texture.h"
|
||||||
#include "ozone_sidebar.h"
|
#include "ozone_sidebar.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_DISCORD
|
||||||
|
#include "discord/discord.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <file/file_path.h>
|
#include <file/file_path.h>
|
||||||
#include <string/stdstring.h>
|
#include <string/stdstring.h>
|
||||||
#include <encodings/utf.h>
|
#include <encodings/utf.h>
|
||||||
@ -348,14 +352,37 @@ static void ozone_context_reset(void *data, bool is_threaded)
|
|||||||
for (i = 0; i < OZONE_TEXTURE_LAST; i++)
|
for (i = 0; i < OZONE_TEXTURE_LAST; i++)
|
||||||
{
|
{
|
||||||
char filename[PATH_MAX_LENGTH];
|
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));
|
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;
|
char buf[PATH_MAX_LENGTH];
|
||||||
RARCH_WARN("[OZONE] Asset missing: %s%s%s\n", ozone->png_path, path_default_slash(), filename);
|
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 */
|
/* Sidebar textures */
|
||||||
@ -930,7 +957,12 @@ static void ozone_draw_header(ozone_handle_t *ozone, video_frame_info_t *video_i
|
|||||||
|
|
||||||
/* Icon */
|
/* Icon */
|
||||||
menu_display_blend_begin(video_info);
|
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);
|
menu_display_blend_end(video_info);
|
||||||
|
|
||||||
/* Battery */
|
/* 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();
|
bool draw_osk = menu_input_dialog_get_display_kb();
|
||||||
static bool draw_osk_old = false;
|
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;
|
menu_animation_ctx_entry_t entry;
|
||||||
|
|
||||||
if (!ozone)
|
if (!ozone)
|
||||||
|
@ -28,7 +28,9 @@
|
|||||||
enum OZONE_TEXTURE {
|
enum OZONE_TEXTURE {
|
||||||
OZONE_TEXTURE_RETROARCH = 0,
|
OZONE_TEXTURE_RETROARCH = 0,
|
||||||
OZONE_TEXTURE_CURSOR_BORDER,
|
OZONE_TEXTURE_CURSOR_BORDER,
|
||||||
|
#ifdef HAVE_DISCORD
|
||||||
|
OZONE_TEXTURE_DISCORD_OWN_AVATAR,
|
||||||
|
#endif
|
||||||
OZONE_TEXTURE_LAST
|
OZONE_TEXTURE_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -286,6 +286,10 @@ void menu_cbs_init(void *data,
|
|||||||
|
|
||||||
int menu_cbs_exit(void);
|
int menu_cbs_exit(void);
|
||||||
|
|
||||||
|
void cb_generic_download(void *task_data,
|
||||||
|
void *user_data, const char *err);
|
||||||
|
|
||||||
|
|
||||||
RETRO_END_DECLS
|
RETRO_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -189,6 +189,7 @@ enum msg_hash_enums
|
|||||||
MSG_RESAMPLER_QUALITY_NORMAL,
|
MSG_RESAMPLER_QUALITY_NORMAL,
|
||||||
MSG_RESAMPLER_QUALITY_HIGHER,
|
MSG_RESAMPLER_QUALITY_HIGHER,
|
||||||
MSG_RESAMPLER_QUALITY_HIGHEST,
|
MSG_RESAMPLER_QUALITY_HIGHEST,
|
||||||
|
MSG_DISCORD_CONNECTION_REQUEST,
|
||||||
MSG_ADDED_TO_FAVORITES,
|
MSG_ADDED_TO_FAVORITES,
|
||||||
MSG_RESET_CORE_ASSOCIATION,
|
MSG_RESET_CORE_ASSOCIATION,
|
||||||
MSG_CORE_ASSOCIATION_RESET,
|
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_CG,
|
||||||
MENU_ENUM_LABEL_CB_UPDATE_SHADERS_GLSL,
|
MENU_ENUM_LABEL_CB_UPDATE_SHADERS_GLSL,
|
||||||
MENU_ENUM_LABEL_CB_UPDATE_SHADERS_SLANG,
|
MENU_ENUM_LABEL_CB_UPDATE_SHADERS_SLANG,
|
||||||
|
MENU_ENUM_LABEL_CB_DISCORD_AVATAR,
|
||||||
|
|
||||||
/* Sublabels */
|
/* Sublabels */
|
||||||
MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY,
|
MENU_ENUM_SUBLABEL_MIXER_ACTION_PLAY,
|
||||||
|
16
retroarch.c
16
retroarch.c
@ -279,6 +279,8 @@ static retro_time_t frame_limit_last_time = 0.0;
|
|||||||
|
|
||||||
extern bool input_driver_flushing_input;
|
extern bool input_driver_flushing_input;
|
||||||
|
|
||||||
|
static char launch_arguments[4096];
|
||||||
|
|
||||||
#ifdef HAVE_DYNAMIC
|
#ifdef HAVE_DYNAMIC
|
||||||
bool retroarch_core_set_on_cmdline(void)
|
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;
|
bool explicit_menu = false;
|
||||||
global_t *global = global_get_ptr();
|
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[] = {
|
const struct option opts[] = {
|
||||||
#ifdef HAVE_DYNAMIC
|
#ifdef HAVE_DYNAMIC
|
||||||
{ "libretro", 1, NULL, 'L' },
|
{ "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;
|
struct retro_system_info *system = &runloop_system.info;
|
||||||
return system;
|
return system;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *get_retroarch_launch_arguments(void)
|
||||||
|
{
|
||||||
|
return launch_arguments;
|
||||||
|
}
|
@ -391,6 +391,8 @@ void rarch_menu_running_finished(void);
|
|||||||
|
|
||||||
bool retroarch_is_on_main_thread(void);
|
bool retroarch_is_on_main_thread(void);
|
||||||
|
|
||||||
|
char *get_retroarch_launch_arguments(void);
|
||||||
|
|
||||||
rarch_system_info_t *runloop_get_system_info(void);
|
rarch_system_info_t *runloop_get_system_info(void);
|
||||||
|
|
||||||
struct retro_system_info *runloop_get_libretro_system_info(void);
|
struct retro_system_info *runloop_get_libretro_system_info(void);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user