From fbb508ab5ecc43c229d69cfc73123302796cbd3a Mon Sep 17 00:00:00 2001 From: Gregor Richards Date: Tue, 18 Apr 2017 15:25:58 -0400 Subject: [PATCH] Make rewind compatible with netplay. This commit adds support for temporary desync in netplay. When frontend features that can't be truly synced, in particular rewind, are used, netplay is momentarily disabled. As soon as the feature finished, e.g. a rewind ending, netplay resumes with a state load. For rewind, netplay peers won't actually experience the effect of rewind, but they will load the rewound state. --- command.c | 15 ++------------- managers/state_manager.c | 30 ++++++++++++++++++++++++++++++ network/netplay/netplay.h | 4 +++- network/netplay/netplay_frontend.c | 15 +++++++++++++++ network/netplay/netplay_private.h | 4 ++++ network/netplay/netplay_sync.c | 5 +++-- 6 files changed, 57 insertions(+), 16 deletions(-) diff --git a/command.c b/command.c index 4d0b1044e8..17ebcc58d9 100644 --- a/command.c +++ b/command.c @@ -2020,12 +2020,6 @@ bool command_event(enum event_command cmd, void *data) { #ifdef HAVE_CHEEVOS settings_t *settings = config_get_ptr(); -#endif -#ifdef HAVE_NETWORKING - if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL)) - return false; -#endif -#ifdef HAVE_CHEEVOS if (settings->cheevos.hardcore_mode_enable) return false; #endif @@ -2041,13 +2035,8 @@ bool command_event(enum event_command cmd, void *data) return false; #endif -#ifdef HAVE_NETWORKING - if (!netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL)) -#endif - { - if (settings->rewind_enable) - state_manager_event_init((unsigned)settings->rewind_buffer_size); - } + if (settings->rewind_enable) + state_manager_event_init((unsigned)settings->rewind_buffer_size); } break; case CMD_EVENT_REWIND_TOGGLE: diff --git a/managers/state_manager.c b/managers/state_manager.c index 39a55c236f..8ab2563ae0 100644 --- a/managers/state_manager.c +++ b/managers/state_manager.c @@ -31,6 +31,10 @@ #include "../verbosity.h" #include "../audio/audio_driver.h" +#ifdef HAVE_NETWORKING +#include "../network/netplay/netplay.h" +#endif + /* This makes Valgrind throw errors if a core overflows its savestate size. */ /* Keep it off unless you're chasing a core bug, it slows things down. */ #define STRICT_BUF_SIZE 0 @@ -687,9 +691,11 @@ bool state_manager_check_rewind(bool pressed, { bool ret = false; static bool first = true; + bool was_reversed = false; if (state_manager_frame_is_reversed()) { + was_reversed = true; audio_driver_frame_is_reverse(); state_manager_set_frame_is_reversed(false); } @@ -711,6 +717,14 @@ bool state_manager_check_rewind(bool pressed, { retro_ctx_serialize_info_t serial_info; +#ifdef HAVE_NETWORKING + if (!was_reversed) + { + /* Make sure netplay isn't confused */ + netplay_driver_ctl(RARCH_NETPLAY_CTL_DESYNC_PUSH, NULL); + } +#endif + state_manager_set_frame_is_reversed(true); audio_driver_setup_rewind(); @@ -735,6 +749,14 @@ bool state_manager_check_rewind(bool pressed, serial_info.size = rewind_state.size; core_unserialize(&serial_info); +#ifdef HAVE_NETWORKING + if (was_reversed) + { + /* Tell netplay we're done */ + netplay_driver_ctl(RARCH_NETPLAY_CTL_DESYNC_POP, NULL); + } +#endif + strlcpy(s, msg_hash_to_str(MSG_REWIND_REACHED_END), len); @@ -747,6 +769,14 @@ bool state_manager_check_rewind(bool pressed, { static unsigned cnt = 0; +#ifdef HAVE_NETWORKING + if (was_reversed) + { + /* Tell netplay we're done */ + netplay_driver_ctl(RARCH_NETPLAY_CTL_DESYNC_POP, NULL); + } +#endif + cnt = (cnt + 1) % (rewind_granularity ? rewind_granularity : 1); /* Avoid possible SIGFPE. */ diff --git a/network/netplay/netplay.h b/network/netplay/netplay.h index 8a22bc12dd..38b04326ab 100644 --- a/network/netplay/netplay.h +++ b/network/netplay/netplay.h @@ -46,7 +46,9 @@ enum rarch_netplay_ctl_state RARCH_NETPLAY_CTL_LOAD_SAVESTATE, RARCH_NETPLAY_CTL_RESET, RARCH_NETPLAY_CTL_DISCONNECT, - RARCH_NETPLAY_CTL_FINISHED_NAT_TRAVERSAL + RARCH_NETPLAY_CTL_FINISHED_NAT_TRAVERSAL, + RARCH_NETPLAY_CTL_DESYNC_PUSH, + RARCH_NETPLAY_CTL_DESYNC_POP }; int16_t input_state_net(unsigned port, unsigned device, diff --git a/network/netplay/netplay_frontend.c b/network/netplay/netplay_frontend.c index 1327354d13..0f0e941026 100644 --- a/network/netplay/netplay_frontend.c +++ b/network/netplay/netplay_frontend.c @@ -996,6 +996,10 @@ void netplay_load_savestate(netplay_t *netplay, } } + /* Don't send it if we're expected to be desynced */ + if (netplay->desync) + return; + /* If we can't send it to the peer, loading a state was a bad idea */ if (netplay->quirks & ( NETPLAY_QUIRK_NO_SAVESTATES @@ -1319,6 +1323,17 @@ bool netplay_driver_ctl(enum rarch_netplay_ctl_state state, void *data) netplay_announce_nat_traversal(netplay_data); #endif goto done; + case RARCH_NETPLAY_CTL_DESYNC_PUSH: + netplay_data->desync++; + break; + case RARCH_NETPLAY_CTL_DESYNC_POP: + if (netplay_data->desync) + { + netplay_data->desync--; + if (!netplay_data->desync) + netplay_load_savestate(netplay_data, NULL, true); + } + break; default: case RARCH_NETPLAY_CTL_NONE: ret = false; diff --git a/network/netplay/netplay_private.h b/network/netplay/netplay_private.h index fc4a7bd751..272c96cfae 100644 --- a/network/netplay/netplay_private.h +++ b/network/netplay/netplay_private.h @@ -354,6 +354,10 @@ struct netplay * connected_players) */ uint32_t connected_slaves; + /* Number of desync operations we're currently performing. If set, we don't + * attempt to stay in sync. */ + uint32_t desync; + /* Maximum player number */ uint32_t player_max; diff --git a/network/netplay/netplay_sync.c b/network/netplay/netplay_sync.c index cf624c81de..bcaedb364e 100644 --- a/network/netplay/netplay_sync.c +++ b/network/netplay/netplay_sync.c @@ -389,9 +389,10 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled) netplay->self_frame_count++; } - /* Only relevant if we're connected */ + /* Only relevant if we're connected and not in a desynching operation */ if ((netplay->is_server && !netplay->connected_players) || - (netplay->self_mode < NETPLAY_CONNECTION_CONNECTED)) + (netplay->self_mode < NETPLAY_CONNECTION_CONNECTED) || + (netplay->desync)) { netplay->other_frame_count = netplay->self_frame_count; netplay->other_ptr = netplay->self_ptr;