diff --git a/config.def.h b/config.def.h index 12c2773810..78ac7d8191 100644 --- a/config.def.h +++ b/config.def.h @@ -794,6 +794,9 @@ static const bool pause_nonactive = true; * It is measured in seconds. A value of 0 disables autosave. */ static const unsigned autosave_interval = 0; +/* Netplay without savestates/rewind */ +static const bool netplay_stateless_mode = false; + /* When being client over netplay, use keybinds for * user 1 rather than user 2. */ static const bool netplay_client_swap_input = true; diff --git a/configuration.c b/configuration.c index 33d65f2a7c..3b3499cfe3 100644 --- a/configuration.c +++ b/configuration.c @@ -718,6 +718,7 @@ static int populate_settings_bool(settings_t *settings, struct config_bool_setti SETTING_BOOL("all_users_control_menu", &settings->input.all_users_control_menu, true, all_users_control_menu, false); SETTING_BOOL("menu_swap_ok_cancel_buttons", &settings->input.menu_swap_ok_cancel_buttons, true, menu_swap_ok_cancel_buttons, false); #ifdef HAVE_NETWORKING + SETTING_BOOL("netplay_stateless_mode", &settings->netplay.stateless_mode, false, netplay_stateless_mode, false); SETTING_BOOL("netplay_client_swap_input", &settings->netplay.swap_input, true, netplay_client_swap_input, false); #endif SETTING_BOOL("input_descriptor_label_show", &settings->input.input_descriptor_label_show, true, input_descriptor_label_show, false); @@ -947,7 +948,6 @@ static int populate_settings_int(settings_t *settings, struct config_int_setting SETTING_INT("state_slot", (unsigned*)&settings->state_slot, false, 0 /* TODO */, false); #ifdef HAVE_NETWORKING SETTING_INT("netplay_ip_port", &settings->netplay.port, true, RARCH_DEFAULT_PORT, false); - SETTING_INT("netplay_delay_frames", &settings->netplay.delay_frames, true, netplay_delay_frames, false); SETTING_INT("netplay_check_frames", &settings->netplay.check_frames, true, netplay_check_frames, false); #endif #ifdef HAVE_LANGEXTRA @@ -1856,8 +1856,8 @@ static bool config_load_file(const char *path, bool set_defaults, } #ifdef HAVE_NETWORKING - if (!retroarch_override_setting_is_set(RARCH_OVERRIDE_SETTING_NETPLAY_DELAY_FRAMES, NULL)) - CONFIG_GET_INT_BASE(conf, settings, netplay.delay_frames, "netplay_delay_frames"); + if (!retroarch_override_setting_is_set(RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE, NULL)) + CONFIG_GET_BOOL_BASE(conf, settings, netplay.stateless_mode, "netplay_stateless_mode"); if (!retroarch_override_setting_is_set(RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES, NULL)) CONFIG_GET_INT_BASE(conf, settings, netplay.check_frames, "netplay_check_frames"); if (!retroarch_override_setting_is_set(RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT, NULL)) diff --git a/configuration.h b/configuration.h index ade5ac6815..4f32cef7ff 100644 --- a/configuration.h +++ b/configuration.h @@ -401,7 +401,7 @@ typedef struct settings { char server[255]; unsigned port; - unsigned delay_frames; + bool stateless_mode; unsigned check_frames; bool swap_input; bool nat_traversal; diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 73886da4cc..da4e6a5521 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -571,8 +571,6 @@ MSG_HASH(MENU_ENUM_LABEL_NETPLAY_CHECK_FRAMES, "netplay_check_frames") MSG_HASH(MENU_ENUM_LABEL_NETPLAY_CLIENT_SWAP_INPUT, "netplay_client_swap_input") -MSG_HASH(MENU_ENUM_LABEL_NETPLAY_DELAY_FRAMES, - "netplay_delay_frames") MSG_HASH(MENU_ENUM_LABEL_NETPLAY_DISCONNECT, "menu_netplay_disconnect") MSG_HASH(MENU_ENUM_LABEL_NETPLAY_ENABLE, @@ -597,6 +595,8 @@ MSG_HASH(MENU_ENUM_LABEL_NETPLAY_SPECTATE_PASSWORD, "netplay_spectate_password") MSG_HASH(MENU_ENUM_LABEL_NETPLAY_SPECTATOR_MODE_ENABLE, "netplay_spectator_mode_enable") +MSG_HASH(MENU_ENUM_LABEL_NETPLAY_STATELESS_MODE, + "netplay_stateless_mode") MSG_HASH(MENU_ENUM_LABEL_NETPLAY_TCP_UDP_PORT, "netplay_tcp_udp_port") MSG_HASH(MENU_ENUM_LABEL_NETPLAY_LAN_SCAN_SETTINGS, diff --git a/intl/msg_hash_us.c b/intl/msg_hash_us.c index cce55e8447..aee30281a6 100644 --- a/intl/msg_hash_us.c +++ b/intl/msg_hash_us.c @@ -1561,6 +1561,15 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) "Increasing this value will increase \n" "performance, but introduce more latency."); break; + case MENU_ENUM_LABEL_NETPLAY_STATELESS_MODE: + snprintf(s, len, + "Whether to run netplay in a mode not requiring\n" + "save states. \n" + " \n" + "If set to true, a very fast network is required,\n" + "but no rewinding is performed, so there will be\n" + "no netplay jitter.\n"); + break; case MENU_ENUM_LABEL_NETPLAY_CHECK_FRAMES: snprintf(s, len, "The frequency in frames with which netplay \n" diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 2b263696ed..e8ff6da8c0 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -976,6 +976,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_PASSWORD, "Server Password") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SETTINGS, "Netplay settings") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_STATELESS_MODE, + "Netplay Stateless Mode") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATE_PASSWORD, "Server Spectate-Only Password") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATOR_MODE_ENABLE, diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 048f67be9d..f59782c09c 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -4698,7 +4698,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) PARSE_ONLY_STRING, false) != -1) count++; if (menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_NETPLAY_DELAY_FRAMES, + MENU_ENUM_LABEL_NETPLAY_STATELESS_MODE, PARSE_ONLY_UINT, false) != -1) count++; if (menu_displaylist_parse_settings_enum(menu, info, diff --git a/menu/menu_setting.c b/menu/menu_setting.c index d6cd6a53c4..1a8499c44f 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -1721,16 +1721,9 @@ void general_write_handler(void *data) retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_NETPLAY_MODE, NULL); #endif break; - case MENU_ENUM_LABEL_NETPLAY_DELAY_FRAMES: + case MENU_ENUM_LABEL_NETPLAY_STATELESS_MODE: #ifdef HAVE_NETWORKING - { - bool val = (settings->netplay.delay_frames > 0); - - if (val) - retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_NETPLAY_DELAY_FRAMES, NULL); - else - retroarch_override_setting_unset(RARCH_OVERRIDE_SETTING_NETPLAY_DELAY_FRAMES, NULL); - } + retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE, NULL); #endif break; case MENU_ENUM_LABEL_NETPLAY_CHECK_FRAMES: @@ -5605,19 +5598,20 @@ static bool setting_append_list( general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT); - CONFIG_UINT( + CONFIG_BOOL( list, list_info, - &settings->netplay.delay_frames, - MENU_ENUM_LABEL_NETPLAY_DELAY_FRAMES, - MENU_ENUM_LABEL_VALUE_NETPLAY_DELAY_FRAMES, - netplay_delay_frames, + &settings->netplay.stateless_mode, + MENU_ENUM_LABEL_NETPLAY_STATELESS_MODE, + MENU_ENUM_LABEL_VALUE_NETPLAY_STATELESS_MODE, + false, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, &group_info, &subgroup_info, parent_group, general_write_handler, - general_read_handler); - menu_settings_list_current_add_range(list, list_info, 0, 60, 1, true, false); - settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); + general_read_handler, + SD_FLAG_NONE); CONFIG_UINT( list, list_info, diff --git a/msg_hash.h b/msg_hash.h index ab8d972ae9..1bb53899e1 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1008,6 +1008,7 @@ enum msg_hash_enums MENU_LABEL(BLUETOOTH_ENABLE), MENU_LABEL(NETPLAY_CLIENT_SWAP_INPUT), MENU_LABEL(NETPLAY_DELAY_FRAMES), + MENU_LABEL(NETPLAY_STATELESS_MODE), MENU_LABEL(NETPLAY_CHECK_FRAMES), MENU_LABEL(NETPLAY_SPECTATOR_MODE_ENABLE), MENU_LABEL(NETPLAY_TCP_UDP_PORT), diff --git a/network/netplay/netplay_frontend.c b/network/netplay/netplay_frontend.c index 5ab01f89e6..524c5e814f 100644 --- a/network/netplay/netplay_frontend.c +++ b/network/netplay/netplay_frontend.c @@ -178,7 +178,7 @@ static bool netplay_poll(void) /* Read Netplay input, block if we're configured to stall for input every * frame */ - if (netplay_data->delay_frames == 0 && + if (netplay_data->stateless_mode && netplay_data->unread_frame_count <= netplay_data->self_frame_count) res = netplay_poll_net_input(netplay_data, true); else @@ -226,9 +226,9 @@ static bool netplay_poll(void) if (netplay_data->frame_run_time_avg) max_ahead = 50000 / netplay_data->frame_run_time_avg; else - max_ahead = netplay_data->delay_frames; - if (max_ahead > netplay_data->delay_frames) - max_ahead = netplay_data->delay_frames; + max_ahead = NETPLAY_MAX_STALL_FRAMES; + if (max_ahead > NETPLAY_MAX_STALL_FRAMES) + max_ahead = NETPLAY_MAX_STALL_FRAMES; /* Are we too far ahead? */ netplay_update_unread_ptr(netplay_data); @@ -846,7 +846,7 @@ bool init_netplay(void *direct_host, const char *server, unsigned port, netplay_is_client ? server : NULL, port ? port : RARCH_DEFAULT_PORT, play_password, spectate_password, - settings->netplay.delay_frames, settings->netplay.check_frames, &cbs, + settings->netplay.stateless_mode, settings->netplay.check_frames, &cbs, settings->netplay.nat_traversal, settings->username, quirks); diff --git a/network/netplay/netplay_init.c b/network/netplay/netplay_init.c index 5494e532a1..4c9dd0ce84 100644 --- a/network/netplay/netplay_init.c +++ b/network/netplay/netplay_init.c @@ -230,11 +230,11 @@ static bool init_socket(netplay_t *netplay, void *direct_host, const char *serve static bool netplay_init_socket_buffers(netplay_t *netplay) { - /* Make our packet buffer big enough for a save state and frames-many frames - * of input data, plus the headers for each of them */ + /* Make our packet buffer big enough for a save state and stall-frames-many + * frames of input data, plus the headers for each of them */ size_t i; size_t packet_buffer_size = netplay->zbuffer_size + - netplay->delay_frames * WORDS_PER_FRAME + (netplay->delay_frames+1)*3; + NETPLAY_MAX_STALL_FRAMES * WORDS_PER_FRAME + (NETPLAY_MAX_STALL_FRAMES+1)*3; netplay->packet_buffer_size = packet_buffer_size; for (i = 0; i < netplay->connections_size; i++) @@ -366,18 +366,15 @@ bool netplay_wait_and_init_serialization(netplay_t *netplay) return false; } -static bool netplay_init_buffers(netplay_t *netplay, unsigned frames) +static bool netplay_init_buffers(netplay_t *netplay) { size_t packet_buffer_size; if (!netplay) return false; - /* * 2 + 1 because: - * Self sits in the middle, - * Other is allowed to drift as much as 'frames' frames behind - * Read is allowed to drift as much as 'frames' frames ahead */ - netplay->buffer_size = frames * 2 + 1; + /* Enough to get ahead or behind by MAX_STALL_FRAMES frames */ + netplay->buffer_size = NETPLAY_MAX_STALL_FRAMES + 1; netplay->buffer = (struct delta_frame*)calloc(netplay->buffer_size, sizeof(*netplay->buffer)); @@ -398,7 +395,7 @@ static bool netplay_init_buffers(netplay_t *netplay, unsigned frames) * @port : Port of server. * @play_password : Password required to play. * @spectate_password : Password required to connect. - * @delay_frames : Amount of delay frames. + * @stateless_mode : Shall we use stateless mode? * @check_frames : Frequency with which to check CRCs. * @cb : Libretro callbacks. * @nat_traversal : If true, attempt NAT traversal. @@ -412,7 +409,7 @@ static bool netplay_init_buffers(netplay_t *netplay, unsigned frames) */ netplay_t *netplay_new(void *direct_host, const char *server, uint16_t port, const char *play_password, const char *spectate_password, - unsigned delay_frames, unsigned check_frames, + bool stateless_mode, unsigned check_frames, const struct retro_callbacks *cb, bool nat_traversal, const char *nick, uint64_t quirks) { @@ -427,7 +424,7 @@ netplay_t *netplay_new(void *direct_host, const char *server, uint16_t port, netplay->player_max = 1; netplay->is_server = server == NULL; netplay->nat_traversal = netplay->is_server ? nat_traversal : false; - netplay->delay_frames = delay_frames; + netplay->stateless_mode = stateless_mode; netplay->check_frames = check_frames; netplay->crc_validity_checked = false; netplay->crcs_valid = true; @@ -458,7 +455,7 @@ netplay_t *netplay_new(void *direct_host, const char *server, uint16_t port, return NULL; } - if (!netplay_init_buffers(netplay, delay_frames)) + if (!netplay_init_buffers(netplay)) { free(netplay); return NULL; diff --git a/network/netplay/netplay_private.h b/network/netplay/netplay_private.h index aba8cf1179..5a183965a9 100644 --- a/network/netplay/netplay_private.h +++ b/network/netplay/netplay_private.h @@ -45,7 +45,8 @@ #define MAX_RETRIES 16 #define RETRY_MS 500 -#define NETPLAY_FRAME_RUN_TIME_WINDOW 128 +#define NETPLAY_MAX_STALL_FRAMES 60 +#define NETPLAY_FRAME_RUN_TIME_WINDOW 120 #define PREV_PTR(x) ((x) == 0 ? netplay->buffer_size - 1 : (x) - 1) #define NEXT_PTR(x) ((x + 1) % netplay->buffer_size) @@ -178,22 +179,6 @@ enum netplay_cmd_mode_reasons NETPLAY_CMD_MODE_REFUSED_REASON_NO_SLOTS }; -/* These are the configurations sent by NETPLAY_CMD_CFG. */ -enum netplay_cmd_cfg -{ - /* Nickname */ - NETPLAY_CFG_NICK = 0x0001, - - /* input.netplay_client_swap_input */ - NETPLAY_CFG_SWAP_INPUT = 0x0002, - - /* netplay.delay_frames */ - NETPLAY_CFG_DELAY_FRAMES = 0x0004, - - /* For more than 2 players */ - NETPLAY_CFG_PLAYER_SLOT = 0x0008 -}; - enum rarch_netplay_connection_mode { NETPLAY_CONNECTION_NONE = 0, @@ -421,8 +406,8 @@ struct netplay bool local_paused; bool remote_paused; - /* Old-style stalling (to be removed) */ - uint32_t delay_frames; + /* If true, never progress without peer input (stateless/rewindless mode) */ + bool stateless_mode; /* 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 @@ -661,7 +646,7 @@ bool netplay_wait_and_init_serialization(netplay_t *netplay); * @port : Port of server. * @play_password : Password required to play. * @spectate_password : Password required to connect. - * @delay_frames : Amount of delay frames. + * @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. @@ -675,7 +660,7 @@ bool netplay_wait_and_init_serialization(netplay_t *netplay); */ netplay_t *netplay_new(void *direct_host, const char *server, uint16_t port, const char *play_password, const char *spectate_password, - unsigned delay_frames, unsigned check_frames, + bool stateless_mode, unsigned check_frames, const struct retro_callbacks *cb, bool nat_traversal, const char *nick, uint64_t quirks); diff --git a/network/netplay/netplay_sync.c b/network/netplay/netplay_sync.c index 7601b6abc4..94420518b1 100644 --- a/network/netplay/netplay_sync.c +++ b/network/netplay/netplay_sync.c @@ -15,6 +15,7 @@ * If not, see . */ +#include #include #include @@ -203,7 +204,7 @@ bool netplay_sync_pre_frame(netplay_t *netplay) /* If the core can't serialize properly, we must stall for the * remote input on EVERY frame, because we can't recover */ netplay->quirks |= NETPLAY_QUIRK_NO_SAVESTATES; - netplay->delay_frames = 0; + netplay->stateless_mode = true; } /* If we can't transmit savestates, we must stall until the client is ready */ diff --git a/retroarch.c b/retroarch.c index 380c5dbdde..b0b10c8236 100644 --- a/retroarch.c +++ b/retroarch.c @@ -104,6 +104,7 @@ enum { RA_OPT_MENU = 256, /* must be outside the range of a char */ + RA_OPT_STATELESS, RA_OPT_CHECK_FRAMES, RA_OPT_PORT, RA_OPT_SPECTATE, @@ -143,7 +144,7 @@ static bool has_set_state_path = false; static bool has_set_netplay_mode = false; static bool has_set_netplay_ip_address = false; static bool has_set_netplay_ip_port = false; -static bool has_set_netplay_delay_frames = false; +static bool has_set_netplay_stateless_mode = false; static bool has_set_netplay_check_frames = false; static bool has_set_ups_pref = false; static bool has_set_bps_pref = false; @@ -339,7 +340,8 @@ static void retroarch_print_help(const char *arg0) puts(" -H, --host Host netplay as user 1."); puts(" -C, --connect=HOST Connect to netplay server as user 2."); puts(" --port=PORT Port used to netplay. Default is 55435."); - puts(" -F, --frames=NUMBER Delay frames when using netplay."); + puts(" --stateless Use \"stateless\" mode for netplay"); + puts(" (requires a very fast network)."); puts(" --check-frames=NUMBER\n" " Check frames when using netplay."); #if defined(HAVE_NETWORK_CMD) @@ -426,7 +428,7 @@ static void retroarch_parse_input(int argc, char *argv[]) #ifdef HAVE_NETWORKING { "host", 0, NULL, 'H' }, { "connect", 1, NULL, 'C' }, - { "frames", 1, NULL, 'F' }, + { "stateless", 0, NULL, RA_OPT_STATELESS }, { "check-frames", 1, NULL, RA_OPT_CHECK_FRAMES }, { "port", 1, NULL, RA_OPT_PORT }, #if defined(HAVE_NETWORK_CMD) @@ -705,10 +707,10 @@ static void retroarch_parse_input(int argc, char *argv[]) sizeof(settings->netplay.server)); break; - case 'F': - settings->netplay.delay_frames = strtol(optarg, NULL, 0); + case RA_OPT_STATELESS: + settings->netplay.stateless_mode = true; retroarch_override_setting_set( - RARCH_OVERRIDE_SETTING_NETPLAY_DELAY_FRAMES, NULL); + RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE, NULL); break; case RA_OPT_CHECK_FRAMES: @@ -1361,8 +1363,8 @@ bool retroarch_override_setting_is_set(enum rarch_override_setting enum_idx, voi return has_set_netplay_ip_address; case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT: return has_set_netplay_ip_port; - case RARCH_OVERRIDE_SETTING_NETPLAY_DELAY_FRAMES: - return has_set_netplay_delay_frames; + case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE: + return has_set_netplay_stateless_mode; case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES: return has_set_netplay_check_frames; case RARCH_OVERRIDE_SETTING_UPS_PREF: @@ -1418,8 +1420,8 @@ void retroarch_override_setting_set(enum rarch_override_setting enum_idx, void * case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT: has_set_netplay_ip_port = true; break; - case RARCH_OVERRIDE_SETTING_NETPLAY_DELAY_FRAMES: - has_set_netplay_delay_frames = true; + case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE: + has_set_netplay_stateless_mode = true; break; case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES: has_set_netplay_check_frames = true; @@ -1477,8 +1479,8 @@ void retroarch_override_setting_unset(enum rarch_override_setting enum_idx, void case RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT: has_set_netplay_ip_port = false; break; - case RARCH_OVERRIDE_SETTING_NETPLAY_DELAY_FRAMES: - has_set_netplay_delay_frames = false; + case RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE: + has_set_netplay_stateless_mode = false; break; case RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES: has_set_netplay_check_frames = false; diff --git a/retroarch.h b/retroarch.h index 15799c69fd..32d9a860aa 100644 --- a/retroarch.h +++ b/retroarch.h @@ -129,7 +129,7 @@ enum rarch_override_setting RARCH_OVERRIDE_SETTING_NETPLAY_MODE, RARCH_OVERRIDE_SETTING_NETPLAY_IP_ADDRESS, RARCH_OVERRIDE_SETTING_NETPLAY_IP_PORT, - RARCH_OVERRIDE_SETTING_NETPLAY_DELAY_FRAMES, + RARCH_OVERRIDE_SETTING_NETPLAY_STATELESS_MODE, RARCH_OVERRIDE_SETTING_NETPLAY_CHECK_FRAMES, RARCH_OVERRIDE_SETTING_UPS_PREF, RARCH_OVERRIDE_SETTING_BPS_PREF,