mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-23 07:59:42 +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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
#endif
|
||||
|
@ -85,6 +85,8 @@ bool discord_avatar_is_ready(void);
|
||||
|
||||
char* discord_get_own_avatar(void);
|
||||
|
||||
char *discord_get_own_username(void);
|
||||
|
||||
discord_state_t *discord_state_get_ptr(void);
|
||||
|
||||
void discord_init(const char *discord_app_id, char *args);
|
||||
|
@ -26,21 +26,6 @@
|
||||
|
||||
#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
|
||||
{
|
||||
RARCH_NETPLAY_CTL_NONE = 0,
|
||||
@ -86,6 +71,69 @@ enum rarch_netplay_share_analog_preference
|
||||
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);
|
||||
|
||||
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 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
|
||||
|
@ -54,31 +54,6 @@ enum netplay_host_method
|
||||
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
|
||||
enum rarch_netplay_discovery_ctl_state
|
||||
{
|
||||
|
@ -25,10 +25,12 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include <retro_assert.h>
|
||||
|
||||
#include <compat/strl.h>
|
||||
#include <net/net_compat.h>
|
||||
#include <net/net_socket.h>
|
||||
#include <net/net_http.h>
|
||||
#include <encodings/crc32.h>
|
||||
#include <lrc_hash.h>
|
||||
#include <retro_timers.h>
|
||||
@ -36,6 +38,10 @@
|
||||
#include <string/stdstring.h>
|
||||
#include <file/file_path.h>
|
||||
|
||||
#ifdef HAVE_DISCORD
|
||||
#include "../discord.h"
|
||||
#endif
|
||||
|
||||
#include "../../file_path_special.h"
|
||||
#include "../../paths.h"
|
||||
#include "../../content.h"
|
||||
@ -205,6 +211,13 @@ static int16_t htons_for_morons(int16_t value)
|
||||
|
||||
#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)
|
||||
{
|
||||
unsigned i;
|
||||
@ -6728,5 +6741,711 @@ void netplay_post_frame(netplay_t *netplay)
|
||||
false))
|
||||
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 <compat/strl.h>
|
||||
#include <formats/rjson.h>
|
||||
#include "netplay.h"
|
||||
#include "netplay_discovery.h"
|
||||
#include "../../verbosity.h"
|
||||
|
||||
|
790
retroarch.c
790
retroarch.c
@ -1249,7 +1249,7 @@ bool discord_is_ready(void)
|
||||
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;
|
||||
if (discord_st->ready)
|
||||
@ -1570,7 +1570,7 @@ void discord_update(enum discord_presence presence)
|
||||
{
|
||||
char join_secret[128];
|
||||
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;
|
||||
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;
|
||||
@ -1691,728 +1691,6 @@ void discord_init(const char *discord_app_id, char *args)
|
||||
}
|
||||
#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(
|
||||
struct retro_perf_counter **counters, unsigned num)
|
||||
{
|
||||
@ -7613,6 +6891,10 @@ void retroarch_override_setting_set(
|
||||
enum rarch_override_setting enum_idx, void *data)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -7644,19 +6926,19 @@ void retroarch_override_setting_set(
|
||||
break;
|
||||
#ifdef HAVE_NETWORKING
|
||||
case RARCH_OVERRIDE_SETTING_NETPLAY_MODE:
|
||||
p_rarch->has_set_netplay_mode = true;
|
||||
net_st->has_set_netplay_mode = true;
|
||||
break;
|
||||
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS:
|
||||
p_rarch->has_set_netplay_ip_address = true;
|
||||
net_st->has_set_netplay_ip_address = true;
|
||||
break;
|
||||
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT:
|
||||
p_rarch->has_set_netplay_ip_port = true;
|
||||
net_st->has_set_netplay_ip_port = true;
|
||||
break;
|
||||
case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE:
|
||||
p_rarch->has_set_netplay_stateless_mode = true;
|
||||
net_st->has_set_netplay_stateless_mode = true;
|
||||
break;
|
||||
case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES:
|
||||
p_rarch->has_set_netplay_check_frames = true;
|
||||
net_st->has_set_netplay_check_frames = true;
|
||||
break;
|
||||
#endif
|
||||
case RARCH_OVERRIDE_SETTING_UPS_PREF:
|
||||
@ -7686,7 +6968,11 @@ void retroarch_override_setting_set(
|
||||
void retroarch_override_setting_unset(
|
||||
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)
|
||||
{
|
||||
@ -7718,19 +7004,19 @@ void retroarch_override_setting_unset(
|
||||
break;
|
||||
#ifdef HAVE_NETWORKING
|
||||
case RARCH_OVERRIDE_SETTING_NETPLAY_MODE:
|
||||
p_rarch->has_set_netplay_mode = false;
|
||||
net_st->has_set_netplay_mode = false;
|
||||
break;
|
||||
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS:
|
||||
p_rarch->has_set_netplay_ip_address = false;
|
||||
net_st->has_set_netplay_ip_address = false;
|
||||
break;
|
||||
case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT:
|
||||
p_rarch->has_set_netplay_ip_port = false;
|
||||
net_st->has_set_netplay_ip_port = false;
|
||||
break;
|
||||
case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE:
|
||||
p_rarch->has_set_netplay_stateless_mode = false;
|
||||
net_st->has_set_netplay_stateless_mode = false;
|
||||
break;
|
||||
case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES:
|
||||
p_rarch->has_set_netplay_check_frames = false;
|
||||
net_st->has_set_netplay_check_frames = false;
|
||||
break;
|
||||
#endif
|
||||
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(
|
||||
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)
|
||||
{
|
||||
@ -16345,15 +15634,15 @@ bool retroarch_override_setting_is_set(
|
||||
return p_rarch->has_set_state_path;
|
||||
#ifdef HAVE_NETWORKING
|
||||
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:
|
||||
return p_rarch->has_set_netplay_ip_address;
|
||||
return net_st->has_set_netplay_ip_address;
|
||||
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:
|
||||
return p_rarch->has_set_netplay_stateless_mode;
|
||||
return net_st->has_set_netplay_stateless_mode;
|
||||
case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES:
|
||||
return p_rarch->has_set_netplay_check_frames;
|
||||
return net_st->has_set_netplay_check_frames;
|
||||
#endif
|
||||
#ifdef HAVE_PATCH
|
||||
case RARCH_OVERRIDE_SETTING_UPS_PREF:
|
||||
@ -18416,21 +17705,16 @@ static bool core_init_libretro_cbs(struct retro_callbacks *cbs)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
bool core_set_default_callbacks(void *data)
|
||||
{
|
||||
struct retro_callbacks *cbs = (struct retro_callbacks*)data;
|
||||
retro_input_state_t state_cb = core_input_state_poll_return_cb();
|
||||
|
||||
cbs->frame_cb = video_driver_frame;
|
||||
cbs->sample_cb = audio_driver_sample;
|
||||
cbs->sample_batch_cb = audio_driver_sample_batch;
|
||||
cbs->state_cb = state_cb;
|
||||
cbs->poll_cb = input_driver_poll;
|
||||
cbs->frame_cb = video_driver_frame;
|
||||
cbs->sample_cb = audio_driver_sample;
|
||||
cbs->sample_batch_cb = audio_driver_sample_batch;
|
||||
cbs->state_cb = state_cb;
|
||||
cbs->poll_cb = input_driver_poll;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -405,16 +405,9 @@ struct rarch_state
|
||||
const wifi_driver_t *wifi_driver;
|
||||
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];
|
||||
|
||||
#ifdef HAVE_NETWORKING
|
||||
struct netplay_room netplay_host_room; /* ptr alignment */
|
||||
#endif
|
||||
jmp_buf error_sjlj_context; /* 4-byte alignment,
|
||||
put it right before long */
|
||||
#if defined(HAVE_RUNAHEAD)
|
||||
@ -426,22 +419,13 @@ struct rarch_state
|
||||
#if defined(HAVE_TRANSLATE)
|
||||
int ai_service_auto;
|
||||
#endif
|
||||
#ifdef HAVE_NETWORKING
|
||||
int reannounce;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_THREAD_STORAGE
|
||||
sthread_tls_t rarch_tls; /* unsigned alignment */
|
||||
#endif
|
||||
#ifdef HAVE_NETWORKING
|
||||
unsigned server_port_deferred;
|
||||
#endif
|
||||
unsigned perf_ptr_rarch;
|
||||
|
||||
char error_string[255];
|
||||
#ifdef HAVE_NETWORKING
|
||||
char server_address_deferred[512];
|
||||
#endif
|
||||
char launch_arguments[4096];
|
||||
char path_default_shader_preset[PATH_MAX_LENGTH];
|
||||
char path_content[PATH_MAX_LENGTH];
|
||||
@ -452,16 +436,6 @@ struct rarch_state
|
||||
char dir_system[PATH_MAX_LENGTH];
|
||||
char dir_savefile[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 rarch_error_on_init;
|
||||
bool has_set_verbosity;
|
||||
@ -494,14 +468,6 @@ struct rarch_state
|
||||
bool wifi_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 main_ui_companion_is_on_foreground;
|
||||
};
|
||||
|
@ -29,10 +29,6 @@ static bool is_narrator_running(struct rarch_state *p_rarch, bool accessibility_
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETWORKING
|
||||
static void deinit_netplay(void);
|
||||
#endif
|
||||
|
||||
static void retroarch_deinit_drivers(struct rarch_state *p_rarch,
|
||||
struct retro_callbacks *cbs);
|
||||
|
||||
@ -92,6 +88,4 @@ static const void *find_driver_nonempty(
|
||||
const char *label, int i,
|
||||
char *s, size_t len);
|
||||
|
||||
static bool core_set_default_callbacks(struct retro_callbacks *cbs);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user