mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-23 16:09:47 +00:00
Move netplay/networking code to netplay_frontend.c - move it out of
retroarch.c
This commit is contained in:
parent
21beb6064a
commit
11defb4009
8
core.h
8
core.h
@ -67,6 +67,14 @@ bool core_set_controller_port_device(retro_ctx_controller_info_t *pad);
|
|||||||
|
|
||||||
bool core_has_set_input_descriptor(void);
|
bool core_has_set_input_descriptor(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* core_set_default_callbacks:
|
||||||
|
* @data : pointer to retro_callbacks object
|
||||||
|
*
|
||||||
|
* Binds the libretro callbacks to default callback functions.
|
||||||
|
**/
|
||||||
|
bool core_set_default_callbacks(void *data);
|
||||||
|
|
||||||
RETRO_END_DECLS
|
RETRO_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -85,6 +85,8 @@ bool discord_avatar_is_ready(void);
|
|||||||
|
|
||||||
char* discord_get_own_avatar(void);
|
char* discord_get_own_avatar(void);
|
||||||
|
|
||||||
|
char *discord_get_own_username(void);
|
||||||
|
|
||||||
discord_state_t *discord_state_get_ptr(void);
|
discord_state_t *discord_state_get_ptr(void);
|
||||||
|
|
||||||
void discord_init(const char *discord_app_id, char *args);
|
void discord_init(const char *discord_app_id, char *args);
|
||||||
|
@ -26,21 +26,6 @@
|
|||||||
|
|
||||||
#include "../../core.h"
|
#include "../../core.h"
|
||||||
|
|
||||||
typedef struct netplay netplay_t;
|
|
||||||
|
|
||||||
typedef struct mitm_server
|
|
||||||
{
|
|
||||||
const char *name;
|
|
||||||
const char *description;
|
|
||||||
} mitm_server_t;
|
|
||||||
|
|
||||||
static const mitm_server_t netplay_mitm_server_list[] = {
|
|
||||||
{ "nyc", "New York City, USA" },
|
|
||||||
{ "madrid", "Madrid, Spain" },
|
|
||||||
{ "montreal", "Montreal, Canada" },
|
|
||||||
{ "saopaulo", "Sao Paulo, Brazil" },
|
|
||||||
};
|
|
||||||
|
|
||||||
enum rarch_netplay_ctl_state
|
enum rarch_netplay_ctl_state
|
||||||
{
|
{
|
||||||
RARCH_NETPLAY_CTL_NONE = 0,
|
RARCH_NETPLAY_CTL_NONE = 0,
|
||||||
@ -86,6 +71,69 @@ enum rarch_netplay_share_analog_preference
|
|||||||
RARCH_NETPLAY_SHARE_ANALOG_LAST
|
RARCH_NETPLAY_SHARE_ANALOG_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct netplay netplay_t;
|
||||||
|
|
||||||
|
typedef struct mitm_server
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
const char *description;
|
||||||
|
} mitm_server_t;
|
||||||
|
|
||||||
|
static const mitm_server_t netplay_mitm_server_list[] = {
|
||||||
|
{ "nyc", "New York City, USA" },
|
||||||
|
{ "madrid", "Madrid, Spain" },
|
||||||
|
{ "montreal", "Montreal, Canada" },
|
||||||
|
{ "saopaulo", "Sao Paulo, Brazil" },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct netplay_room
|
||||||
|
{
|
||||||
|
struct netplay_room *next;
|
||||||
|
int id;
|
||||||
|
int port;
|
||||||
|
int mitm_port;
|
||||||
|
int gamecrc;
|
||||||
|
int timestamp;
|
||||||
|
int host_method;
|
||||||
|
char country [3];
|
||||||
|
char retroarch_version [33];
|
||||||
|
char nickname [33];
|
||||||
|
char subsystem_name [256];
|
||||||
|
char corename [256];
|
||||||
|
char frontend [256];
|
||||||
|
char coreversion [256];
|
||||||
|
char gamename [256];
|
||||||
|
char address [256];
|
||||||
|
char mitm_address [256];
|
||||||
|
bool has_password;
|
||||||
|
bool has_spectate_password;
|
||||||
|
bool lan;
|
||||||
|
bool fixed;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
netplay_t *data; /* Used while Netplay is running */
|
||||||
|
struct netplay_room host_room; /* ptr alignment */
|
||||||
|
int reannounce;
|
||||||
|
unsigned server_port_deferred;
|
||||||
|
/* Only used before init_netplay */
|
||||||
|
bool netplay_enabled;
|
||||||
|
bool netplay_is_client;
|
||||||
|
/* Used to avoid recursive netplay calls */
|
||||||
|
bool in_netplay;
|
||||||
|
bool netplay_client_deferred;
|
||||||
|
bool is_mitm;
|
||||||
|
char server_address_deferred[512];
|
||||||
|
bool has_set_netplay_mode;
|
||||||
|
bool has_set_netplay_ip_address;
|
||||||
|
bool has_set_netplay_ip_port;
|
||||||
|
bool has_set_netplay_stateless_mode;
|
||||||
|
bool has_set_netplay_check_frames;
|
||||||
|
} net_driver_state_t;
|
||||||
|
|
||||||
|
net_driver_state_t *networking_state_get_ptr(void);
|
||||||
|
|
||||||
bool netplay_driver_ctl(enum rarch_netplay_ctl_state state, void *data);
|
bool netplay_driver_ctl(enum rarch_netplay_ctl_state state, void *data);
|
||||||
|
|
||||||
int netplay_rooms_parse(const char *buf);
|
int netplay_rooms_parse(const char *buf);
|
||||||
@ -184,4 +232,29 @@ bool netplay_should_skip(netplay_t *netplay);
|
|||||||
**/
|
**/
|
||||||
void netplay_post_frame(netplay_t *netplay);
|
void netplay_post_frame(netplay_t *netplay);
|
||||||
|
|
||||||
|
void deinit_netplay(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* init_netplay
|
||||||
|
* @direct_host : Host to connect to directly, if applicable (client only)
|
||||||
|
* @server : server address to connect to (client only)
|
||||||
|
* @port : TCP port to host on/connect to
|
||||||
|
*
|
||||||
|
* Initializes netplay.
|
||||||
|
*
|
||||||
|
* If netplay is already initialized, will return false (0).
|
||||||
|
*
|
||||||
|
* Returns: true (1) if successful, otherwise false (0).
|
||||||
|
**/
|
||||||
|
bool init_netplay(void *direct_host, const char *server, unsigned port);
|
||||||
|
|
||||||
|
bool init_netplay_deferred(const char* server, unsigned port);
|
||||||
|
|
||||||
|
void video_frame_net(const void *data, unsigned width,
|
||||||
|
unsigned height, size_t pitch);
|
||||||
|
void audio_sample_net(int16_t left, int16_t right);
|
||||||
|
size_t audio_sample_batch_net(const int16_t *data, size_t frames);
|
||||||
|
int16_t input_state_net(unsigned port, unsigned device,
|
||||||
|
unsigned idx, unsigned id);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -54,31 +54,6 @@ enum netplay_host_method
|
|||||||
NETPLAY_HOST_METHOD_MITM
|
NETPLAY_HOST_METHOD_MITM
|
||||||
};
|
};
|
||||||
|
|
||||||
struct netplay_room
|
|
||||||
{
|
|
||||||
struct netplay_room *next;
|
|
||||||
int id;
|
|
||||||
int port;
|
|
||||||
int mitm_port;
|
|
||||||
int gamecrc;
|
|
||||||
int timestamp;
|
|
||||||
int host_method;
|
|
||||||
char country [3];
|
|
||||||
char retroarch_version [33];
|
|
||||||
char nickname [33];
|
|
||||||
char subsystem_name [256];
|
|
||||||
char corename [256];
|
|
||||||
char frontend [256];
|
|
||||||
char coreversion [256];
|
|
||||||
char gamename [256];
|
|
||||||
char address [256];
|
|
||||||
char mitm_address [256];
|
|
||||||
bool has_password;
|
|
||||||
bool has_spectate_password;
|
|
||||||
bool lan;
|
|
||||||
bool fixed;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef HAVE_NETPLAYDISCOVERY
|
#ifdef HAVE_NETPLAYDISCOVERY
|
||||||
enum rarch_netplay_discovery_ctl_state
|
enum rarch_netplay_discovery_ctl_state
|
||||||
{
|
{
|
||||||
|
@ -25,10 +25,12 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <boolean.h>
|
#include <boolean.h>
|
||||||
|
#include <retro_assert.h>
|
||||||
|
|
||||||
#include <compat/strl.h>
|
#include <compat/strl.h>
|
||||||
#include <net/net_compat.h>
|
#include <net/net_compat.h>
|
||||||
#include <net/net_socket.h>
|
#include <net/net_socket.h>
|
||||||
|
#include <net/net_http.h>
|
||||||
#include <encodings/crc32.h>
|
#include <encodings/crc32.h>
|
||||||
#include <lrc_hash.h>
|
#include <lrc_hash.h>
|
||||||
#include <retro_timers.h>
|
#include <retro_timers.h>
|
||||||
@ -36,6 +38,10 @@
|
|||||||
#include <string/stdstring.h>
|
#include <string/stdstring.h>
|
||||||
#include <file/file_path.h>
|
#include <file/file_path.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_DISCORD
|
||||||
|
#include "../discord.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "../../file_path_special.h"
|
#include "../../file_path_special.h"
|
||||||
#include "../../paths.h"
|
#include "../../paths.h"
|
||||||
#include "../../content.h"
|
#include "../../content.h"
|
||||||
@ -205,6 +211,13 @@ static int16_t htons_for_morons(int16_t value)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static net_driver_state_t networking_driver_st = {0};
|
||||||
|
|
||||||
|
net_driver_state_t *networking_state_get_ptr(void)
|
||||||
|
{
|
||||||
|
return &networking_driver_st;
|
||||||
|
}
|
||||||
|
|
||||||
static bool netplay_lan_ad_client(void)
|
static bool netplay_lan_ad_client(void)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
@ -6728,5 +6741,711 @@ void netplay_post_frame(netplay_t *netplay)
|
|||||||
false))
|
false))
|
||||||
netplay_hangup(netplay, connection);
|
netplay_hangup(netplay, connection);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool init_netplay_deferred(const char* server, unsigned port)
|
||||||
|
{
|
||||||
|
net_driver_state_t *net_st = &networking_driver_st;
|
||||||
|
if (!string_is_empty(server) && port != 0)
|
||||||
|
{
|
||||||
|
strlcpy(net_st->server_address_deferred, server,
|
||||||
|
sizeof(net_st->server_address_deferred));
|
||||||
|
net_st->server_port_deferred = port;
|
||||||
|
net_st->netplay_client_deferred = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
net_st->netplay_client_deferred = false;
|
||||||
|
|
||||||
|
return net_st->netplay_client_deferred;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* input_poll_net
|
||||||
|
*
|
||||||
|
* Poll the network if necessary.
|
||||||
|
*/
|
||||||
|
void input_poll_net(void)
|
||||||
|
{
|
||||||
|
net_driver_state_t *net_st = &networking_driver_st;
|
||||||
|
netplay_t *netplay = net_st->data;
|
||||||
|
if (!netplay_should_skip(netplay) && netplay && netplay->can_poll)
|
||||||
|
{
|
||||||
|
input_driver_state_t
|
||||||
|
*input_st = input_state_get_ptr();
|
||||||
|
netplay->can_poll = false;
|
||||||
|
netplay_poll(
|
||||||
|
input_st->block_libretro_input,
|
||||||
|
config_get_ptr(),
|
||||||
|
netplay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Netplay polling callbacks */
|
||||||
|
void video_frame_net(const void *data, unsigned width,
|
||||||
|
unsigned height, size_t pitch)
|
||||||
|
{
|
||||||
|
net_driver_state_t *net_st = &networking_driver_st;
|
||||||
|
netplay_t *netplay = net_st->data;
|
||||||
|
if (!netplay_should_skip(netplay))
|
||||||
|
netplay->cbs.frame_cb(data, width, height, pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void audio_sample_net(int16_t left, int16_t right)
|
||||||
|
{
|
||||||
|
net_driver_state_t *net_st = &networking_driver_st;
|
||||||
|
netplay_t *netplay = net_st->data;
|
||||||
|
if (!netplay_should_skip(netplay) && !netplay->stall)
|
||||||
|
netplay->cbs.sample_cb(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t audio_sample_batch_net(const int16_t *data, size_t frames)
|
||||||
|
{
|
||||||
|
net_driver_state_t *net_st = &networking_driver_st;
|
||||||
|
netplay_t *netplay = net_st->data;
|
||||||
|
if (!netplay_should_skip(netplay) && !netplay->stall)
|
||||||
|
return netplay->cbs.sample_batch_cb(data, frames);
|
||||||
|
return frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void netplay_announce_cb(retro_task_t *task,
|
||||||
|
void *task_data, void *user_data, const char *error)
|
||||||
|
{
|
||||||
|
net_driver_state_t *net_st = &networking_driver_st;
|
||||||
|
if (task_data)
|
||||||
|
{
|
||||||
|
unsigned i, ip_len, port_len;
|
||||||
|
http_transfer_data_t *data = (http_transfer_data_t*)task_data;
|
||||||
|
struct netplay_room *host_room = &net_st->host_room;
|
||||||
|
struct string_list *lines = NULL;
|
||||||
|
char *mitm_ip = NULL;
|
||||||
|
char *mitm_port = NULL;
|
||||||
|
char *buf = NULL;
|
||||||
|
char *host_string = NULL;
|
||||||
|
|
||||||
|
if (data->len == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
buf = (char*)calloc(1, data->len + 1);
|
||||||
|
|
||||||
|
memcpy(buf, data->data, data->len);
|
||||||
|
|
||||||
|
lines = string_split(buf, "\n");
|
||||||
|
|
||||||
|
if (lines->size == 0)
|
||||||
|
{
|
||||||
|
string_list_free(lines);
|
||||||
|
free(buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(host_room, 0, sizeof(*host_room));
|
||||||
|
|
||||||
|
for (i = 0; i < lines->size; i++)
|
||||||
|
{
|
||||||
|
const char *line = lines->elems[i].data;
|
||||||
|
|
||||||
|
if (!string_is_empty(line))
|
||||||
|
{
|
||||||
|
struct string_list *kv = string_split(line, "=");
|
||||||
|
const char *key = NULL;
|
||||||
|
const char *val = NULL;
|
||||||
|
|
||||||
|
if (!kv)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (kv->size != 2)
|
||||||
|
{
|
||||||
|
string_list_free(kv);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = kv->elems[0].data;
|
||||||
|
val = kv->elems[1].data;
|
||||||
|
|
||||||
|
if (string_is_equal(key, "id"))
|
||||||
|
sscanf(val, "%i", &host_room->id);
|
||||||
|
if (string_is_equal(key, "username"))
|
||||||
|
strlcpy(host_room->nickname, val, sizeof(host_room->nickname));
|
||||||
|
if (string_is_equal(key, "ip"))
|
||||||
|
strlcpy(host_room->address, val, sizeof(host_room->address));
|
||||||
|
if (string_is_equal(key, "mitm_ip"))
|
||||||
|
{
|
||||||
|
mitm_ip = strdup(val);
|
||||||
|
strlcpy(host_room->mitm_address, val, sizeof(host_room->mitm_address));
|
||||||
|
}
|
||||||
|
if (string_is_equal(key, "port"))
|
||||||
|
sscanf(val, "%i", &host_room->port);
|
||||||
|
if (string_is_equal(key, "mitm_port"))
|
||||||
|
{
|
||||||
|
mitm_port = strdup(val);
|
||||||
|
sscanf(mitm_port, "%i", &host_room->mitm_port);
|
||||||
|
}
|
||||||
|
if (string_is_equal(key, "core_name"))
|
||||||
|
strlcpy(host_room->corename, val, sizeof(host_room->corename));
|
||||||
|
if (string_is_equal(key, "frontend"))
|
||||||
|
strlcpy(host_room->frontend, val, sizeof(host_room->frontend));
|
||||||
|
if (string_is_equal(key, "core_version"))
|
||||||
|
strlcpy(host_room->coreversion, val, sizeof(host_room->coreversion));
|
||||||
|
if (string_is_equal(key, "game_name"))
|
||||||
|
strlcpy(host_room->gamename, val,
|
||||||
|
sizeof(host_room->gamename));
|
||||||
|
if (string_is_equal(key, "game_crc"))
|
||||||
|
sscanf(val, "%08d", &host_room->gamecrc);
|
||||||
|
if (string_is_equal(key, "host_method"))
|
||||||
|
sscanf(val, "%i", &host_room->host_method);
|
||||||
|
if (string_is_equal(key, "has_password"))
|
||||||
|
{
|
||||||
|
if ( string_is_equal_noncase(val, "true")
|
||||||
|
|| string_is_equal(val, "1"))
|
||||||
|
host_room->has_password = true;
|
||||||
|
else
|
||||||
|
host_room->has_password = false;
|
||||||
|
}
|
||||||
|
if (string_is_equal(key, "has_spectate_password"))
|
||||||
|
{
|
||||||
|
if ( string_is_equal_noncase(val, "true")
|
||||||
|
|| string_is_equal(val, "1"))
|
||||||
|
host_room->has_spectate_password = true;
|
||||||
|
else
|
||||||
|
host_room->has_spectate_password = false;
|
||||||
|
}
|
||||||
|
if (string_is_equal(key, "fixed"))
|
||||||
|
{
|
||||||
|
if ( string_is_equal_noncase(val, "true")
|
||||||
|
|| string_is_equal(val, "1"))
|
||||||
|
host_room->fixed = true;
|
||||||
|
else
|
||||||
|
host_room->fixed = false;
|
||||||
|
}
|
||||||
|
if (string_is_equal(key, "retroarch_version"))
|
||||||
|
strlcpy(host_room->retroarch_version, val,
|
||||||
|
sizeof(host_room->retroarch_version));
|
||||||
|
if (string_is_equal(key, "country"))
|
||||||
|
strlcpy(host_room->country, val,
|
||||||
|
sizeof(host_room->country));
|
||||||
|
|
||||||
|
string_list_free(kv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mitm_ip && mitm_port)
|
||||||
|
{
|
||||||
|
ip_len = (unsigned)strlen(mitm_ip);
|
||||||
|
port_len = (unsigned)strlen(mitm_port);
|
||||||
|
|
||||||
|
/* Enable Netplay client mode */
|
||||||
|
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL))
|
||||||
|
{
|
||||||
|
command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
|
||||||
|
net_st->is_mitm = true;
|
||||||
|
host_room->host_method = NETPLAY_HOST_METHOD_MITM;
|
||||||
|
}
|
||||||
|
|
||||||
|
netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_CLIENT, NULL);
|
||||||
|
|
||||||
|
host_string = (char*)calloc(1, ip_len + port_len + 2);
|
||||||
|
|
||||||
|
memcpy(host_string, mitm_ip, ip_len);
|
||||||
|
memcpy(host_string + ip_len, "|", 1);
|
||||||
|
memcpy(host_string + ip_len + 1, mitm_port, port_len);
|
||||||
|
|
||||||
|
/* Enable Netplay */
|
||||||
|
command_event(CMD_EVENT_NETPLAY_INIT_DIRECT_DEFERRED, (void*)host_string);
|
||||||
|
command_event(CMD_EVENT_NETPLAY_INIT, (void*)host_string);
|
||||||
|
|
||||||
|
free(host_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DISCORD
|
||||||
|
if (discord_is_inited)
|
||||||
|
{
|
||||||
|
discord_userdata_t userdata;
|
||||||
|
userdata.status = DISCORD_PRESENCE_NETPLAY_HOSTING;
|
||||||
|
command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
string_list_free(lines);
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
if (mitm_ip)
|
||||||
|
free(mitm_ip);
|
||||||
|
if (mitm_port)
|
||||||
|
free(mitm_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void netplay_announce(void)
|
||||||
|
{
|
||||||
|
char buf[4600];
|
||||||
|
char frontend_architecture[PATH_MAX_LENGTH];
|
||||||
|
char frontend_architecture_tmp[32];
|
||||||
|
const frontend_ctx_driver_t
|
||||||
|
*frontend_drv = NULL;
|
||||||
|
char url[2048] = "http://lobby.libretro.com/add/";
|
||||||
|
char *username = NULL;
|
||||||
|
char *corename = NULL;
|
||||||
|
char *gamename = NULL;
|
||||||
|
char *subsystemname = NULL;
|
||||||
|
char *coreversion = NULL;
|
||||||
|
char *frontend_ident = NULL;
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
runloop_state_t *runloop_st = runloop_state_get_ptr();
|
||||||
|
struct retro_system_info *system = &runloop_st->system.info;
|
||||||
|
uint32_t content_crc = content_get_crc();
|
||||||
|
struct string_list *subsystem = path_get_subsystem_list();
|
||||||
|
|
||||||
|
frontend_architecture[0] = '\0';
|
||||||
|
buf[0] = '\0';
|
||||||
|
|
||||||
|
if (subsystem)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for (i = 0; i < subsystem->size; i++)
|
||||||
|
{
|
||||||
|
strlcat(buf, path_basename(subsystem->elems[i].data), sizeof(buf));
|
||||||
|
if (i < subsystem->size - 1)
|
||||||
|
strlcat(buf, "|", sizeof(buf));
|
||||||
|
}
|
||||||
|
net_http_urlencode(&gamename, buf);
|
||||||
|
net_http_urlencode(&subsystemname, path_get(RARCH_PATH_SUBSYSTEM));
|
||||||
|
content_crc = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const char *base = path_basename(path_get(RARCH_PATH_BASENAME));
|
||||||
|
|
||||||
|
net_http_urlencode(&gamename,
|
||||||
|
!string_is_empty(base) ? base : "N/A");
|
||||||
|
/* TODO/FIXME - subsystem should be implemented later? */
|
||||||
|
net_http_urlencode(&subsystemname, "N/A");
|
||||||
|
}
|
||||||
|
|
||||||
|
frontend_drv =
|
||||||
|
(const frontend_ctx_driver_t*)frontend_driver_get_cpu_architecture_str(
|
||||||
|
frontend_architecture_tmp, sizeof(frontend_architecture_tmp));
|
||||||
|
snprintf(frontend_architecture,
|
||||||
|
sizeof(frontend_architecture),
|
||||||
|
"%s %s",
|
||||||
|
frontend_drv->ident,
|
||||||
|
frontend_architecture_tmp);
|
||||||
|
|
||||||
|
#ifdef HAVE_DISCORD
|
||||||
|
if (discord_is_ready())
|
||||||
|
net_http_urlencode(&username, discord_get_own_username());
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
net_http_urlencode(&username, settings->paths.username);
|
||||||
|
net_http_urlencode(&corename, system->library_name);
|
||||||
|
net_http_urlencode(&coreversion, system->library_version);
|
||||||
|
net_http_urlencode(&frontend_ident, frontend_architecture);
|
||||||
|
|
||||||
|
buf[0] = '\0';
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "username=%s&core_name=%s&core_version=%s&"
|
||||||
|
"game_name=%s&game_crc=%08lX&port=%d&mitm_server=%s"
|
||||||
|
"&has_password=%d&has_spectate_password=%d&force_mitm=%d"
|
||||||
|
"&retroarch_version=%s&frontend=%s&subsystem_name=%s",
|
||||||
|
username, corename, coreversion, gamename, (unsigned long)content_crc,
|
||||||
|
settings->uints.netplay_port,
|
||||||
|
settings->arrays.netplay_mitm_server,
|
||||||
|
*settings->paths.netplay_password ? 1 : 0,
|
||||||
|
*settings->paths.netplay_spectate_password ? 1 : 0,
|
||||||
|
settings->bools.netplay_use_mitm_server,
|
||||||
|
PACKAGE_VERSION, frontend_architecture, subsystemname);
|
||||||
|
task_push_http_post_transfer(url, buf, true, NULL,
|
||||||
|
netplay_announce_cb, NULL);
|
||||||
|
|
||||||
|
if (username)
|
||||||
|
free(username);
|
||||||
|
if (corename)
|
||||||
|
free(corename);
|
||||||
|
if (gamename)
|
||||||
|
free(gamename);
|
||||||
|
if (coreversion)
|
||||||
|
free(coreversion);
|
||||||
|
if (frontend_ident)
|
||||||
|
free(frontend_ident);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t input_state_net(unsigned port, unsigned device,
|
||||||
|
unsigned idx, unsigned id)
|
||||||
|
{
|
||||||
|
net_driver_state_t *net_st = &networking_driver_st;
|
||||||
|
netplay_t *netplay = net_st->data;
|
||||||
|
if (netplay)
|
||||||
|
{
|
||||||
|
if (netplay_is_alive(netplay))
|
||||||
|
return netplay_input_state(netplay, port, device, idx, id);
|
||||||
|
return netplay->cbs.state_cb(port, device, idx, id);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ^^^ Netplay polling callbacks */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netplay_disconnect
|
||||||
|
* @netplay : pointer to netplay object
|
||||||
|
*
|
||||||
|
* Disconnect netplay.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if successful. At present, cannot fail.
|
||||||
|
**/
|
||||||
|
static void netplay_disconnect(netplay_t *netplay)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < netplay->connections_size; i++)
|
||||||
|
netplay_hangup(netplay, &netplay->connections[i]);
|
||||||
|
|
||||||
|
deinit_netplay();
|
||||||
|
|
||||||
|
#ifdef HAVE_DISCORD
|
||||||
|
if (discord_is_inited)
|
||||||
|
{
|
||||||
|
discord_userdata_t userdata;
|
||||||
|
userdata.status = DISCORD_PRESENCE_NETPLAY_NETPLAY_STOPPED;
|
||||||
|
command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netplay_pre_frame:
|
||||||
|
* @netplay : pointer to netplay object
|
||||||
|
*
|
||||||
|
* Pre-frame for Netplay.
|
||||||
|
* Call this before running retro_run().
|
||||||
|
*
|
||||||
|
* Returns: true (1) if the frontend is cleared to emulate the frame, false (0)
|
||||||
|
* if we're stalled or paused
|
||||||
|
**/
|
||||||
|
static bool netplay_pre_frame(
|
||||||
|
bool netplay_public_announce,
|
||||||
|
bool netplay_use_mitm_server,
|
||||||
|
netplay_t *netplay)
|
||||||
|
{
|
||||||
|
bool sync_stalled = false;
|
||||||
|
net_driver_state_t *net_st = &networking_driver_st;
|
||||||
|
|
||||||
|
retro_assert(netplay);
|
||||||
|
|
||||||
|
if (netplay_public_announce)
|
||||||
|
{
|
||||||
|
net_st->reannounce++;
|
||||||
|
if (
|
||||||
|
(netplay->is_server || net_st->is_mitm) &&
|
||||||
|
(net_st->reannounce % 300 == 0))
|
||||||
|
netplay_announce();
|
||||||
|
}
|
||||||
|
/* Make sure that if announcement is turned on mid-game, it gets announced */
|
||||||
|
else
|
||||||
|
net_st->reannounce = -1;
|
||||||
|
|
||||||
|
/* FIXME: This is an ugly way to learn we're not paused anymore */
|
||||||
|
if (netplay->local_paused)
|
||||||
|
if (netplay->local_paused != false)
|
||||||
|
netplay_frontend_paused(netplay, false);
|
||||||
|
|
||||||
|
/* Are we ready now? */
|
||||||
|
if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION)
|
||||||
|
netplay_try_init_serialization(netplay);
|
||||||
|
|
||||||
|
if (netplay->is_server && !netplay_use_mitm_server)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_NETPLAYDISCOVERY
|
||||||
|
/* Advertise our server */
|
||||||
|
netplay_lan_ad_server(netplay);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* NAT traversal if applicable */
|
||||||
|
if (netplay->nat_traversal &&
|
||||||
|
!netplay->nat_traversal_task_oustanding &&
|
||||||
|
netplay->nat_traversal_state.request_outstanding &&
|
||||||
|
!netplay->nat_traversal_state.have_inet4)
|
||||||
|
{
|
||||||
|
struct timeval tmptv = {0};
|
||||||
|
fd_set fds = netplay->nat_traversal_state.fds;
|
||||||
|
if (socket_select(netplay->nat_traversal_state.nfds, &fds, NULL, NULL, &tmptv) > 0)
|
||||||
|
natt_read(&netplay->nat_traversal_state);
|
||||||
|
|
||||||
|
#ifndef HAVE_SOCKET_LEGACY
|
||||||
|
if (!netplay->nat_traversal_state.request_outstanding ||
|
||||||
|
netplay->nat_traversal_state.have_inet4)
|
||||||
|
netplay_announce_nat_traversal(netplay);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sync_stalled = !netplay_sync_pre_frame(netplay);
|
||||||
|
|
||||||
|
/* If we're disconnected, deinitialize */
|
||||||
|
if (!netplay->is_server && !netplay->connections[0].active)
|
||||||
|
{
|
||||||
|
netplay_disconnect(netplay);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sync_stalled ||
|
||||||
|
((!netplay->is_server || (netplay->connected_players>1)) &&
|
||||||
|
(netplay->stall || netplay->remote_paused)))
|
||||||
|
{
|
||||||
|
/* We may have received data even if we're stalled, so run post-frame
|
||||||
|
* sync */
|
||||||
|
netplay_sync_post_frame(netplay, true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deinit_netplay(void)
|
||||||
|
{
|
||||||
|
net_driver_state_t *net_st = &networking_driver_st;
|
||||||
|
|
||||||
|
if (net_st->data)
|
||||||
|
{
|
||||||
|
netplay_free(net_st->data);
|
||||||
|
net_st->netplay_enabled = false;
|
||||||
|
net_st->netplay_is_client = false;
|
||||||
|
net_st->is_mitm = false;
|
||||||
|
}
|
||||||
|
net_st->data = NULL;
|
||||||
|
core_unset_netplay_callbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool init_netplay(void *direct_host, const char *server, unsigned port)
|
||||||
|
{
|
||||||
|
struct retro_callbacks cbs = {0};
|
||||||
|
uint64_t serialization_quirks = 0;
|
||||||
|
uint64_t quirks = 0;
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
net_driver_state_t *net_st = &networking_driver_st;
|
||||||
|
bool _netplay_is_client = net_st->netplay_is_client;
|
||||||
|
bool _netplay_enabled = net_st->netplay_enabled;
|
||||||
|
|
||||||
|
if (!_netplay_enabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
core_set_default_callbacks(&cbs);
|
||||||
|
if (!core_set_netplay_callbacks())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Map the core's quirks to our quirks */
|
||||||
|
serialization_quirks = core_serialization_quirks();
|
||||||
|
|
||||||
|
/* Quirks we don't support! Just disable everything. */
|
||||||
|
if (serialization_quirks & ~((uint64_t) NETPLAY_QUIRK_MAP_UNDERSTOOD))
|
||||||
|
quirks |= NETPLAY_QUIRK_NO_SAVESTATES;
|
||||||
|
|
||||||
|
if (serialization_quirks & NETPLAY_QUIRK_MAP_NO_SAVESTATES)
|
||||||
|
quirks |= NETPLAY_QUIRK_NO_SAVESTATES;
|
||||||
|
if (serialization_quirks & NETPLAY_QUIRK_MAP_NO_TRANSMISSION)
|
||||||
|
quirks |= NETPLAY_QUIRK_NO_TRANSMISSION;
|
||||||
|
if (serialization_quirks & NETPLAY_QUIRK_MAP_INITIALIZATION)
|
||||||
|
quirks |= NETPLAY_QUIRK_INITIALIZATION;
|
||||||
|
if (serialization_quirks & NETPLAY_QUIRK_MAP_ENDIAN_DEPENDENT)
|
||||||
|
quirks |= NETPLAY_QUIRK_ENDIAN_DEPENDENT;
|
||||||
|
if (serialization_quirks & NETPLAY_QUIRK_MAP_PLATFORM_DEPENDENT)
|
||||||
|
quirks |= NETPLAY_QUIRK_PLATFORM_DEPENDENT;
|
||||||
|
|
||||||
|
if (!_netplay_is_client)
|
||||||
|
{
|
||||||
|
runloop_msg_queue_push(
|
||||||
|
msg_hash_to_str(MSG_WAITING_FOR_CLIENT),
|
||||||
|
0, 180, false,
|
||||||
|
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||||
|
|
||||||
|
if (settings->bools.netplay_public_announce)
|
||||||
|
netplay_announce();
|
||||||
|
}
|
||||||
|
|
||||||
|
net_st->data = (netplay_t*)netplay_new(
|
||||||
|
_netplay_is_client
|
||||||
|
? direct_host
|
||||||
|
: NULL,
|
||||||
|
_netplay_is_client
|
||||||
|
? (!net_st->netplay_client_deferred
|
||||||
|
? server
|
||||||
|
: net_st->server_address_deferred)
|
||||||
|
: NULL,
|
||||||
|
_netplay_is_client ? (!net_st->netplay_client_deferred
|
||||||
|
? port
|
||||||
|
: net_st->server_port_deferred)
|
||||||
|
: (port != 0 ? port : RARCH_DEFAULT_PORT),
|
||||||
|
settings->bools.netplay_stateless_mode,
|
||||||
|
settings->ints.netplay_check_frames,
|
||||||
|
&cbs,
|
||||||
|
settings->bools.netplay_nat_traversal && !settings->bools.netplay_use_mitm_server,
|
||||||
|
#ifdef HAVE_DISCORD
|
||||||
|
discord_get_own_username()
|
||||||
|
? discord_get_own_username()
|
||||||
|
:
|
||||||
|
#endif
|
||||||
|
settings->paths.username,
|
||||||
|
quirks);
|
||||||
|
|
||||||
|
if (net_st->data)
|
||||||
|
{
|
||||||
|
if ( net_st->data->is_server
|
||||||
|
&& !settings->bools.netplay_start_as_spectator)
|
||||||
|
netplay_toggle_play_spectate(net_st->data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RARCH_WARN("%s\n", msg_hash_to_str(MSG_NETPLAY_FAILED));
|
||||||
|
|
||||||
|
runloop_msg_queue_push(
|
||||||
|
msg_hash_to_str(MSG_NETPLAY_FAILED),
|
||||||
|
0, 180, false,
|
||||||
|
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netplay_driver_ctl
|
||||||
|
*
|
||||||
|
* Frontend access to Netplay functionality
|
||||||
|
*/
|
||||||
|
bool netplay_driver_ctl(enum rarch_netplay_ctl_state state, void *data)
|
||||||
|
{
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
net_driver_state_t *net_st = &networking_driver_st;
|
||||||
|
netplay_t *netplay = net_st->data;
|
||||||
|
bool ret = true;
|
||||||
|
|
||||||
|
if (net_st->in_netplay)
|
||||||
|
return true;
|
||||||
|
net_st->in_netplay = true;
|
||||||
|
|
||||||
|
if (!netplay)
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case RARCH_NETPLAY_CTL_ENABLE_SERVER:
|
||||||
|
net_st->netplay_enabled = true;
|
||||||
|
net_st->netplay_is_client = false;
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
case RARCH_NETPLAY_CTL_ENABLE_CLIENT:
|
||||||
|
net_st->netplay_enabled = true;
|
||||||
|
net_st->netplay_is_client = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RARCH_NETPLAY_CTL_DISABLE:
|
||||||
|
net_st->netplay_enabled = false;
|
||||||
|
#ifdef HAVE_DISCORD
|
||||||
|
if (discord_is_inited)
|
||||||
|
{
|
||||||
|
discord_userdata_t userdata;
|
||||||
|
userdata.status = DISCORD_PRESENCE_NETPLAY_NETPLAY_STOPPED;
|
||||||
|
command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
case RARCH_NETPLAY_CTL_IS_ENABLED:
|
||||||
|
ret = net_st->netplay_enabled;
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
case RARCH_NETPLAY_CTL_IS_REPLAYING:
|
||||||
|
case RARCH_NETPLAY_CTL_IS_DATA_INITED:
|
||||||
|
ret = false;
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
case RARCH_NETPLAY_CTL_IS_SERVER:
|
||||||
|
ret = net_st->netplay_enabled
|
||||||
|
&& !net_st->netplay_is_client;
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
case RARCH_NETPLAY_CTL_IS_CONNECTED:
|
||||||
|
ret = false;
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case RARCH_NETPLAY_CTL_ENABLE_SERVER:
|
||||||
|
case RARCH_NETPLAY_CTL_ENABLE_CLIENT:
|
||||||
|
case RARCH_NETPLAY_CTL_IS_DATA_INITED:
|
||||||
|
goto done;
|
||||||
|
case RARCH_NETPLAY_CTL_DISABLE:
|
||||||
|
ret = false;
|
||||||
|
goto done;
|
||||||
|
case RARCH_NETPLAY_CTL_IS_ENABLED:
|
||||||
|
goto done;
|
||||||
|
case RARCH_NETPLAY_CTL_IS_REPLAYING:
|
||||||
|
ret = netplay->is_replay;
|
||||||
|
goto done;
|
||||||
|
case RARCH_NETPLAY_CTL_IS_SERVER:
|
||||||
|
ret = net_st->netplay_enabled
|
||||||
|
&& !net_st->netplay_is_client;
|
||||||
|
goto done;
|
||||||
|
case RARCH_NETPLAY_CTL_IS_CONNECTED:
|
||||||
|
ret = netplay->is_connected;
|
||||||
|
goto done;
|
||||||
|
case RARCH_NETPLAY_CTL_POST_FRAME:
|
||||||
|
netplay_post_frame(netplay);
|
||||||
|
/* If we're disconnected, deinitialize */
|
||||||
|
if (!netplay->is_server && !netplay->connections[0].active)
|
||||||
|
netplay_disconnect(netplay);
|
||||||
|
break;
|
||||||
|
case RARCH_NETPLAY_CTL_PRE_FRAME:
|
||||||
|
ret = netplay_pre_frame(
|
||||||
|
settings->bools.netplay_public_announce,
|
||||||
|
settings->bools.netplay_use_mitm_server,
|
||||||
|
netplay);
|
||||||
|
goto done;
|
||||||
|
case RARCH_NETPLAY_CTL_GAME_WATCH:
|
||||||
|
netplay_toggle_play_spectate(netplay);
|
||||||
|
break;
|
||||||
|
case RARCH_NETPLAY_CTL_PAUSE:
|
||||||
|
if (netplay->local_paused != true)
|
||||||
|
netplay_frontend_paused(netplay, true);
|
||||||
|
break;
|
||||||
|
case RARCH_NETPLAY_CTL_UNPAUSE:
|
||||||
|
if (netplay->local_paused != false)
|
||||||
|
netplay_frontend_paused(netplay, false);
|
||||||
|
break;
|
||||||
|
case RARCH_NETPLAY_CTL_LOAD_SAVESTATE:
|
||||||
|
netplay_load_savestate(netplay, (retro_ctx_serialize_info_t*)data, true);
|
||||||
|
break;
|
||||||
|
case RARCH_NETPLAY_CTL_RESET:
|
||||||
|
netplay_core_reset(netplay);
|
||||||
|
break;
|
||||||
|
case RARCH_NETPLAY_CTL_DISCONNECT:
|
||||||
|
ret = true;
|
||||||
|
if (netplay)
|
||||||
|
netplay_disconnect(netplay);
|
||||||
|
goto done;
|
||||||
|
case RARCH_NETPLAY_CTL_FINISHED_NAT_TRAVERSAL:
|
||||||
|
netplay->nat_traversal_task_oustanding = false;
|
||||||
|
#ifndef HAVE_SOCKET_LEGACY
|
||||||
|
netplay_announce_nat_traversal(netplay);
|
||||||
|
#endif
|
||||||
|
goto done;
|
||||||
|
case RARCH_NETPLAY_CTL_DESYNC_PUSH:
|
||||||
|
netplay->desync++;
|
||||||
|
break;
|
||||||
|
case RARCH_NETPLAY_CTL_DESYNC_POP:
|
||||||
|
if (netplay->desync)
|
||||||
|
{
|
||||||
|
netplay->desync--;
|
||||||
|
if (!netplay->desync)
|
||||||
|
netplay_load_savestate(netplay, NULL, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case RARCH_NETPLAY_CTL_NONE:
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
net_st->in_netplay = false;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <string/stdstring.h>
|
#include <string/stdstring.h>
|
||||||
#include <compat/strl.h>
|
#include <compat/strl.h>
|
||||||
#include <formats/rjson.h>
|
#include <formats/rjson.h>
|
||||||
|
#include "netplay.h"
|
||||||
#include "netplay_discovery.h"
|
#include "netplay_discovery.h"
|
||||||
#include "../../verbosity.h"
|
#include "../../verbosity.h"
|
||||||
|
|
||||||
|
790
retroarch.c
790
retroarch.c
@ -1249,7 +1249,7 @@ bool discord_is_ready(void)
|
|||||||
return discord_st->ready;
|
return discord_st->ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *discord_get_own_username(void)
|
char *discord_get_own_username(void)
|
||||||
{
|
{
|
||||||
discord_state_t *discord_st = &discord_state_st;
|
discord_state_t *discord_st = &discord_state_st;
|
||||||
if (discord_st->ready)
|
if (discord_st->ready)
|
||||||
@ -1570,7 +1570,7 @@ void discord_update(enum discord_presence presence)
|
|||||||
{
|
{
|
||||||
char join_secret[128];
|
char join_secret[128];
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
struct rarch_state *p_rarch = &rarch_st;
|
||||||
struct netplay_room *room = &p_rarch->netplay_host_room;
|
struct netplay_room *room = &networking_state_get_ptr()->host_room;
|
||||||
bool host_method_is_mitm = room->host_method == NETPLAY_HOST_METHOD_MITM;
|
bool host_method_is_mitm = room->host_method == NETPLAY_HOST_METHOD_MITM;
|
||||||
const char *srv_address = host_method_is_mitm ? room->mitm_address : room->address;
|
const char *srv_address = host_method_is_mitm ? room->mitm_address : room->address;
|
||||||
unsigned srv_port = host_method_is_mitm ? room->mitm_port : room->port;
|
unsigned srv_port = host_method_is_mitm ? room->mitm_port : room->port;
|
||||||
@ -1691,728 +1691,6 @@ void discord_init(const char *discord_app_id, char *args)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_NETWORKING
|
|
||||||
static bool init_netplay_deferred(const char* server, unsigned port)
|
|
||||||
{
|
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
|
||||||
if (!string_is_empty(server) && port != 0)
|
|
||||||
{
|
|
||||||
strlcpy(p_rarch->server_address_deferred, server,
|
|
||||||
sizeof(p_rarch->server_address_deferred));
|
|
||||||
p_rarch->server_port_deferred = port;
|
|
||||||
p_rarch->netplay_client_deferred = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
p_rarch->netplay_client_deferred = false;
|
|
||||||
|
|
||||||
return p_rarch->netplay_client_deferred;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* input_poll_net
|
|
||||||
*
|
|
||||||
* Poll the network if necessary.
|
|
||||||
*/
|
|
||||||
void input_poll_net(void)
|
|
||||||
{
|
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
|
||||||
netplay_t *netplay = p_rarch->netplay_data;
|
|
||||||
if (!netplay_should_skip(netplay) && netplay && netplay->can_poll)
|
|
||||||
{
|
|
||||||
input_driver_state_t
|
|
||||||
*input_st = input_state_get_ptr();
|
|
||||||
netplay->can_poll = false;
|
|
||||||
netplay_poll(
|
|
||||||
input_st->block_libretro_input,
|
|
||||||
config_get_ptr(),
|
|
||||||
netplay);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Netplay polling callbacks */
|
|
||||||
static void video_frame_net(const void *data, unsigned width,
|
|
||||||
unsigned height, size_t pitch)
|
|
||||||
{
|
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
|
||||||
netplay_t *netplay = p_rarch->netplay_data;
|
|
||||||
if (!netplay_should_skip(netplay))
|
|
||||||
netplay->cbs.frame_cb(data, width, height, pitch);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void audio_sample_net(int16_t left, int16_t right)
|
|
||||||
{
|
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
|
||||||
netplay_t *netplay = p_rarch->netplay_data;
|
|
||||||
if (!netplay_should_skip(netplay) && !netplay->stall)
|
|
||||||
netplay->cbs.sample_cb(left, right);
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t audio_sample_batch_net(const int16_t *data, size_t frames)
|
|
||||||
{
|
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
|
||||||
netplay_t *netplay = p_rarch->netplay_data;
|
|
||||||
if (!netplay_should_skip(netplay) && !netplay->stall)
|
|
||||||
return netplay->cbs.sample_batch_cb(data, frames);
|
|
||||||
return frames;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void netplay_announce_cb(retro_task_t *task,
|
|
||||||
void *task_data, void *user_data, const char *error)
|
|
||||||
{
|
|
||||||
if (task_data)
|
|
||||||
{
|
|
||||||
unsigned i, ip_len, port_len;
|
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
|
||||||
http_transfer_data_t *data = (http_transfer_data_t*)task_data;
|
|
||||||
struct netplay_room *host_room = &p_rarch->netplay_host_room;
|
|
||||||
struct string_list *lines = NULL;
|
|
||||||
char *mitm_ip = NULL;
|
|
||||||
char *mitm_port = NULL;
|
|
||||||
char *buf = NULL;
|
|
||||||
char *host_string = NULL;
|
|
||||||
|
|
||||||
if (data->len == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
buf = (char*)calloc(1, data->len + 1);
|
|
||||||
|
|
||||||
memcpy(buf, data->data, data->len);
|
|
||||||
|
|
||||||
lines = string_split(buf, "\n");
|
|
||||||
|
|
||||||
if (lines->size == 0)
|
|
||||||
{
|
|
||||||
string_list_free(lines);
|
|
||||||
free(buf);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(host_room, 0, sizeof(*host_room));
|
|
||||||
|
|
||||||
for (i = 0; i < lines->size; i++)
|
|
||||||
{
|
|
||||||
const char *line = lines->elems[i].data;
|
|
||||||
|
|
||||||
if (!string_is_empty(line))
|
|
||||||
{
|
|
||||||
struct string_list *kv = string_split(line, "=");
|
|
||||||
const char *key = NULL;
|
|
||||||
const char *val = NULL;
|
|
||||||
|
|
||||||
if (!kv)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (kv->size != 2)
|
|
||||||
{
|
|
||||||
string_list_free(kv);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
key = kv->elems[0].data;
|
|
||||||
val = kv->elems[1].data;
|
|
||||||
|
|
||||||
if (string_is_equal(key, "id"))
|
|
||||||
sscanf(val, "%i", &host_room->id);
|
|
||||||
if (string_is_equal(key, "username"))
|
|
||||||
strlcpy(host_room->nickname, val, sizeof(host_room->nickname));
|
|
||||||
if (string_is_equal(key, "ip"))
|
|
||||||
strlcpy(host_room->address, val, sizeof(host_room->address));
|
|
||||||
if (string_is_equal(key, "mitm_ip"))
|
|
||||||
{
|
|
||||||
mitm_ip = strdup(val);
|
|
||||||
strlcpy(host_room->mitm_address, val, sizeof(host_room->mitm_address));
|
|
||||||
}
|
|
||||||
if (string_is_equal(key, "port"))
|
|
||||||
sscanf(val, "%i", &host_room->port);
|
|
||||||
if (string_is_equal(key, "mitm_port"))
|
|
||||||
{
|
|
||||||
mitm_port = strdup(val);
|
|
||||||
sscanf(mitm_port, "%i", &host_room->mitm_port);
|
|
||||||
}
|
|
||||||
if (string_is_equal(key, "core_name"))
|
|
||||||
strlcpy(host_room->corename, val, sizeof(host_room->corename));
|
|
||||||
if (string_is_equal(key, "frontend"))
|
|
||||||
strlcpy(host_room->frontend, val, sizeof(host_room->frontend));
|
|
||||||
if (string_is_equal(key, "core_version"))
|
|
||||||
strlcpy(host_room->coreversion, val, sizeof(host_room->coreversion));
|
|
||||||
if (string_is_equal(key, "game_name"))
|
|
||||||
strlcpy(host_room->gamename, val,
|
|
||||||
sizeof(host_room->gamename));
|
|
||||||
if (string_is_equal(key, "game_crc"))
|
|
||||||
sscanf(val, "%08d", &host_room->gamecrc);
|
|
||||||
if (string_is_equal(key, "host_method"))
|
|
||||||
sscanf(val, "%i", &host_room->host_method);
|
|
||||||
if (string_is_equal(key, "has_password"))
|
|
||||||
{
|
|
||||||
if ( string_is_equal_noncase(val, "true")
|
|
||||||
|| string_is_equal(val, "1"))
|
|
||||||
host_room->has_password = true;
|
|
||||||
else
|
|
||||||
host_room->has_password = false;
|
|
||||||
}
|
|
||||||
if (string_is_equal(key, "has_spectate_password"))
|
|
||||||
{
|
|
||||||
if ( string_is_equal_noncase(val, "true")
|
|
||||||
|| string_is_equal(val, "1"))
|
|
||||||
host_room->has_spectate_password = true;
|
|
||||||
else
|
|
||||||
host_room->has_spectate_password = false;
|
|
||||||
}
|
|
||||||
if (string_is_equal(key, "fixed"))
|
|
||||||
{
|
|
||||||
if ( string_is_equal_noncase(val, "true")
|
|
||||||
|| string_is_equal(val, "1"))
|
|
||||||
host_room->fixed = true;
|
|
||||||
else
|
|
||||||
host_room->fixed = false;
|
|
||||||
}
|
|
||||||
if (string_is_equal(key, "retroarch_version"))
|
|
||||||
strlcpy(host_room->retroarch_version, val,
|
|
||||||
sizeof(host_room->retroarch_version));
|
|
||||||
if (string_is_equal(key, "country"))
|
|
||||||
strlcpy(host_room->country, val,
|
|
||||||
sizeof(host_room->country));
|
|
||||||
|
|
||||||
string_list_free(kv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mitm_ip && mitm_port)
|
|
||||||
{
|
|
||||||
ip_len = (unsigned)strlen(mitm_ip);
|
|
||||||
port_len = (unsigned)strlen(mitm_port);
|
|
||||||
|
|
||||||
/* Enable Netplay client mode */
|
|
||||||
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL))
|
|
||||||
{
|
|
||||||
command_event(CMD_EVENT_NETPLAY_DEINIT, NULL);
|
|
||||||
p_rarch->is_mitm = true;
|
|
||||||
host_room->host_method = NETPLAY_HOST_METHOD_MITM;
|
|
||||||
}
|
|
||||||
|
|
||||||
netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_CLIENT, NULL);
|
|
||||||
|
|
||||||
host_string = (char*)calloc(1, ip_len + port_len + 2);
|
|
||||||
|
|
||||||
memcpy(host_string, mitm_ip, ip_len);
|
|
||||||
memcpy(host_string + ip_len, "|", 1);
|
|
||||||
memcpy(host_string + ip_len + 1, mitm_port, port_len);
|
|
||||||
|
|
||||||
/* Enable Netplay */
|
|
||||||
command_event(CMD_EVENT_NETPLAY_INIT_DIRECT_DEFERRED, (void*)host_string);
|
|
||||||
command_event(CMD_EVENT_NETPLAY_INIT, (void*)host_string);
|
|
||||||
|
|
||||||
free(host_string);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_DISCORD
|
|
||||||
if (discord_is_inited)
|
|
||||||
{
|
|
||||||
discord_userdata_t userdata;
|
|
||||||
userdata.status = DISCORD_PRESENCE_NETPLAY_HOSTING;
|
|
||||||
command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
string_list_free(lines);
|
|
||||||
free(buf);
|
|
||||||
|
|
||||||
if (mitm_ip)
|
|
||||||
free(mitm_ip);
|
|
||||||
if (mitm_port)
|
|
||||||
free(mitm_port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void netplay_announce(void)
|
|
||||||
{
|
|
||||||
char buf[4600];
|
|
||||||
char frontend_architecture[PATH_MAX_LENGTH];
|
|
||||||
char frontend_architecture_tmp[32];
|
|
||||||
const frontend_ctx_driver_t
|
|
||||||
*frontend_drv = NULL;
|
|
||||||
char url[2048] = "http://lobby.libretro.com/add/";
|
|
||||||
char *username = NULL;
|
|
||||||
char *corename = NULL;
|
|
||||||
char *gamename = NULL;
|
|
||||||
char *subsystemname = NULL;
|
|
||||||
char *coreversion = NULL;
|
|
||||||
char *frontend_ident = NULL;
|
|
||||||
settings_t *settings = config_get_ptr();
|
|
||||||
runloop_state_t *runloop_st = &runloop_state;
|
|
||||||
struct retro_system_info *system = &runloop_st->system.info;
|
|
||||||
uint32_t content_crc = content_get_crc();
|
|
||||||
struct string_list *subsystem = path_get_subsystem_list();
|
|
||||||
|
|
||||||
frontend_architecture[0] = '\0';
|
|
||||||
buf[0] = '\0';
|
|
||||||
|
|
||||||
if (subsystem)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
for (i = 0; i < subsystem->size; i++)
|
|
||||||
{
|
|
||||||
strlcat(buf, path_basename(subsystem->elems[i].data), sizeof(buf));
|
|
||||||
if (i < subsystem->size - 1)
|
|
||||||
strlcat(buf, "|", sizeof(buf));
|
|
||||||
}
|
|
||||||
net_http_urlencode(&gamename, buf);
|
|
||||||
net_http_urlencode(&subsystemname, path_get(RARCH_PATH_SUBSYSTEM));
|
|
||||||
content_crc = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const char *base = path_basename(path_get(RARCH_PATH_BASENAME));
|
|
||||||
|
|
||||||
net_http_urlencode(&gamename,
|
|
||||||
!string_is_empty(base) ? base : "N/A");
|
|
||||||
/* TODO/FIXME - subsystem should be implemented later? */
|
|
||||||
net_http_urlencode(&subsystemname, "N/A");
|
|
||||||
}
|
|
||||||
|
|
||||||
frontend_drv =
|
|
||||||
(const frontend_ctx_driver_t*)frontend_driver_get_cpu_architecture_str(
|
|
||||||
frontend_architecture_tmp, sizeof(frontend_architecture_tmp));
|
|
||||||
snprintf(frontend_architecture,
|
|
||||||
sizeof(frontend_architecture),
|
|
||||||
"%s %s",
|
|
||||||
frontend_drv->ident,
|
|
||||||
frontend_architecture_tmp);
|
|
||||||
|
|
||||||
#ifdef HAVE_DISCORD
|
|
||||||
if (discord_is_ready())
|
|
||||||
net_http_urlencode(&username, discord_get_own_username());
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
net_http_urlencode(&username, settings->paths.username);
|
|
||||||
net_http_urlencode(&corename, system->library_name);
|
|
||||||
net_http_urlencode(&coreversion, system->library_version);
|
|
||||||
net_http_urlencode(&frontend_ident, frontend_architecture);
|
|
||||||
|
|
||||||
buf[0] = '\0';
|
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "username=%s&core_name=%s&core_version=%s&"
|
|
||||||
"game_name=%s&game_crc=%08lX&port=%d&mitm_server=%s"
|
|
||||||
"&has_password=%d&has_spectate_password=%d&force_mitm=%d"
|
|
||||||
"&retroarch_version=%s&frontend=%s&subsystem_name=%s",
|
|
||||||
username, corename, coreversion, gamename, (unsigned long)content_crc,
|
|
||||||
settings->uints.netplay_port,
|
|
||||||
settings->arrays.netplay_mitm_server,
|
|
||||||
*settings->paths.netplay_password ? 1 : 0,
|
|
||||||
*settings->paths.netplay_spectate_password ? 1 : 0,
|
|
||||||
settings->bools.netplay_use_mitm_server,
|
|
||||||
PACKAGE_VERSION, frontend_architecture, subsystemname);
|
|
||||||
task_push_http_post_transfer(url, buf, true, NULL,
|
|
||||||
netplay_announce_cb, NULL);
|
|
||||||
|
|
||||||
if (username)
|
|
||||||
free(username);
|
|
||||||
if (corename)
|
|
||||||
free(corename);
|
|
||||||
if (gamename)
|
|
||||||
free(gamename);
|
|
||||||
if (coreversion)
|
|
||||||
free(coreversion);
|
|
||||||
if (frontend_ident)
|
|
||||||
free(frontend_ident);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int16_t input_state_net(unsigned port, unsigned device,
|
|
||||||
unsigned idx, unsigned id)
|
|
||||||
{
|
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
|
||||||
netplay_t *netplay = p_rarch->netplay_data;
|
|
||||||
if (netplay)
|
|
||||||
{
|
|
||||||
if (netplay_is_alive(netplay))
|
|
||||||
return netplay_input_state(netplay, port, device, idx, id);
|
|
||||||
return netplay->cbs.state_cb(port, device, idx, id);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ^^^ Netplay polling callbacks */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* netplay_disconnect
|
|
||||||
* @netplay : pointer to netplay object
|
|
||||||
*
|
|
||||||
* Disconnect netplay.
|
|
||||||
*
|
|
||||||
* Returns: true (1) if successful. At present, cannot fail.
|
|
||||||
**/
|
|
||||||
static void netplay_disconnect(netplay_t *netplay)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < netplay->connections_size; i++)
|
|
||||||
netplay_hangup(netplay, &netplay->connections[i]);
|
|
||||||
|
|
||||||
deinit_netplay();
|
|
||||||
|
|
||||||
#ifdef HAVE_DISCORD
|
|
||||||
if (discord_is_inited)
|
|
||||||
{
|
|
||||||
discord_userdata_t userdata;
|
|
||||||
userdata.status = DISCORD_PRESENCE_NETPLAY_NETPLAY_STOPPED;
|
|
||||||
command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* netplay_pre_frame:
|
|
||||||
* @netplay : pointer to netplay object
|
|
||||||
*
|
|
||||||
* Pre-frame for Netplay.
|
|
||||||
* Call this before running retro_run().
|
|
||||||
*
|
|
||||||
* Returns: true (1) if the frontend is cleared to emulate the frame, false (0)
|
|
||||||
* if we're stalled or paused
|
|
||||||
**/
|
|
||||||
static bool netplay_pre_frame(
|
|
||||||
bool netplay_public_announce,
|
|
||||||
bool netplay_use_mitm_server,
|
|
||||||
netplay_t *netplay)
|
|
||||||
{
|
|
||||||
bool sync_stalled = false;
|
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
|
||||||
|
|
||||||
retro_assert(netplay);
|
|
||||||
|
|
||||||
if (netplay_public_announce)
|
|
||||||
{
|
|
||||||
p_rarch->reannounce++;
|
|
||||||
if (
|
|
||||||
(netplay->is_server || p_rarch->is_mitm) &&
|
|
||||||
(p_rarch->reannounce % 300 == 0))
|
|
||||||
netplay_announce();
|
|
||||||
}
|
|
||||||
/* Make sure that if announcement is turned on mid-game, it gets announced */
|
|
||||||
else
|
|
||||||
p_rarch->reannounce = -1;
|
|
||||||
|
|
||||||
/* FIXME: This is an ugly way to learn we're not paused anymore */
|
|
||||||
if (netplay->local_paused)
|
|
||||||
if (netplay->local_paused != false)
|
|
||||||
netplay_frontend_paused(netplay, false);
|
|
||||||
|
|
||||||
/* Are we ready now? */
|
|
||||||
if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION)
|
|
||||||
netplay_try_init_serialization(netplay);
|
|
||||||
|
|
||||||
if (netplay->is_server && !netplay_use_mitm_server)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_NETPLAYDISCOVERY
|
|
||||||
/* Advertise our server */
|
|
||||||
netplay_lan_ad_server(netplay);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* NAT traversal if applicable */
|
|
||||||
if (netplay->nat_traversal &&
|
|
||||||
!netplay->nat_traversal_task_oustanding &&
|
|
||||||
netplay->nat_traversal_state.request_outstanding &&
|
|
||||||
!netplay->nat_traversal_state.have_inet4)
|
|
||||||
{
|
|
||||||
struct timeval tmptv = {0};
|
|
||||||
fd_set fds = netplay->nat_traversal_state.fds;
|
|
||||||
if (socket_select(netplay->nat_traversal_state.nfds, &fds, NULL, NULL, &tmptv) > 0)
|
|
||||||
natt_read(&netplay->nat_traversal_state);
|
|
||||||
|
|
||||||
#ifndef HAVE_SOCKET_LEGACY
|
|
||||||
if (!netplay->nat_traversal_state.request_outstanding ||
|
|
||||||
netplay->nat_traversal_state.have_inet4)
|
|
||||||
netplay_announce_nat_traversal(netplay);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sync_stalled = !netplay_sync_pre_frame(netplay);
|
|
||||||
|
|
||||||
/* If we're disconnected, deinitialize */
|
|
||||||
if (!netplay->is_server && !netplay->connections[0].active)
|
|
||||||
{
|
|
||||||
netplay_disconnect(netplay);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sync_stalled ||
|
|
||||||
((!netplay->is_server || (netplay->connected_players>1)) &&
|
|
||||||
(netplay->stall || netplay->remote_paused)))
|
|
||||||
{
|
|
||||||
/* We may have received data even if we're stalled, so run post-frame
|
|
||||||
* sync */
|
|
||||||
netplay_sync_post_frame(netplay, true);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void deinit_netplay(void)
|
|
||||||
{
|
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
|
||||||
|
|
||||||
if (p_rarch->netplay_data)
|
|
||||||
{
|
|
||||||
netplay_free(p_rarch->netplay_data);
|
|
||||||
p_rarch->netplay_enabled = false;
|
|
||||||
p_rarch->netplay_is_client = false;
|
|
||||||
p_rarch->is_mitm = false;
|
|
||||||
}
|
|
||||||
p_rarch->netplay_data = NULL;
|
|
||||||
core_unset_netplay_callbacks();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* init_netplay
|
|
||||||
* @direct_host : Host to connect to directly, if applicable (client only)
|
|
||||||
* @server : server address to connect to (client only)
|
|
||||||
* @port : TCP port to host on/connect to
|
|
||||||
*
|
|
||||||
* Initializes netplay.
|
|
||||||
*
|
|
||||||
* If netplay is already initialized, will return false (0).
|
|
||||||
*
|
|
||||||
* Returns: true (1) if successful, otherwise false (0).
|
|
||||||
**/
|
|
||||||
static bool init_netplay(void *direct_host,
|
|
||||||
const char *server, unsigned port)
|
|
||||||
{
|
|
||||||
struct retro_callbacks cbs = {0};
|
|
||||||
uint64_t serialization_quirks = 0;
|
|
||||||
uint64_t quirks = 0;
|
|
||||||
settings_t *settings = config_get_ptr();
|
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
|
||||||
bool _netplay_is_client = p_rarch->netplay_is_client;
|
|
||||||
bool _netplay_enabled = p_rarch->netplay_enabled;
|
|
||||||
|
|
||||||
if (!_netplay_enabled)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
core_set_default_callbacks(&cbs);
|
|
||||||
if (!core_set_netplay_callbacks())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Map the core's quirks to our quirks */
|
|
||||||
serialization_quirks = core_serialization_quirks();
|
|
||||||
|
|
||||||
/* Quirks we don't support! Just disable everything. */
|
|
||||||
if (serialization_quirks & ~((uint64_t) NETPLAY_QUIRK_MAP_UNDERSTOOD))
|
|
||||||
quirks |= NETPLAY_QUIRK_NO_SAVESTATES;
|
|
||||||
|
|
||||||
if (serialization_quirks & NETPLAY_QUIRK_MAP_NO_SAVESTATES)
|
|
||||||
quirks |= NETPLAY_QUIRK_NO_SAVESTATES;
|
|
||||||
if (serialization_quirks & NETPLAY_QUIRK_MAP_NO_TRANSMISSION)
|
|
||||||
quirks |= NETPLAY_QUIRK_NO_TRANSMISSION;
|
|
||||||
if (serialization_quirks & NETPLAY_QUIRK_MAP_INITIALIZATION)
|
|
||||||
quirks |= NETPLAY_QUIRK_INITIALIZATION;
|
|
||||||
if (serialization_quirks & NETPLAY_QUIRK_MAP_ENDIAN_DEPENDENT)
|
|
||||||
quirks |= NETPLAY_QUIRK_ENDIAN_DEPENDENT;
|
|
||||||
if (serialization_quirks & NETPLAY_QUIRK_MAP_PLATFORM_DEPENDENT)
|
|
||||||
quirks |= NETPLAY_QUIRK_PLATFORM_DEPENDENT;
|
|
||||||
|
|
||||||
if (!_netplay_is_client)
|
|
||||||
{
|
|
||||||
runloop_msg_queue_push(
|
|
||||||
msg_hash_to_str(MSG_WAITING_FOR_CLIENT),
|
|
||||||
0, 180, false,
|
|
||||||
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
|
||||||
|
|
||||||
if (settings->bools.netplay_public_announce)
|
|
||||||
netplay_announce();
|
|
||||||
}
|
|
||||||
|
|
||||||
p_rarch->netplay_data = (netplay_t*)netplay_new(
|
|
||||||
_netplay_is_client
|
|
||||||
? direct_host
|
|
||||||
: NULL,
|
|
||||||
_netplay_is_client
|
|
||||||
? (!p_rarch->netplay_client_deferred
|
|
||||||
? server
|
|
||||||
: p_rarch->server_address_deferred)
|
|
||||||
: NULL,
|
|
||||||
_netplay_is_client ? (!p_rarch->netplay_client_deferred
|
|
||||||
? port
|
|
||||||
: p_rarch->server_port_deferred)
|
|
||||||
: (port != 0 ? port : RARCH_DEFAULT_PORT),
|
|
||||||
settings->bools.netplay_stateless_mode,
|
|
||||||
settings->ints.netplay_check_frames,
|
|
||||||
&cbs,
|
|
||||||
settings->bools.netplay_nat_traversal && !settings->bools.netplay_use_mitm_server,
|
|
||||||
#ifdef HAVE_DISCORD
|
|
||||||
discord_get_own_username()
|
|
||||||
? discord_get_own_username()
|
|
||||||
:
|
|
||||||
#endif
|
|
||||||
settings->paths.username,
|
|
||||||
quirks);
|
|
||||||
|
|
||||||
if (p_rarch->netplay_data)
|
|
||||||
{
|
|
||||||
if ( p_rarch->netplay_data->is_server
|
|
||||||
&& !settings->bools.netplay_start_as_spectator)
|
|
||||||
netplay_toggle_play_spectate(p_rarch->netplay_data);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
RARCH_WARN("%s\n", msg_hash_to_str(MSG_NETPLAY_FAILED));
|
|
||||||
|
|
||||||
runloop_msg_queue_push(
|
|
||||||
msg_hash_to_str(MSG_NETPLAY_FAILED),
|
|
||||||
0, 180, false,
|
|
||||||
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* netplay_driver_ctl
|
|
||||||
*
|
|
||||||
* Frontend access to Netplay functionality
|
|
||||||
*/
|
|
||||||
bool netplay_driver_ctl(enum rarch_netplay_ctl_state state, void *data)
|
|
||||||
{
|
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
|
||||||
settings_t *settings = config_get_ptr();
|
|
||||||
netplay_t *netplay = p_rarch->netplay_data;
|
|
||||||
bool ret = true;
|
|
||||||
|
|
||||||
if (p_rarch->in_netplay)
|
|
||||||
return true;
|
|
||||||
p_rarch->in_netplay = true;
|
|
||||||
|
|
||||||
if (!netplay)
|
|
||||||
{
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case RARCH_NETPLAY_CTL_ENABLE_SERVER:
|
|
||||||
p_rarch->netplay_enabled = true;
|
|
||||||
p_rarch->netplay_is_client = false;
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
case RARCH_NETPLAY_CTL_ENABLE_CLIENT:
|
|
||||||
p_rarch->netplay_enabled = true;
|
|
||||||
p_rarch->netplay_is_client = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RARCH_NETPLAY_CTL_DISABLE:
|
|
||||||
p_rarch->netplay_enabled = false;
|
|
||||||
#ifdef HAVE_DISCORD
|
|
||||||
if (discord_is_inited)
|
|
||||||
{
|
|
||||||
discord_userdata_t userdata;
|
|
||||||
userdata.status = DISCORD_PRESENCE_NETPLAY_NETPLAY_STOPPED;
|
|
||||||
command_event(CMD_EVENT_DISCORD_UPDATE, &userdata);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
case RARCH_NETPLAY_CTL_IS_ENABLED:
|
|
||||||
ret = p_rarch->netplay_enabled;
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
case RARCH_NETPLAY_CTL_IS_REPLAYING:
|
|
||||||
case RARCH_NETPLAY_CTL_IS_DATA_INITED:
|
|
||||||
ret = false;
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
case RARCH_NETPLAY_CTL_IS_SERVER:
|
|
||||||
ret = p_rarch->netplay_enabled
|
|
||||||
&& !p_rarch->netplay_is_client;
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
case RARCH_NETPLAY_CTL_IS_CONNECTED:
|
|
||||||
ret = false;
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
default:
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case RARCH_NETPLAY_CTL_ENABLE_SERVER:
|
|
||||||
case RARCH_NETPLAY_CTL_ENABLE_CLIENT:
|
|
||||||
case RARCH_NETPLAY_CTL_IS_DATA_INITED:
|
|
||||||
goto done;
|
|
||||||
case RARCH_NETPLAY_CTL_DISABLE:
|
|
||||||
ret = false;
|
|
||||||
goto done;
|
|
||||||
case RARCH_NETPLAY_CTL_IS_ENABLED:
|
|
||||||
goto done;
|
|
||||||
case RARCH_NETPLAY_CTL_IS_REPLAYING:
|
|
||||||
ret = netplay->is_replay;
|
|
||||||
goto done;
|
|
||||||
case RARCH_NETPLAY_CTL_IS_SERVER:
|
|
||||||
ret = p_rarch->netplay_enabled
|
|
||||||
&& !p_rarch->netplay_is_client;
|
|
||||||
goto done;
|
|
||||||
case RARCH_NETPLAY_CTL_IS_CONNECTED:
|
|
||||||
ret = netplay->is_connected;
|
|
||||||
goto done;
|
|
||||||
case RARCH_NETPLAY_CTL_POST_FRAME:
|
|
||||||
netplay_post_frame(netplay);
|
|
||||||
/* If we're disconnected, deinitialize */
|
|
||||||
if (!netplay->is_server && !netplay->connections[0].active)
|
|
||||||
netplay_disconnect(netplay);
|
|
||||||
break;
|
|
||||||
case RARCH_NETPLAY_CTL_PRE_FRAME:
|
|
||||||
ret = netplay_pre_frame(
|
|
||||||
settings->bools.netplay_public_announce,
|
|
||||||
settings->bools.netplay_use_mitm_server,
|
|
||||||
netplay);
|
|
||||||
goto done;
|
|
||||||
case RARCH_NETPLAY_CTL_GAME_WATCH:
|
|
||||||
netplay_toggle_play_spectate(netplay);
|
|
||||||
break;
|
|
||||||
case RARCH_NETPLAY_CTL_PAUSE:
|
|
||||||
if (netplay->local_paused != true)
|
|
||||||
netplay_frontend_paused(netplay, true);
|
|
||||||
break;
|
|
||||||
case RARCH_NETPLAY_CTL_UNPAUSE:
|
|
||||||
if (netplay->local_paused != false)
|
|
||||||
netplay_frontend_paused(netplay, false);
|
|
||||||
break;
|
|
||||||
case RARCH_NETPLAY_CTL_LOAD_SAVESTATE:
|
|
||||||
netplay_load_savestate(netplay, (retro_ctx_serialize_info_t*)data, true);
|
|
||||||
break;
|
|
||||||
case RARCH_NETPLAY_CTL_RESET:
|
|
||||||
netplay_core_reset(netplay);
|
|
||||||
break;
|
|
||||||
case RARCH_NETPLAY_CTL_DISCONNECT:
|
|
||||||
ret = true;
|
|
||||||
if (netplay)
|
|
||||||
netplay_disconnect(netplay);
|
|
||||||
goto done;
|
|
||||||
case RARCH_NETPLAY_CTL_FINISHED_NAT_TRAVERSAL:
|
|
||||||
netplay->nat_traversal_task_oustanding = false;
|
|
||||||
#ifndef HAVE_SOCKET_LEGACY
|
|
||||||
netplay_announce_nat_traversal(netplay);
|
|
||||||
#endif
|
|
||||||
goto done;
|
|
||||||
case RARCH_NETPLAY_CTL_DESYNC_PUSH:
|
|
||||||
netplay->desync++;
|
|
||||||
break;
|
|
||||||
case RARCH_NETPLAY_CTL_DESYNC_POP:
|
|
||||||
if (netplay->desync)
|
|
||||||
{
|
|
||||||
netplay->desync--;
|
|
||||||
if (!netplay->desync)
|
|
||||||
netplay_load_savestate(netplay, NULL, true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
case RARCH_NETPLAY_CTL_NONE:
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
p_rarch->in_netplay = false;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void log_counters(
|
static void log_counters(
|
||||||
struct retro_perf_counter **counters, unsigned num)
|
struct retro_perf_counter **counters, unsigned num)
|
||||||
{
|
{
|
||||||
@ -7613,6 +6891,10 @@ void retroarch_override_setting_set(
|
|||||||
enum rarch_override_setting enum_idx, void *data)
|
enum rarch_override_setting enum_idx, void *data)
|
||||||
{
|
{
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
struct rarch_state *p_rarch = &rarch_st;
|
||||||
|
#ifdef HAVE_NETWORKING
|
||||||
|
net_driver_state_t *net_st = networking_state_get_ptr();
|
||||||
|
netplay_t *netplay = net_st->data;
|
||||||
|
#endif
|
||||||
|
|
||||||
switch (enum_idx)
|
switch (enum_idx)
|
||||||
{
|
{
|
||||||
@ -7644,19 +6926,19 @@ void retroarch_override_setting_set(
|
|||||||
break;
|
break;
|
||||||
#ifdef HAVE_NETWORKING
|
#ifdef HAVE_NETWORKING
|
||||||
case RARCH_OVERRIDE_SETTING_NETPLAY_MODE:
|
case RARCH_OVERRIDE_SETTING_NETPLAY_MODE:
|
||||||
p_rarch->has_set_netplay_mode = true;
|
net_st->has_set_netplay_mode = true;
|
||||||
break;
|
break;
|
||||||
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS:
|
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS:
|
||||||
p_rarch->has_set_netplay_ip_address = true;
|
net_st->has_set_netplay_ip_address = true;
|
||||||
break;
|
break;
|
||||||
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT:
|
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT:
|
||||||
p_rarch->has_set_netplay_ip_port = true;
|
net_st->has_set_netplay_ip_port = true;
|
||||||
break;
|
break;
|
||||||
case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE:
|
case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE:
|
||||||
p_rarch->has_set_netplay_stateless_mode = true;
|
net_st->has_set_netplay_stateless_mode = true;
|
||||||
break;
|
break;
|
||||||
case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES:
|
case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES:
|
||||||
p_rarch->has_set_netplay_check_frames = true;
|
net_st->has_set_netplay_check_frames = true;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case RARCH_OVERRIDE_SETTING_UPS_PREF:
|
case RARCH_OVERRIDE_SETTING_UPS_PREF:
|
||||||
@ -7686,7 +6968,11 @@ void retroarch_override_setting_set(
|
|||||||
void retroarch_override_setting_unset(
|
void retroarch_override_setting_unset(
|
||||||
enum rarch_override_setting enum_idx, void *data)
|
enum rarch_override_setting enum_idx, void *data)
|
||||||
{
|
{
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
struct rarch_state *p_rarch = &rarch_st;
|
||||||
|
#ifdef HAVE_NETWORKING
|
||||||
|
net_driver_state_t *net_st = networking_state_get_ptr();
|
||||||
|
netplay_t *netplay = net_st->data;
|
||||||
|
#endif
|
||||||
|
|
||||||
switch (enum_idx)
|
switch (enum_idx)
|
||||||
{
|
{
|
||||||
@ -7718,19 +7004,19 @@ void retroarch_override_setting_unset(
|
|||||||
break;
|
break;
|
||||||
#ifdef HAVE_NETWORKING
|
#ifdef HAVE_NETWORKING
|
||||||
case RARCH_OVERRIDE_SETTING_NETPLAY_MODE:
|
case RARCH_OVERRIDE_SETTING_NETPLAY_MODE:
|
||||||
p_rarch->has_set_netplay_mode = false;
|
net_st->has_set_netplay_mode = false;
|
||||||
break;
|
break;
|
||||||
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS:
|
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS:
|
||||||
p_rarch->has_set_netplay_ip_address = false;
|
net_st->has_set_netplay_ip_address = false;
|
||||||
break;
|
break;
|
||||||
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT:
|
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT:
|
||||||
p_rarch->has_set_netplay_ip_port = false;
|
net_st->has_set_netplay_ip_port = false;
|
||||||
break;
|
break;
|
||||||
case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE:
|
case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE:
|
||||||
p_rarch->has_set_netplay_stateless_mode = false;
|
net_st->has_set_netplay_stateless_mode = false;
|
||||||
break;
|
break;
|
||||||
case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES:
|
case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES:
|
||||||
p_rarch->has_set_netplay_check_frames = false;
|
net_st->has_set_netplay_check_frames = false;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case RARCH_OVERRIDE_SETTING_UPS_PREF:
|
case RARCH_OVERRIDE_SETTING_UPS_PREF:
|
||||||
@ -16318,7 +15604,10 @@ bool retroarch_ctl(enum rarch_ctl_state state, void *data)
|
|||||||
bool retroarch_override_setting_is_set(
|
bool retroarch_override_setting_is_set(
|
||||||
enum rarch_override_setting enum_idx, void *data)
|
enum rarch_override_setting enum_idx, void *data)
|
||||||
{
|
{
|
||||||
struct rarch_state *p_rarch = &rarch_st;
|
struct rarch_state *p_rarch = &rarch_st;
|
||||||
|
#ifdef HAVE_NETWORKING
|
||||||
|
net_driver_state_t *net_st = networking_state_get_ptr();
|
||||||
|
#endif
|
||||||
|
|
||||||
switch (enum_idx)
|
switch (enum_idx)
|
||||||
{
|
{
|
||||||
@ -16345,15 +15634,15 @@ bool retroarch_override_setting_is_set(
|
|||||||
return p_rarch->has_set_state_path;
|
return p_rarch->has_set_state_path;
|
||||||
#ifdef HAVE_NETWORKING
|
#ifdef HAVE_NETWORKING
|
||||||
case RARCH_OVERRIDE_SETTING_NETPLAY_MODE:
|
case RARCH_OVERRIDE_SETTING_NETPLAY_MODE:
|
||||||
return p_rarch->has_set_netplay_mode;
|
return net_st->has_set_netplay_mode;
|
||||||
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS:
|
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS:
|
||||||
return p_rarch->has_set_netplay_ip_address;
|
return net_st->has_set_netplay_ip_address;
|
||||||
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT:
|
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT:
|
||||||
return p_rarch->has_set_netplay_ip_port;
|
return net_st->has_set_netplay_ip_port;
|
||||||
case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE:
|
case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE:
|
||||||
return p_rarch->has_set_netplay_stateless_mode;
|
return net_st->has_set_netplay_stateless_mode;
|
||||||
case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES:
|
case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES:
|
||||||
return p_rarch->has_set_netplay_check_frames;
|
return net_st->has_set_netplay_check_frames;
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_PATCH
|
#ifdef HAVE_PATCH
|
||||||
case RARCH_OVERRIDE_SETTING_UPS_PREF:
|
case RARCH_OVERRIDE_SETTING_UPS_PREF:
|
||||||
@ -18416,21 +17705,16 @@ static bool core_init_libretro_cbs(struct retro_callbacks *cbs)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
bool core_set_default_callbacks(void *data)
|
||||||
* core_set_default_callbacks:
|
|
||||||
* @data : pointer to retro_callbacks object
|
|
||||||
*
|
|
||||||
* Binds the libretro callbacks to default callback functions.
|
|
||||||
**/
|
|
||||||
static bool core_set_default_callbacks(struct retro_callbacks *cbs)
|
|
||||||
{
|
{
|
||||||
|
struct retro_callbacks *cbs = (struct retro_callbacks*)data;
|
||||||
retro_input_state_t state_cb = core_input_state_poll_return_cb();
|
retro_input_state_t state_cb = core_input_state_poll_return_cb();
|
||||||
|
|
||||||
cbs->frame_cb = video_driver_frame;
|
cbs->frame_cb = video_driver_frame;
|
||||||
cbs->sample_cb = audio_driver_sample;
|
cbs->sample_cb = audio_driver_sample;
|
||||||
cbs->sample_batch_cb = audio_driver_sample_batch;
|
cbs->sample_batch_cb = audio_driver_sample_batch;
|
||||||
cbs->state_cb = state_cb;
|
cbs->state_cb = state_cb;
|
||||||
cbs->poll_cb = input_driver_poll;
|
cbs->poll_cb = input_driver_poll;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -405,16 +405,9 @@ struct rarch_state
|
|||||||
const wifi_driver_t *wifi_driver;
|
const wifi_driver_t *wifi_driver;
|
||||||
void *wifi_data;
|
void *wifi_data;
|
||||||
|
|
||||||
#ifdef HAVE_NETWORKING
|
|
||||||
/* Used while Netplay is running */
|
|
||||||
netplay_t *netplay_data;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct retro_perf_counter *perf_counters_rarch[MAX_COUNTERS];
|
struct retro_perf_counter *perf_counters_rarch[MAX_COUNTERS];
|
||||||
|
|
||||||
#ifdef HAVE_NETWORKING
|
|
||||||
struct netplay_room netplay_host_room; /* ptr alignment */
|
|
||||||
#endif
|
|
||||||
jmp_buf error_sjlj_context; /* 4-byte alignment,
|
jmp_buf error_sjlj_context; /* 4-byte alignment,
|
||||||
put it right before long */
|
put it right before long */
|
||||||
#if defined(HAVE_RUNAHEAD)
|
#if defined(HAVE_RUNAHEAD)
|
||||||
@ -426,22 +419,13 @@ struct rarch_state
|
|||||||
#if defined(HAVE_TRANSLATE)
|
#if defined(HAVE_TRANSLATE)
|
||||||
int ai_service_auto;
|
int ai_service_auto;
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_NETWORKING
|
|
||||||
int reannounce;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_THREAD_STORAGE
|
#ifdef HAVE_THREAD_STORAGE
|
||||||
sthread_tls_t rarch_tls; /* unsigned alignment */
|
sthread_tls_t rarch_tls; /* unsigned alignment */
|
||||||
#endif
|
|
||||||
#ifdef HAVE_NETWORKING
|
|
||||||
unsigned server_port_deferred;
|
|
||||||
#endif
|
#endif
|
||||||
unsigned perf_ptr_rarch;
|
unsigned perf_ptr_rarch;
|
||||||
|
|
||||||
char error_string[255];
|
char error_string[255];
|
||||||
#ifdef HAVE_NETWORKING
|
|
||||||
char server_address_deferred[512];
|
|
||||||
#endif
|
|
||||||
char launch_arguments[4096];
|
char launch_arguments[4096];
|
||||||
char path_default_shader_preset[PATH_MAX_LENGTH];
|
char path_default_shader_preset[PATH_MAX_LENGTH];
|
||||||
char path_content[PATH_MAX_LENGTH];
|
char path_content[PATH_MAX_LENGTH];
|
||||||
@ -452,16 +436,6 @@ struct rarch_state
|
|||||||
char dir_system[PATH_MAX_LENGTH];
|
char dir_system[PATH_MAX_LENGTH];
|
||||||
char dir_savefile[PATH_MAX_LENGTH];
|
char dir_savefile[PATH_MAX_LENGTH];
|
||||||
char dir_savestate[PATH_MAX_LENGTH];
|
char dir_savestate[PATH_MAX_LENGTH];
|
||||||
|
|
||||||
#ifdef HAVE_NETWORKING
|
|
||||||
/* Only used before init_netplay */
|
|
||||||
bool netplay_enabled;
|
|
||||||
bool netplay_is_client;
|
|
||||||
/* Used to avoid recursive netplay calls */
|
|
||||||
bool in_netplay;
|
|
||||||
bool netplay_client_deferred;
|
|
||||||
bool is_mitm;
|
|
||||||
#endif
|
|
||||||
bool has_set_username;
|
bool has_set_username;
|
||||||
bool rarch_error_on_init;
|
bool rarch_error_on_init;
|
||||||
bool has_set_verbosity;
|
bool has_set_verbosity;
|
||||||
@ -494,14 +468,6 @@ struct rarch_state
|
|||||||
bool wifi_driver_active;
|
bool wifi_driver_active;
|
||||||
bool camera_driver_active;
|
bool camera_driver_active;
|
||||||
|
|
||||||
#if defined(HAVE_NETWORKING)
|
|
||||||
bool has_set_netplay_mode;
|
|
||||||
bool has_set_netplay_ip_address;
|
|
||||||
bool has_set_netplay_ip_port;
|
|
||||||
bool has_set_netplay_stateless_mode;
|
|
||||||
bool has_set_netplay_check_frames;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool streaming_enable;
|
bool streaming_enable;
|
||||||
bool main_ui_companion_is_on_foreground;
|
bool main_ui_companion_is_on_foreground;
|
||||||
};
|
};
|
||||||
|
@ -29,10 +29,6 @@ static bool is_narrator_running(struct rarch_state *p_rarch, bool accessibility_
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_NETWORKING
|
|
||||||
static void deinit_netplay(void);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void retroarch_deinit_drivers(struct rarch_state *p_rarch,
|
static void retroarch_deinit_drivers(struct rarch_state *p_rarch,
|
||||||
struct retro_callbacks *cbs);
|
struct retro_callbacks *cbs);
|
||||||
|
|
||||||
@ -92,6 +88,4 @@ static const void *find_driver_nonempty(
|
|||||||
const char *label, int i,
|
const char *label, int i,
|
||||||
char *s, size_t len);
|
char *s, size_t len);
|
||||||
|
|
||||||
static bool core_set_default_callbacks(struct retro_callbacks *cbs);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user