Merge pull request #14054 from Cthulhu-throwaway/netplay-refactor

(Netplay) Some refactoring and fixes
This commit is contained in:
LibretroAdmin 2022-06-18 03:28:47 +01:00 committed by GitHub
commit 838e5117d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 1352 additions and 1607 deletions

View File

@ -5959,113 +5959,109 @@ static int action_ok_wifi_disconnect(const char *path,
}
#endif
static int action_ok_netplay_connect_room(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
static int action_ok_netplay_connect_room(const char *path, const char *label,
unsigned type, size_t idx, size_t entry_idx)
{
char tmp_hostname[4115];
char hostname[512];
struct netplay_room *room;
net_driver_state_t *net_st = networking_state_get_ptr();
unsigned room_index = type - MENU_SETTINGS_NETPLAY_ROOMS_START;
if (room_index >= (unsigned)net_st->room_count)
return menu_cbs_exit();
tmp_hostname[0] = '\0';
room = &net_st->room_list[room_index];
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL))
generic_action_ok_command(CMD_EVENT_NETPLAY_DEINIT);
netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_CLIENT, NULL);
if (net_st->room_list[room_index].host_method == NETPLAY_HOST_METHOD_MITM)
snprintf(tmp_hostname,
sizeof(tmp_hostname),
"%s|%d|%s",
net_st->room_list[room_index].mitm_address,
net_st->room_list[room_index].mitm_port,
net_st->room_list[room_index].mitm_session);
if (room->host_method == NETPLAY_HOST_METHOD_MITM)
snprintf(hostname, sizeof(hostname), "%s|%d|%s",
room->mitm_address, room->mitm_port, room->mitm_session);
else
snprintf(tmp_hostname,
sizeof(tmp_hostname),
"%s|%d",
net_st->room_list[room_index].address,
net_st->room_list[room_index].port);
snprintf(hostname, sizeof(hostname), "%s|%d", room->address, room->port);
#if 0
RARCH_LOG("[lobby] connecting to: %s with game: %s/%08x\n",
tmp_hostname,
net_st->room_list[room_index].gamename,
net_st->room_list[room_index].gamecrc);
RARCH_LOG("[Lobby] Connecting to: %s with game: %s/%08x\n",
hostname, room->gamename, room->gamecrc);
#endif
task_push_netplay_crc_scan(
net_st->room_list[room_index].gamecrc,
net_st->room_list[room_index].gamename,
tmp_hostname,
net_st->room_list[room_index].corename,
net_st->room_list[room_index].subsystem_name);
task_push_netplay_crc_scan(room->gamecrc, room->gamename, hostname,
room->corename, room->subsystem_name);
return 0;
}
static void netplay_refresh_rooms_cb(retro_task_t *task,
void *task_data, void *user_data, const char *error)
static void netplay_refresh_rooms_cb(retro_task_t *task, void *task_data,
void *user_data, const char *error)
{
char *new_data = NULL;
char *room_data = NULL;
const char *path = NULL;
const char *label = NULL;
unsigned menu_type = 0;
enum msg_hash_enums enum_idx = MSG_UNKNOWN;
net_driver_state_t *net_st = networking_state_get_ptr();
http_transfer_data_t *data = (http_transfer_data_t*)task_data;
bool refresh = false;
http_transfer_data_t *data = (http_transfer_data_t*)task_data;
net_driver_state_t *net_st = networking_state_get_ptr();
free(net_st->room_list);
net_st->room_list = NULL;
net_st->room_count = 0;
menu_entries_get_last_stack(&path, &label, &menu_type, &enum_idx, NULL);
/* Don't push the results if we left the netplay menu */
if (!string_is_equal(label,
msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY_TAB)) &&
!string_is_equal(label,
msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY)))
if (!string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY_TAB)) &&
!string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY)))
return;
if (error)
{
RARCH_ERR("%s: %s\n", msg_hash_to_str(MSG_DOWNLOAD_FAILED),
error);
return;
RARCH_ERR("%s: %s\n", msg_hash_to_str(MSG_DOWNLOAD_FAILED), error);
goto done;
}
if (!data || !data->data || !data->len || data->status != 200)
{
RARCH_ERR("%s\n", msg_hash_to_str(MSG_DOWNLOAD_FAILED));
return;
goto done;
}
new_data = (char*)realloc(data->data, data->len + 1);
if (!new_data)
return;
data->data = new_data;
data->data[data->len] = '\0';
room_data = (char*)malloc(data->len + 1);
if (!room_data)
goto done;
memcpy(room_data, data->data, data->len);
room_data[data->len] = '\0';
if (net_st->room_list)
free(net_st->room_list);
net_st->room_list = NULL;
net_st->room_count = 0;
if (!string_is_empty(data->data))
if (!string_is_empty(room_data))
{
int i;
int room_count;
netplay_rooms_parse(data->data);
netplay_rooms_parse(room_data);
net_st->room_count = netplay_rooms_get_count();
net_st->room_list = (struct netplay_room*)calloc(net_st->room_count,
sizeof(*net_st->room_list));
for (i = 0; i < net_st->room_count; i++)
memcpy(&net_st->room_list[i], netplay_room_get(i),
room_count = netplay_rooms_get_count();
if (room_count > 0)
{
net_st->room_list = (struct netplay_room*)calloc(room_count,
sizeof(*net_st->room_list));
if (net_st->room_list)
{
int i;
net_st->room_count = room_count;
for (i = 0; i < room_count; i++)
memcpy(&net_st->room_list[i], netplay_room_get(i),
sizeof(*net_st->room_list));
}
}
netplay_rooms_free();
}
free(room_data);
done:
menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
}
@ -6073,92 +6069,81 @@ static void netplay_refresh_rooms_cb(retro_task_t *task,
static int action_ok_push_netplay_refresh_rooms(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
#ifndef NETPLAY_TEST_BUILD
const char *url = "http://lobby.libretro.com/list";
#else
const char *url = "http://lobbytest.libretro.com/list";
#endif
task_push_http_transfer(url, true, NULL, netplay_refresh_rooms_cb, NULL);
task_push_http_transfer(FILE_PATH_LOBBY_LIBRETRO_URL "list", true, NULL,
netplay_refresh_rooms_cb, NULL);
return 0;
}
#ifdef HAVE_NETPLAYDISCOVERY
static void netplay_refresh_lan_cb(retro_task_t *task,
void *task_data, void *user_data, const char *error)
static void netplay_refresh_lan_cb(retro_task_t *task, void *task_data,
void *user_data, const char *error)
{
int i;
const char *path = NULL;
const char *label = NULL;
unsigned menu_type = 0;
enum msg_hash_enums enum_idx = MSG_UNKNOWN;
net_driver_state_t *net_st = networking_state_get_ptr();
struct netplay_host_list *hosts = NULL;
bool refresh = false;
net_driver_state_t *net_st = networking_state_get_ptr();
free(net_st->room_list);
net_st->room_list = NULL;
net_st->room_count = 0;
menu_entries_get_last_stack(&path, &label, &menu_type, &enum_idx, NULL);
/* Don't push the results if we left the netplay menu */
if (!string_is_equal(label,
msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY_TAB)) &&
!string_is_equal(label,
msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY)))
goto finished;
if (!string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY_TAB)) &&
!string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY)))
goto deinit;
if (!netplay_discovery_driver_ctl(
RARCH_NETPLAY_DISCOVERY_CTL_LAN_GET_RESPONSES, &hosts) ||
!hosts)
goto finished;
RARCH_NETPLAY_DISCOVERY_CTL_LAN_GET_RESPONSES, &hosts))
goto done;
if (!hosts || !hosts->size)
goto done;
if (net_st->room_list)
free(net_st->room_list);
net_st->room_list =
(struct netplay_room*)calloc(hosts->size, sizeof(*net_st->room_list));
if (!net_st->room_list)
goto done;
net_st->room_count = hosts->size;
net_st->room_list = NULL;
net_st->room_count = 0;
if (hosts->size)
for (i = 0; i < net_st->room_count; i++)
{
int i;
struct netplay_host *host = &hosts->hosts[i];
struct netplay_room *room = &net_st->room_list[i];
net_st->room_count = hosts->size;
net_st->room_list = (struct netplay_room*)calloc(net_st->room_count,
sizeof(*net_st->room_list));
room->gamecrc = host->content_crc;
room->port = host->port;
for (i = 0; i < net_st->room_count; i++)
{
struct netplay_host *host = &hosts->hosts[i];
struct netplay_room *room = &net_st->room_list[i];
strlcpy(room->nickname, host->nick, sizeof(room->nickname));
strlcpy(room->frontend, host->frontend, sizeof(room->frontend));
strlcpy(room->corename, host->core, sizeof(room->corename));
strlcpy(room->coreversion, host->core_version,
sizeof(room->coreversion));
strlcpy(room->retroarch_version, host->retroarch_version,
sizeof(room->retroarch_version));
strlcpy(room->gamename, host->content, sizeof(room->gamename));
strlcpy(room->subsystem_name, host->subsystem_name,
sizeof(room->subsystem_name));
strlcpy(room->address, host->address, sizeof(room->address));
room->port = host->port;
room->gamecrc = host->content_crc;
strlcpy(room->retroarch_version, host->retroarch_version,
sizeof(room->retroarch_version));
strlcpy(room->nickname, host->nick,
sizeof(room->nickname));
strlcpy(room->subsystem_name, host->subsystem_name,
sizeof(room->subsystem_name));
strlcpy(room->corename, host->core,
sizeof(room->corename));
strlcpy(room->frontend, host->frontend,
sizeof(room->frontend));
strlcpy(room->coreversion, host->core_version,
sizeof(room->coreversion));
strlcpy(room->gamename, host->content,
sizeof(room->gamename));
strlcpy(room->address, host->address,
sizeof(room->address));
room->has_password = host->has_password;
room->has_spectate_password = host->has_spectate_password;
room->connectable = true;
room->is_retroarch = true;
room->lan = true;
}
room->has_password = host->has_password;
room->has_spectate_password = host->has_spectate_password;
room->connectable = true;
room->is_retroarch = true;
room->lan = true;
}
done:
menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
finished:
deinit:
deinit_netplay_discovery();
}

View File

@ -1494,93 +1494,48 @@ static int action_bind_sublabel_cheat_desc(
#endif
#ifdef HAVE_NETWORKING
static int action_bind_sublabel_netplay_room(
file_list_t *list,
static int action_bind_sublabel_netplay_room(file_list_t *list,
unsigned type, unsigned i,
const char *label, const char *path,
char *s, size_t len)
{
uint32_t gamecrc = 0;
const char *ra_version = NULL;
const char *corename = NULL;
const char *gamename = NULL;
const char *core_ver = NULL;
const char *frontend = NULL;
const char *na = NULL;
const char *subsystem = NULL;
char buf[512];
struct netplay_room *room;
net_driver_state_t *net_st = networking_state_get_ptr();
unsigned room_index = type - MENU_SETTINGS_NETPLAY_ROOMS_START;
if (room_index >= (unsigned)net_st->room_count)
return menu_cbs_exit();
ra_version = net_st->room_list[room_index].retroarch_version;
corename = net_st->room_list[room_index].corename;
gamename = net_st->room_list[room_index].gamename;
core_ver = net_st->room_list[room_index].coreversion;
gamecrc = net_st->room_list[room_index].gamecrc;
frontend = net_st->room_list[room_index].frontend;
subsystem = net_st->room_list[room_index].subsystem_name;
na = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE);
room = &net_st->room_list[room_index];
if (string_is_empty(subsystem) || string_is_equal(subsystem,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE)))
{
snprintf(s, len,
"%s: %s (%s)\n%s: %s (%s)\nGame: %s (%08lx)",
msg_hash_to_str(MSG_PROGRAM),
string_is_empty(ra_version) ? na : ra_version,
string_is_empty(frontend) ? na : frontend,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONTENT_INFO_CORE_NAME),
corename, core_ver,
!string_is_equal(gamename, na) ? gamename : na,
(unsigned long)gamecrc);
}
snprintf(s, len,
"%s: %s (%s)\n"
"%s: %s (%s)\n"
"%s: %s ",
msg_hash_to_str(MSG_PROGRAM),
!string_is_empty(room->retroarch_version) ? room->retroarch_version :
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE),
(!string_is_empty(room->frontend) &&
!string_is_equal_case_insensitive(room->frontend, "N/A")) ?
room->frontend :
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONTENT_INFO_CORE_NAME),
room->corename, room->coreversion,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONTENT),
(!string_is_empty(room->gamename) &&
!string_is_equal_case_insensitive(room->gamename, "N/A")) ?
room->gamename :
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE));
if (string_is_empty(room->subsystem_name) ||
string_is_equal_case_insensitive(room->subsystem_name, "N/A"))
snprintf(buf, sizeof(buf), "(%08lX)", (unsigned long)room->gamecrc);
else
{
if (strstr(gamename, "|"))
{
char buf[4096];
unsigned i = 0;
struct string_list list = {0};
snprintf(buf, sizeof(buf), "(%s)", room->subsystem_name);
string_list_initialize(&list);
string_split_noalloc(&list, gamename, "|");
strlcat(s, buf, len);
buf[0] = '\0';
for (i = 0; i < list.size; i++)
{
strlcat(buf, " ", sizeof(buf));
strlcat(buf, list.elems[i].data, sizeof(buf));
/* Never terminate a UI string with a newline */
if (i != list.size - 1)
strlcat(buf, "\n", sizeof(buf));
}
snprintf(s, len,
"%s: %s (%s)\n%s: %s (%s)\nSubsystem: %s\nGames:\n%s",
msg_hash_to_str(MSG_PROGRAM),
string_is_empty(ra_version) ? na : ra_version,
string_is_empty(frontend) ? na : frontend,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONTENT_INFO_CORE_NAME),
corename, core_ver, subsystem,
!string_is_equal(gamename, na) ? buf : na
);
string_list_deinitialize(&list);
}
else
{
snprintf(s, len,
"%s: %s (%s)\n%s: %s (%s)\nSubsystem: %s\nGame: %s (%08lx)",
msg_hash_to_str(MSG_PROGRAM),
string_is_empty(ra_version) ? na : ra_version,
string_is_empty(frontend) ? na : frontend,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONTENT_INFO_CORE_NAME),
corename, core_ver, subsystem,
!string_is_equal(gamename, na) ? gamename : na,
(unsigned long)gamecrc);
}
}
return 0;
}
@ -1590,10 +1545,10 @@ static int action_bind_sublabel_netplay_kick_client(file_list_t *list,
char *s, size_t len)
{
char buf[256];
netplay_client_info_t *client = NULL;
const char *status = NULL;
size_t idx = list->list[i].entry_idx;
net_driver_state_t *net_st = networking_state_get_ptr();
netplay_client_info_t *client;
const char *status = NULL;
size_t idx = list->list[i].entry_idx;
net_driver_state_t *net_st = networking_state_get_ptr();
if (idx >= net_st->client_info_count)
return menu_cbs_exit();
@ -1625,20 +1580,17 @@ static int action_bind_sublabel_netplay_kick_client(file_list_t *list,
snprintf(buf, sizeof(buf), "%s: %s",
msg_hash_to_str(MSG_NETPLAY_CHAT_SUPPORTED),
msg_hash_to_str((client->protocol >= 6) ?
MENU_ENUM_LABEL_VALUE_YES :
MENU_ENUM_LABEL_VALUE_NO));
MENU_ENUM_LABEL_VALUE_YES : MENU_ENUM_LABEL_VALUE_NO));
strlcat(s, buf, len);
if (client->ping >= 0)
{
snprintf(buf, sizeof(buf), "\nPing: %u",
(unsigned)client->ping);
snprintf(buf, sizeof(buf), "\nPing: %u", (unsigned)client->ping);
strlcat(s, buf, len);
}
return 0;
}
#endif
static int action_bind_sublabel_playlist_entry(

View File

@ -10386,9 +10386,16 @@ static unsigned menu_displaylist_build_shader_parameter(
unsigned menu_displaylist_netplay_refresh_rooms(file_list_t *list)
{
int i;
char buf[256];
char passworded[64];
char country[8];
const char *room_type;
struct netplay_room *room;
unsigned count = 0;
settings_t *settings = config_get_ptr();
net_driver_state_t *net_st = networking_state_get_ptr();
bool show_only_connectable = settings->bools.netplay_show_only_connectable;
bool show_passworded = settings->bools.netplay_show_passworded;
menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, list);
@ -10400,8 +10407,8 @@ unsigned menu_displaylist_netplay_refresh_rooms(file_list_t *list)
count++;
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL) &&
!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_SERVER, NULL) &&
netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_CONNECTED, NULL))
!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_SERVER, NULL) &&
netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_CONNECTED, NULL))
{
if (menu_entries_append_enum(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_DISCONNECT),
@ -10412,10 +10419,10 @@ unsigned menu_displaylist_netplay_refresh_rooms(file_list_t *list)
}
if (menu_entries_append_enum(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_CLIENT),
msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY_ENABLE_CLIENT),
MENU_ENUM_LABEL_NETPLAY_ENABLE_CLIENT,
MENU_SETTING_ACTION, 0, 0))
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_CLIENT),
msg_hash_to_str(MENU_ENUM_LABEL_NETPLAY_ENABLE_CLIENT),
MENU_ENUM_LABEL_NETPLAY_ENABLE_CLIENT,
MENU_SETTING_ACTION, 0, 0))
count++;
if (menu_entries_append_enum(list,
@ -10450,11 +10457,7 @@ unsigned menu_displaylist_netplay_refresh_rooms(file_list_t *list)
for (i = 0; i < net_st->room_count; i++)
{
char buf[8192];
char passworded[64];
char country[8];
const char *room_type;
struct netplay_room *room = &net_st->room_list[i];
room = &net_st->room_list[i];
/* Get rid of any room that is not running RetroArch. */
if (!room->is_retroarch)
@ -10464,7 +10467,7 @@ unsigned menu_displaylist_netplay_refresh_rooms(file_list_t *list)
if the user opt-in. */
if (!room->connectable)
{
if (settings->bools.netplay_show_only_connectable)
if (show_only_connectable)
continue;
room_type = msg_hash_to_str(MSG_INTERNET_NOT_CONNECTABLE);
@ -10480,7 +10483,7 @@ unsigned menu_displaylist_netplay_refresh_rooms(file_list_t *list)
if the user opt-in. */
if (room->has_password || room->has_spectate_password)
{
if (!settings->bools.netplay_show_passworded)
if (!show_passworded)
continue;
snprintf(passworded, sizeof(passworded), "[%s] ",
@ -10490,46 +10493,20 @@ unsigned menu_displaylist_netplay_refresh_rooms(file_list_t *list)
*passworded = '\0';
if (!room->lan && !string_is_empty(room->country))
snprintf(country, sizeof(country), " (%s)",
room->country);
snprintf(country, sizeof(country), " (%s)", room->country);
else
*country = '\0';
snprintf(buf, sizeof(buf), "%s%s: %s%s",
passworded, room_type,
room->nickname, country);
passworded, room_type, room->nickname, country);
if (menu_entries_append_enum(list,
buf,
if (menu_entries_append_enum(list, buf,
msg_hash_to_str(MENU_ENUM_LABEL_CONNECT_NETPLAY_ROOM),
MENU_ENUM_LABEL_CONNECT_NETPLAY_ROOM,
(unsigned)(MENU_SETTINGS_NETPLAY_ROOMS_START + i), 0, 0))
(unsigned)MENU_SETTINGS_NETPLAY_ROOMS_START + i, 0, 0))
count++;
/* Uncomment this to debug mismatched room parameters*/
#if 0
RARCH_LOG("[Lobby]: Room Data: %d\n"
"Nickname: %s\n"
"Address: %s\n"
"Port: %d\n"
"Core: %s\n"
"Core Version: %s\n"
"Game: %s\n"
"Game CRC: %08x\n"
"Timestamp: %d\n", room_data->elems[j + 6].data,
room->nickname,
room->address,
room->port,
room->corename,
room->coreversion,
room->gamename,
room->gamecrc,
room->timestamp);
#endif
}
netplay_rooms_free();
return count;
}
@ -10637,13 +10614,14 @@ static unsigned menu_displaylist_netplay_kick(file_list_t *list)
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_REFRESH_CLIENT_INFO, NULL))
{
char client_id[4];
size_t i;
char client_id[4];
netplay_client_info_t *client;
net_driver_state_t *net_st = networking_state_get_ptr();
for (i = 0; i < net_st->client_info_count; i++)
{
netplay_client_info_t *client = &net_st->client_info[i];
client = &net_st->client_info[i];
snprintf(client_id, sizeof(client_id), "%d", client->id);
if (menu_entries_append_enum(list, client->name, client_id,
@ -10664,7 +10642,6 @@ static unsigned menu_displaylist_netplay_kick(file_list_t *list)
return count;
}
#endif
bool menu_displaylist_has_subsystems(void)

View File

@ -53,7 +53,7 @@ extern "C"
}
#endif
static discord_state_t discord_state_st; /* int64_t alignment */
static discord_state_t discord_state_st = {0}; /* int64_t alignment */
discord_state_t *discord_state_get_ptr(void)
{
@ -153,99 +153,113 @@ static void handle_discord_error(int errcode, const char* message)
{
}
static void handle_discord_join_cb(retro_task_t *task,
void *task_data, void *user_data, const char *err)
static void handle_discord_join_cb(retro_task_t *task, void *task_data,
void *user_data, const char *error)
{
char join_hostname[PATH_MAX_LENGTH];
struct netplay_room *room = NULL;
http_transfer_data_t *data = (http_transfer_data_t*)task_data;
discord_state_t *discord_st = &discord_state_st;
char hostname[512];
struct netplay_room *room;
char *room_data = NULL;
http_transfer_data_t *data = (http_transfer_data_t*)task_data;
discord_state_t *discord_st = &discord_state_st;
if (!data || err || !data->data || !data->len)
goto finish;
if (error)
goto done;
if (!data || !data->data || !data->len)
goto done;
if (data->status != 200)
goto done;
data->data = (char*)realloc(data->data, data->len + 1);
data->data[data->len] = '\0';
room_data = (char*)malloc(data->len + 1);
if (!room_data)
goto done;
memcpy(room_data, data->data, data->len);
room_data[data->len] = '\0';
netplay_rooms_parse(data->data);
room = netplay_room_get(0);
netplay_rooms_parse(room_data);
free(room_data);
room = netplay_room_get(0);
if (room)
{
if (room->host_method == NETPLAY_HOST_METHOD_MITM)
snprintf(join_hostname, sizeof(join_hostname), "%s|%d|%s",
room->mitm_address, room->mitm_port, room->mitm_session);
else
snprintf(join_hostname, sizeof(join_hostname), "%s|%d",
room->address, room->port);
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL))
deinit_netplay();
netplay_driver_ctl(RARCH_NETPLAY_CTL_ENABLE_CLIENT, NULL);
task_push_netplay_crc_scan(room->gamecrc,
room->gamename, join_hostname, room->corename, room->subsystem_name);
if (room->host_method == NETPLAY_HOST_METHOD_MITM)
snprintf(hostname, sizeof(hostname), "%s|%d|%s",
room->mitm_address, room->mitm_port, room->mitm_session);
else
snprintf(hostname, sizeof(hostname), "%s|%d",
room->address, room->port);
task_push_netplay_crc_scan(room->gamecrc, room->gamename, hostname,
room->corename, room->subsystem_name);
discord_st->connecting = true;
if (discord_st->ready)
discord_update(PRESENCE_NETPLAY_CLIENT);
}
finish:
if (user_data)
free(user_data);
netplay_rooms_free();
done:
free(user_data);
}
static void handle_discord_join(const char* secret)
static void handle_discord_join(const char *secret)
{
char url[2048];
struct string_list *list = string_split(secret, "|");
char url[512];
discord_state_t *discord_st = &discord_state_st;
int room_id = (int)strtol(secret, NULL, 10);
strlcpy(discord_st->peer_party_id,
list->elems[0].data, sizeof(discord_st->peer_party_id));
snprintf(url, sizeof(url), FILE_PATH_LOBBY_LIBRETRO_URL "%s/",
discord_st->peer_party_id);
if (room_id)
{
snprintf(discord_st->peer_party_id, sizeof(discord_st->peer_party_id),
"%d", room_id);
task_push_http_transfer(url, true, NULL, handle_discord_join_cb, NULL);
strlcpy(url, FILE_PATH_LOBBY_LIBRETRO_URL, sizeof(url));
strlcat(url, discord_st->peer_party_id, sizeof(url));
task_push_http_transfer(url, true, NULL, handle_discord_join_cb, NULL);
}
}
static void handle_discord_spectate(const char* secret)
static void handle_discord_spectate(const char *secret)
{
}
#ifdef HAVE_MENU
#if 0
#ifdef HAVE_MENU
static void handle_discord_join_response(void *ignore, const char *line)
{
/* TODO/FIXME: needs in-game widgets */
if (strstr(line, "yes"))
Discord_Respond(user_id, DISCORD_REPLY_YES);
#ifdef HAVE_MENU
menu_input_dialog_end();
retroarch_menu_running_finished(false);
#endif
}
#endif
#endif
static void handle_discord_join_request(const DiscordUser* request)
static void handle_discord_join_request(const DiscordUser *request)
{
#ifdef HAVE_MENU
#if 0
char buf[PATH_MAX_LENGTH];
menu_input_ctx_line_t line;
menu_input_ctx_line_t line = {0};
#endif
discord_state_t *discord_st = &discord_state_st;
discord_download_avatar(discord_st, request->userId, request->avatar);
#if 0
/* TODO/FIXME: Needs in-game widgets */
retroarch_menu_running();
memset(&line, 0, sizeof(line));
snprintf(buf, sizeof(buf), "%s %s?",
msg_hash_to_str(MSG_DISCORD_CONNECTION_REQUEST), request->username);
msg_hash_to_str(MSG_DISCORD_CONNECTION_REQUEST), request->username);
line.label = buf;
line.label_setting = "no_setting";
line.cb = handle_discord_join_response;

View File

@ -23,8 +23,6 @@
#include <stddef.h>
#include <boolean.h>
#include <libretro.h>
#include <retro_miscellaneous.h>
#ifdef HAVE_CONFIG_H
#include "../../config.h"
@ -32,16 +30,14 @@
#include <net/net_compat.h>
#include "../../retroarch_types.h"
#include "../natt.h"
#include "netplay_protocol.h"
#define NETPLAY_NICK_LEN 32
#define NETPLAY_HOST_STR_LEN 32
#define NETPLAY_HOST_LONGSTR_LEN 256
#define NETPLAY_MITM_SERVERS 5
#define NETPLAY_CHAT_MAX_MESSAGES 5
#define NETPLAY_CHAT_MAX_SIZE 96
#define NETPLAY_CHAT_FRAME_TIME 900
@ -132,10 +128,10 @@ enum netplay_host_method
enum rarch_netplay_discovery_ctl_state
{
RARCH_NETPLAY_DISCOVERY_CTL_NONE = 0,
RARCH_NETPLAY_DISCOVERY_CTL_LAN_SEND_QUERY,
RARCH_NETPLAY_DISCOVERY_CTL_LAN_GET_RESPONSES,
RARCH_NETPLAY_DISCOVERY_CTL_LAN_CLEAR_RESPONSES
RARCH_NETPLAY_DISCOVERY_CTL_NONE = 0,
RARCH_NETPLAY_DISCOVERY_CTL_LAN_SEND_QUERY,
RARCH_NETPLAY_DISCOVERY_CTL_LAN_GET_RESPONSES,
RARCH_NETPLAY_DISCOVERY_CTL_LAN_CLEAR_RESPONSES
};
typedef struct netplay netplay_t;
@ -143,62 +139,38 @@ typedef struct netplay netplay_t;
typedef struct netplay_client_info
{
uint32_t protocol;
int32_t ping;
int id;
enum rarch_netplay_connection_mode mode;
char name[NETPLAY_NICK_LEN];
int32_t ping;
int id;
enum rarch_netplay_connection_mode mode;
char name[NETPLAY_NICK_LEN];
} netplay_client_info_t;
struct ad_packet
{
uint32_t header;
int32_t content_crc;
int32_t port;
uint32_t has_password;
char nick[NETPLAY_NICK_LEN];
char frontend[NETPLAY_HOST_STR_LEN];
char core[NETPLAY_HOST_STR_LEN];
char core_version[NETPLAY_HOST_STR_LEN];
char retroarch_version[NETPLAY_HOST_STR_LEN];
char content[NETPLAY_HOST_LONGSTR_LEN];
char subsystem_name[NETPLAY_HOST_LONGSTR_LEN];
};
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" },
{ "saopaulo", "Sao Paulo, Brazil" },
{ "singapore", "Singapore" },
{ "custom", "Custom" },
};
struct netplay_room
{
struct netplay_room *next;
int id;
int gamecrc;
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_handle [33];
char mitm_address [256];
char mitm_session [33];
char nickname[NETPLAY_NICK_LEN];
char frontend[NETPLAY_HOST_STR_LEN];
char corename[NETPLAY_HOST_STR_LEN];
char coreversion[NETPLAY_HOST_STR_LEN];
char retroarch_version[NETPLAY_HOST_STR_LEN];
char gamename[NETPLAY_HOST_LONGSTR_LEN];
char subsystem_name[NETPLAY_HOST_LONGSTR_LEN];
char country[3];
char address[NETPLAY_HOST_LONGSTR_LEN];
char mitm_handle[NETPLAY_HOST_STR_LEN];
char mitm_address[NETPLAY_HOST_LONGSTR_LEN];
char mitm_session[NETPLAY_HOST_STR_LEN];
bool has_password;
bool has_spectate_password;
bool connectable;
@ -216,7 +188,7 @@ struct netplay_host
{
int content_crc;
int port;
char address[NETPLAY_HOST_STR_LEN];
char address[16];
char nick[NETPLAY_NICK_LEN];
char frontend[NETPLAY_HOST_STR_LEN];
char core[NETPLAY_HOST_STR_LEN];
@ -231,27 +203,17 @@ struct netplay_host
struct netplay_host_list
{
struct netplay_host *hosts;
size_t allocated;
size_t size;
};
struct netplay_chat
{
struct
{
uint32_t frames;
char nick[NETPLAY_NICK_LEN];
char msg[NETPLAY_CHAT_MAX_SIZE];
} messages[NETPLAY_CHAT_MAX_MESSAGES];
uint32_t message_slots;
};
struct netplay_chat_buffer
{
struct
{
uint8_t alpha;
char nick[NETPLAY_NICK_LEN];
char msg[NETPLAY_CHAT_MAX_SIZE];
char nick[NETPLAY_NICK_LEN];
char msg[NETPLAY_CHAT_MAX_SIZE];
} messages[NETPLAY_CHAT_MAX_MESSAGES];
};
@ -260,8 +222,6 @@ typedef struct
/* NAT traversal info (if NAT traversal is used and serving) */
struct nat_traversal_data nat_traversal_request;
#ifdef HAVE_NETPLAYDISCOVERY
/* Packet buffer for advertisement and responses */
struct ad_packet ad_packet_buffer;
/* List of discovered hosts */
struct netplay_host_list discovered_hosts;
#endif
@ -272,21 +232,15 @@ typedef struct
/* Used while Netplay is running */
netplay_t *data;
netplay_client_info_t *client_info;
/* Chat messages */
struct netplay_chat *chat;
size_t client_info_count;
#ifdef HAVE_NETPLAYDISCOVERY
size_t discovered_hosts_allocated;
/* LAN discovery sockets */
int lan_ad_server_fd;
int lan_ad_client_fd;
#endif
int room_count;
int reannounce;
int reping;
int latest_ping;
unsigned server_port_deferred;
uint16_t mapping[RETROK_LAST];
char server_address_deferred[256];
char server_session_deferred[32];
bool netplay_client_deferred;
@ -302,101 +256,16 @@ typedef struct
net_driver_state_t *networking_state_get_ptr(void);
bool netplay_driver_ctl(enum rarch_netplay_ctl_state state, void *data);
bool netplay_decode_hostname(const char *hostname,
char *address, unsigned *port, char *session, size_t len);
bool netplay_is_lan_address(struct sockaddr_in *addr);
bool netplay_6to4(struct sockaddr_storage *addr);
int netplay_rooms_parse(const char *buf);
struct netplay_room* netplay_room_get(int index);
int netplay_rooms_get_count(void);
struct netplay_room *netplay_room_get(int index);
void netplay_rooms_free(void);
/**
* netplay_frontend_paused
* @netplay : pointer to netplay object
* @paused : true if frontend is paused
*
* Inform Netplay of the frontend's pause state (paused or otherwise)
*/
void netplay_frontend_paused(netplay_t *netplay, bool paused);
/**
* netplay_toggle_play_spectate
*
* Toggle between play mode and spectate mode
*/
void netplay_toggle_play_spectate(netplay_t *netplay);
/**
* netplay_input_chat
*
* Opens an input menu for sending netplay chat
*/
void netplay_input_chat(netplay_t *netplay);
/**
* netplay_load_savestate
* @netplay : pointer to netplay object
* @serial_info : the savestate being loaded, NULL means
* "load it yourself"
* @save : Whether to save the provided serial_info
* into the frame buffer
*
* Inform Netplay of a savestate load and send it to the other side
**/
void netplay_load_savestate(netplay_t *netplay,
retro_ctx_serialize_info_t *serial_info, bool save);
/**
* netplay_core_reset
* @netplay : pointer to netplay object
*
* Indicate that the core has been reset to netplay peers
**/
void netplay_core_reset(netplay_t *netplay);
int16_t netplay_input_state(netplay_t *netplay,
unsigned port, unsigned device,
unsigned idx, unsigned id);
/**
* netplay_poll:
* @netplay : pointer to netplay object
*
* Polls network to see if we have anything new. If our
* network buffer is full, we simply have to block
* for new input data.
*
* Returns: true (1) if successful, otherwise false (0).
**/
bool netplay_poll(
bool block_libretro_input,
void *settings_data,
netplay_t *netplay);
/**
* netplay_is_alive:
* @netplay : pointer to netplay object
*
* Checks if input port/index is controlled by netplay or not.
*
* Returns: true (1) if alive, otherwise false (0).
**/
bool netplay_is_alive(netplay_t *netplay);
/**
* netplay_should_skip:
* @netplay : pointer to netplay object
*
* If we're fast-forward replaying to resync, check if we
* should actually show frame.
*
* Returns: bool (1) if we should skip this frame, otherwise
* false (0).
**/
bool netplay_should_skip(netplay_t *netplay);
/**
* init_netplay
* @server : server address to connect to (client only)
@ -410,33 +279,22 @@ bool netplay_should_skip(netplay_t *netplay);
* Returns: true (1) if successful, otherwise false (0).
**/
bool init_netplay(const char *server, unsigned port, const char *mitm_session);
bool init_netplay_deferred(const char *server, unsigned port, const char *mitm_session);
bool init_netplay_deferred(const char *server, unsigned port,
const char *mitm_session);
void deinit_netplay(void);
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);
bool netplay_driver_ctl(enum rarch_netplay_ctl_state state, void *data);
#ifdef HAVE_NETPLAYDISCOVERY
/** Initialize Netplay discovery */
bool init_netplay_discovery(void);
/** Deinitialize and free Netplay discovery */
void deinit_netplay_discovery(void);
/** Discovery control */
bool netplay_discovery_driver_ctl(
enum rarch_netplay_discovery_ctl_state state, void *data);
bool netplay_discovery_driver_ctl(enum rarch_netplay_discovery_ctl_state state,
void *data);
#endif
bool netplay_decode_hostname(const char *hostname,
char *address, unsigned *port, char *session, size_t len);
bool netplay_is_lan_address(struct sockaddr_in *addr);
bool netplay_6to4(struct sockaddr_storage *addr);
extern const mitm_server_t netplay_mitm_server_list[NETPLAY_MITM_SERVERS];
#endif

File diff suppressed because it is too large Load Diff

View File

@ -20,25 +20,30 @@
#define __RARCH_NETPLAY_PRIVATE_H
#include "netplay.h"
#include "netplay_protocol.h"
#include <libretro.h>
#include <retro_miscellaneous.h>
#include <streams/trans_stream.h>
#include "../../retroarch_types.h"
#define RARCH_DEFAULT_PORT 55435
#define RARCH_DEFAULT_NICK "Anonymous"
#define NETPLAY_PASS_LEN 128
#define NETPLAY_PASS_HASH_LEN 64 /* length of a SHA-256 hash */
#define MAX_SERVER_STALL_TIME_USEC (5*1000*1000)
#define MAX_CLIENT_STALL_TIME_USEC (10*1000*1000)
#define CATCH_UP_CHECK_TIME_USEC (500*1000)
#define MAX_RETRIES 16
#define RETRY_MS 500
#define MAX_INPUT_DEVICES 16
#define MAX_SERVER_STALL_TIME_USEC (5*1000*1000)
#define MAX_CLIENT_STALL_TIME_USEC (10*1000*1000)
#define CATCH_UP_CHECK_TIME_USEC (500*1000)
#define MAX_RETRIES 16
#define RETRY_MS 500
#define MAX_INPUT_DEVICES 16
/* We allow only 32 clients to fit into a 32-bit bitmap */
#define MAX_CLIENTS 32
typedef uint32_t client_bitmap_t;
#define MAX_CLIENTS 32
/* Because the callback keyboard reverses some assumptions, when the keyboard
* callbacks are in use, we assign a pseudodevice for it */
@ -63,8 +68,9 @@ typedef uint32_t client_bitmap_t;
/* Mapping of serialization quirks to netplay quirks. */
#define NETPLAY_QUIRK_MAP_UNDERSTOOD (\
RETRO_SERIALIZATION_QUIRK_INCOMPLETE |\
RETRO_SERIALIZATION_QUIRK_CORE_VARIABLE_SIZE |\
RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE |\
RETRO_SERIALIZATION_QUIRK_CORE_VARIABLE_SIZE |\
RETRO_SERIALIZATION_QUIRK_FRONT_VARIABLE_SIZE |\
RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION |\
RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT |\
RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT \
@ -89,6 +95,18 @@ typedef uint32_t client_bitmap_t;
#define NETPLAY_COMPRESSION_SUPPORTED 0
#endif
/* The keys supported by netplay */
enum netplay_keys
{
NETPLAY_KEY_UNKNOWN = 0,
#define K(k) NETPLAY_KEY_ ## k,
#define KL(k,l) K(k)
#include "netplay_keys.h"
#undef KL
#undef K
NETPLAY_KEY_LAST
};
enum netplay_cmd
{
/* Basic commands */
@ -194,11 +212,11 @@ enum netplay_cmd
NETPLAY_CMD_SETTING_INPUT_LATENCY_FRAMES = 0x2001
};
#define NETPLAY_CMD_SYNC_BIT_PAUSED (1U<<31)
#define NETPLAY_CMD_PLAY_BIT_SLAVE (1U<<31)
#define NETPLAY_CMD_MODE_BIT_YOU (1U<<31)
#define NETPLAY_CMD_MODE_BIT_PLAYING (1U<<30)
#define NETPLAY_CMD_MODE_BIT_SLAVE (1U<<29)
#define NETPLAY_CMD_SYNC_BIT_PAUSED (1U<<31)
#define NETPLAY_CMD_PLAY_BIT_SLAVE (1U<<31)
#define NETPLAY_CMD_MODE_BIT_YOU (1U<<31)
#define NETPLAY_CMD_MODE_BIT_PLAYING (1U<<30)
#define NETPLAY_CMD_MODE_BIT_SLAVE (1U<<29)
/* These are the reasons given for mode changes to be rejected */
enum netplay_cmd_mode_reasons
@ -224,22 +242,22 @@ enum rarch_netplay_share_preference
{
/* Prefer not to share, shouldn't be set
as a sharing mode for an shared device */
NETPLAY_SHARE_NO_SHARING = 0x0,
NETPLAY_SHARE_NO_SHARING = 0x00,
/* No preference. Only for requests.
Set if sharing is requested but either
* digital or analog doesn't have a preference. */
NETPLAY_SHARE_NO_PREFERENCE = 0x1,
NETPLAY_SHARE_NO_PREFERENCE = 0x01,
/* For digital devices */
NETPLAY_SHARE_DIGITAL_BITS = 0x1C,
NETPLAY_SHARE_DIGITAL_OR = 0x4,
NETPLAY_SHARE_DIGITAL_XOR = 0x8,
NETPLAY_SHARE_DIGITAL_VOTE = 0xC,
NETPLAY_SHARE_DIGITAL_BITS = 0x1C,
NETPLAY_SHARE_DIGITAL_OR = 0x04,
NETPLAY_SHARE_DIGITAL_XOR = 0x08,
NETPLAY_SHARE_DIGITAL_VOTE = 0x0C,
/* For analog devices */
NETPLAY_SHARE_ANALOG_BITS = 0xE0,
NETPLAY_SHARE_ANALOG_MAX = 0x20,
NETPLAY_SHARE_ANALOG_BITS = 0xE0,
NETPLAY_SHARE_ANALOG_MAX = 0x20,
NETPLAY_SHARE_ANALOG_AVERAGE = 0x40
};
@ -300,7 +318,7 @@ struct delta_frame
/* The simulated input. is_real here means the simulation is done, i.e.,
* it's a real simulation, not real input. */
netplay_input_state_t simlated_input[MAX_INPUT_DEVICES];
netplay_input_state_t simulated_input[MAX_INPUT_DEVICES];
/* The serialized state of the core at this frame, before input */
void *state;
@ -339,14 +357,18 @@ struct netplay_connection
/* Timer used to estimate a connection's latency */
retro_time_t ping_timer;
/* Address of peer */
struct sockaddr_storage addr;
/* Buffers for sending and receiving data */
struct socket_buffer send_packet_buffer, recv_packet_buffer;
struct socket_buffer send_packet_buffer;
struct socket_buffer recv_packet_buffer;
/* fd associated with this connection */
int fd;
/* What compression does this peer support? */
uint32_t compression_supported;
/* Salt associated with password transaction */
uint32_t salt;
/* Which netplay protocol is this connection running? */
uint32_t netplay_protocol;
/* If the mode is a DELAYED_DISCONNECT or SPECTATOR,
* the transmission of the mode change may have to
@ -355,43 +377,37 @@ struct netplay_connection
* is active. */
uint32_t delay_frame;
/* What compression does this peer support? */
uint32_t compression_supported;
/* For the server: When was the last time we requested
* this client to stall?
* For the client: How many frames of stall do we have left? */
uint32_t stall_frame;
/* Salt associated with password transaction */
uint32_t salt;
/* Which netplay protocol is this connection running? */
uint32_t netplay_protocol;
/* What latency is this connection running on?
* Network latency has limited precision as we estimate it
* once every pre-frame. */
int32_t ping;
/* Is this connection stalling? */
enum rarch_netplay_stall_reason stall;
/* fd associated with this connection */
int fd;
/* Mode of the connection */
enum rarch_netplay_connection_mode mode;
/* Is this connection stalling? */
enum rarch_netplay_stall_reason stall;
/* Nickname of peer */
char nick[NETPLAY_NICK_LEN];
/* Is this connection buffer in use? */
bool active;
/* Is this player paused? */
bool paused;
/* Is this connection allowed to play (server only)? */
bool can_play;
/* Is this connection buffer in use? */
bool active;
/* Did we request a ping response? */
bool ping_requested;
};
@ -400,8 +416,8 @@ struct netplay_connection
struct compression_transcoder
{
const struct trans_stream_backend *compression_backend;
void *compression_stream;
const struct trans_stream_backend *decompression_backend;
void *compression_stream;
void *decompression_stream;
};
@ -423,42 +439,52 @@ struct netplay_mitm_pending
int fds[NETPLAY_MITM_MAX_PENDING];
};
struct netplay_chat
{
struct
{
uint32_t frames;
char nick[NETPLAY_NICK_LEN];
char msg[NETPLAY_CHAT_MAX_SIZE];
} messages[NETPLAY_CHAT_MAX_MESSAGES];
};
struct netplay
{
/* Quirks in the savestate implementation */
uint64_t quirks;
/* We stall if we're far enough ahead that we
* couldn't transparently rewind.
* To know if we could transparently rewind,
* we need to know how long running a frame takes.
* We record that every frame and get a running (window) average. */
retro_time_t frame_run_time[NETPLAY_FRAME_RUN_TIME_WINDOW];
retro_time_t frame_run_time_sum;
retro_time_t frame_run_time_avg;
/* When did we start falling behind? */
retro_time_t catch_up_time;
/* How long have we been stalled? */
retro_time_t stall_time;
/* We stall if we're far enough ahead that we
* couldn't transparently rewind.
* To know if we could transparently rewind,
* we need to know how long running a frame takes.
* We record that every frame and get a running (window) average. */
retro_time_t frame_run_time[NETPLAY_FRAME_RUN_TIME_WINDOW];
retro_time_t frame_run_time_sum, frame_run_time_avg;
struct retro_callbacks cbs;
/* Compression transcoder */
struct compression_transcoder compress_nil,
compress_zlib;
struct compression_transcoder compress_nil;
struct compression_transcoder compress_zlib;
/* MITM session id */
mitm_id_t mitm_session_id;
struct netplay_connection one_connection; /* Client only */
/* All of our connections */
struct netplay_connection *connections;
/* Chat messages */
struct netplay_chat chat;
/* MITM connection handler */
struct netplay_mitm_pending *mitm_pending;
/* Our local socket info */
struct addrinfo *addr;
/* All of our connections */
struct netplay_connection *connections;
struct delta_frame *buffer;
@ -475,21 +501,21 @@ struct netplay
/* The frame we're currently inputting */
size_t self_ptr;
/* The frame we're currently running, which may be
/* The frame we're currently running, which may be
* behind the frame we're currently inputting if
* we're using input latency */
size_t run_ptr;
/* The first frame at which some data might be unreliable */
size_t other_ptr;
/* Pointer to the first frame for which we're missing
/* Pointer to the first frame for which we're missing
* the data of at least one connected player excluding ourself.
* Generally, other_ptr <= unread_ptr <= self_ptr,
* but unread_ptr can get ahead of self_ptr if the peer
* Generally, other_ptr <= unread_ptr <= self_ptr,
* but unread_ptr can get ahead of self_ptr if the peer
* is running fast. */
size_t unread_ptr;
/* Pointer to the next frame to read from each client */
size_t read_ptr[MAX_CLIENTS];
/* Pointer to the next frame to read from the server
/* Pointer to the next frame to read from the server
* (as it might not be a player but still synchronizes)
*/
size_t server_ptr;
@ -499,9 +525,6 @@ struct netplay
/* Pseudo random seed */
unsigned long simple_rand_next;
/* TCP connection for listening (server only) */
int listen_fd;
/* Our client number */
uint32_t self_client_num;
@ -516,15 +539,11 @@ struct netplay
uint32_t client_devices[MAX_CLIENTS];
/* For each device, the bitmap of clients connected */
client_bitmap_t device_clients[MAX_INPUT_DEVICES];
uint32_t device_clients[MAX_INPUT_DEVICES];
/* Our own device bitmap */
uint32_t self_devices;
/* Number of desync operations we're currently performing.
* If set, we don't attempt to stay in sync. */
uint32_t desync;
/* The device types for every connected device.
* We store them and ignore any menu changes,
* as netplay needs fixed devices. */
@ -538,31 +557,46 @@ struct netplay
uint32_t server_frame_count;
uint32_t replay_frame_count;
int frame_run_time_ptr;
/* Counter for timeouts */
unsigned timeout_cnt;
/* Latency frames; positive to hide network latency,
* negative to hide input latency */
int input_latency_frames;
/* Frequency with which to check CRCs */
int check_frames;
/* How far behind did we fall? */
uint32_t catch_up_behind;
/* Number of desync operations we're currently performing.
* If set, we don't attempt to stay in sync. */
uint32_t desync;
/* Host settings */
int32_t input_latency_frames_min;
int32_t input_latency_frames_max;
/* Are we stalled? */
enum rarch_netplay_stall_reason stall;
/* Counter for timeouts */
unsigned timeout_cnt;
/* TCP connection for listening (server only) */
int listen_fd;
int frame_run_time_ptr;
/* Frequency with which to check CRCs */
int check_frames;
/* Latency frames; positive to hide network latency,
* negative to hide input latency */
int input_latency_frames;
int reannounce;
int reping;
/* Our mode and status */
enum rarch_netplay_connection_mode self_mode;
/* Are we stalled? */
enum rarch_netplay_stall_reason stall;
/* Keyboard mapping (network and host) */
uint16_t mapping_hton[RETROK_LAST];
uint16_t mapping_ntoh[NETPLAY_KEY_LAST];
/* TCP port (only set if serving) */
uint16_t tcp_port;
uint16_t ext_tcp_port;
@ -573,8 +607,6 @@ struct netplay
/* Our nickname */
char nick[NETPLAY_NICK_LEN];
bool nat_traversal;
/* Set to true if we have a device that most cores
* translate to "up/down" actions, typically a keyboard.
* We need to keep track of this because with such a device,
@ -583,11 +615,30 @@ struct netplay
* up/down states will proceed as expected. */
bool have_updown_device;
/* If true, never progress without peer input
* (stateless/rewindless mode) */
bool stateless_mode;
/* Are we the server? */
bool is_server;
bool nat_traversal;
/* Have we checked whether CRCs are valid at all? */
bool crc_validity_checked;
/* Are they valid? */
bool crcs_valid;
/* Netplay pausing */
bool local_paused;
bool remote_paused;
/* Are we replaying old frames? */
bool is_replay;
/* We don't want to poll several times on a frame. */
bool can_poll;
/* Opposite of stalling, should we be catching up? */
bool catch_up;
/* Force a rewind to other_frame_count/other_ptr.
* This is for synchronized events, such as restarting
@ -603,33 +654,17 @@ struct netplay
/* Have we requested a savestate as a sync point? */
bool savestate_request_outstanding;
/* Netplay pausing */
bool local_paused;
bool remote_paused;
/* If true, never progress without peer input
* (stateless/rewindless mode) */
bool stateless_mode;
/* Opposite of stalling, should we be catching up? */
bool catch_up;
/* Have we checked whether CRCs are valid at all? */
bool crc_validity_checked;
/* Are they valid? */
bool crcs_valid;
/* Are we the server? */
bool is_server;
/* Are we the connected? */
bool is_connected;
/* Host settings */
bool allow_pausing;
};
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);
/***************************************************************
* NETPLAY-BUF.C
**************************************************************/
@ -699,69 +734,22 @@ bool netplay_delta_frame_ready(netplay_t *netplay,
struct delta_frame *delta,
uint32_t frame);
/**
* netplay_input_state_for
*
* Get an input state for a particular client
*/
netplay_input_state_t netplay_input_state_for(
netplay_input_state_t *list,
uint32_t client_num, size_t size,
bool must_create, bool must_not_create);
/**
* netplay_expected_input_size
*
* Size in words for a given set of devices.
*/
uint32_t netplay_expected_input_size(netplay_t *netplay,
uint32_t devices);
/***************************************************************
* NETPLAY-FRONTEND.C
**************************************************************/
/**
* input_poll_net
* @netplay : pointer to netplay object
*
* Poll the network if necessary.
*/
void input_poll_net(void);
/***************************************************************
* NETPLAY-HANDSHAKE.C
**************************************************************/
/**
* netplay_handshake_init_send
*
* Initialize our handshake and send the first
* part of the handshake protocol.
*/
bool netplay_handshake_init_send(netplay_t *netplay,
struct netplay_connection *connection, uint32_t protocol);
/**
* netplay_handshake
*
* Data receiver for all handshake states.
*/
bool netplay_handshake(netplay_t *netplay,
struct netplay_connection *connection, bool *had_input);
void input_poll_net(netplay_t *netplay);
/***************************************************************
* NETPLAY-INIT.C
**************************************************************/
/**
* netplay_try_init_serialization
*
* Try to initialize serialization. For quirky cores.
*
* Returns true if serialization is now ready, false otherwise.
*/
bool netplay_try_init_serialization(netplay_t *netplay);
/**
* netplay_wait_and_init_serialization
*
@ -772,59 +760,10 @@ bool netplay_try_init_serialization(netplay_t *netplay);
*/
bool netplay_wait_and_init_serialization(netplay_t *netplay);
/**
* netplay_new:
* @server : IP address of server.
* @mitm : IP address of the MITM/tunnel server.
* @port : Port of server.
* @mitm_session : Session id for MITM/tunnel.
* @stateless_mode : Shall we run in stateless mode?
* @check_frames : Frequency with which to check CRCs.
* @cb : Libretro callbacks.
* @nat_traversal : If true, attempt NAT traversal.
* @nick : Nickname of user.
* @quirks : Netplay quirks required for this session.
*
* Creates a new netplay handle. A NULL server means we're
* hosting.
*
* Returns: new netplay data.
*/
netplay_t *netplay_new(const char *server, const char *mitm, uint16_t port,
const char *mitm_session,
bool stateless_mode, int check_frames,
const struct retro_callbacks *cb,
bool nat_traversal, const char *nick,
uint64_t quirks);
/**
* netplay_free
* @netplay : pointer to netplay object
*
* Frees netplay data/
*/
void netplay_free(netplay_t *netplay);
/***************************************************************
* NETPLAY-IO.C
**************************************************************/
/**
* netplay_hangup:
*
* Disconnects an active Netplay connection due to an error
*/
void netplay_hangup(netplay_t *netplay,
struct netplay_connection *connection);
/**
* netplay_delayed_state_change:
*
* Handle any pending state changes which are ready as
* of the beginning of the current frame.
*/
void netplay_delayed_state_change(netplay_t *netplay);
/**
* netplay_send_cur_input
*
@ -866,85 +805,20 @@ void netplay_send_raw_cmd_all(netplay_t *netplay,
bool netplay_cmd_mode(netplay_t *netplay,
enum rarch_netplay_connection_mode mode);
/**
* netplay_poll_net_input
*
* Poll input from the network
*/
int netplay_poll_net_input(netplay_t *netplay, bool block);
/**
* netplay_handle_slaves
*
* Handle any slave connections
*/
void netplay_handle_slaves(netplay_t *netplay);
/**
* netplay_init_nat_traversal
*
* Initialize the NAT traversal library and try to open a port
*/
void netplay_init_nat_traversal(netplay_t *netplay);
void netplay_deinit_nat_traversal(void);
/***************************************************************
* NETPLAY-KEYBOARD.C
**************************************************************/
/* The mapping of keys from libretro (host) to netplay (network) */
uint32_t netplay_key_hton(unsigned key);
/* Because the hton keymapping has to be generated,
* call this before using netplay_key_hton */
void netplay_key_hton_init(void);
/***************************************************************
* NETPLAY-SYNC.C
**************************************************************/
/**
* netplay_update_unread_ptr
*
* Update the global unread_ptr and unread_frame_count to
* correspond to the earliest unread frame count of any
* connected player.
*/
void netplay_update_unread_ptr(netplay_t *netplay);
/**
* netplay_resolve_input
* @netplay : pointer to netplay object
* @sim_ptr : frame pointer for which to resolve input
* @resim : are we resimulating, or simulating this
* frame for the first time?
*
* "Simulate" input by assuming it hasn't changed since the
* last read input.
* Returns true if the resolved input changed from the
* last time it was resolved.
*/
bool netplay_resolve_input(netplay_t *netplay,
size_t sim_ptr, bool resim);
/**
* netplay_sync_pre_frame
* netplay_load_savestate
* @netplay : pointer to netplay object
* @disconnect : disconnect netplay
* @serial_info : the savestate being loaded, NULL means
* "load it yourself"
* @save : Whether to save the provided serial_info
* into the frame buffer
*
* Pre-frame for Netplay synchronization.
*/
bool netplay_sync_pre_frame(netplay_t *netplay, bool *disconnect);
/**
* netplay_sync_post_frame
* @netplay : pointer to netplay object
* @stalled : true if we're currently stalled
*
* Post-frame for Netplay synchronization.
* We check if we have new input and replay from recorded input.
*/
void netplay_sync_post_frame(netplay_t *netplay, bool stalled);
* Inform Netplay of a savestate load and send it to the other side
**/
void netplay_load_savestate(netplay_t *netplay,
retro_ctx_serialize_info_t *serial_info, bool save);
#endif