diff --git a/network/netplay/netplay.c b/network/netplay/netplay.c index 0c306b3a4c..90fe92303b 100644 --- a/network/netplay/netplay.c +++ b/network/netplay/netplay.c @@ -31,6 +31,7 @@ #include "netplay_private.h" +#include "../../autosave.h" #include "../../configuration.h" #include "../../command.h" #include "../../movie.h" @@ -951,6 +952,57 @@ void netplay_log_connection(const struct sockaddr_storage *their_addr, +bool netplay_wait_and_init_serialization(netplay_t *netplay) +{ + int frames; + + if (netplay->state_size) + return true; + + /* Wait maximally 60 frames, or until the core reports it's initialized */ + for (frames = 0; (core_serialize_quirks() & RETRO_SERIALIZATION_QUIRK_INITIALIZING) && frames < 60; frames++) + { +#if defined(HAVE_THREADS) + autosave_lock(); +#endif + core_run(); +#if defined(HAVE_THREADS) + autosave_unlock(); +#endif + } + + return netplay_init_serialization(netplay); + +} + +bool netplay_init_serialization(netplay_t *netplay) +{ + unsigned i; + retro_ctx_size_info_t info; + + if (netplay->state_size) + return true; + + core_serialize_size(&info); + + netplay->state_size = info.size; + + for (i = 0; i < netplay->buffer_size; i++) + { + netplay->buffer[i].state = calloc(netplay->state_size, 1); + + if (!netplay->buffer[i].state) + { + netplay->quirks |= NETPLAY_QUIRK_NO_SAVESTATES; + return false; + } + } + + /* Once initialized, we no longer exhibit this quirk */ + netplay->quirks &= ~((uint32_t) NETPLAY_QUIRK_INITIALIZATION); + + return true; +} static bool netplay_init_buffers(netplay_t *netplay, unsigned frames) { @@ -969,25 +1021,8 @@ static bool netplay_init_buffers(netplay_t *netplay, unsigned frames) if (!netplay->buffer) return false; - { - unsigned i; - retro_ctx_size_info_t info; - - core_serialize_size(&info); - - netplay->state_size = info.size; - - for (i = 0; i < netplay->buffer_size; i++) - { - netplay->buffer[i].state = calloc(netplay->state_size, 1); - - if (!netplay->buffer[i].state) - { - netplay->quirks |= NETPLAY_QUIRK_NO_SAVESTATES; - netplay->stall_frames = 0; - } - } - } + if (!(netplay->quirks & NETPLAY_QUIRK_INITIALIZATION)) + return netplay_init_serialization(netplay); return true; } diff --git a/network/netplay/netplay_net.c b/network/netplay/netplay_net.c index a4fffb0a70..ce3e79d2e8 100644 --- a/network/netplay/netplay_net.c +++ b/network/netplay/netplay_net.c @@ -69,7 +69,11 @@ static bool netplay_net_pre_frame(netplay_t *netplay) serial_info.size = netplay->state_size; memset(serial_info.data, 0, serial_info.size); - if (!(netplay->quirks & NETPLAY_QUIRK_NO_SAVESTATES) && core_serialize(&serial_info)) + if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) + { + /* Don't serialize until it's safe */ + } + else if (!(netplay->quirks & NETPLAY_QUIRK_NO_SAVESTATES) && core_serialize(&serial_info)) { if (netplay->force_send_savestate && !netplay->stall) { @@ -216,6 +220,10 @@ static void netplay_net_post_frame(netplay_t *netplay) netplay->replay_ptr = netplay->other_ptr; netplay->replay_frame_count = netplay->other_frame_count; + if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) + /* Make sure we're initialized before we start loading things */ + netplay_wait_and_init_serialization(netplay); + serial_info.data = NULL; serial_info.data_const = netplay->buffer[netplay->replay_ptr].state; serial_info.size = netplay->state_size; diff --git a/network/netplay/netplay_private.h b/network/netplay/netplay_private.h index e2159e10e6..35cb47c530 100644 --- a/network/netplay/netplay_private.h +++ b/network/netplay/netplay_private.h @@ -198,6 +198,12 @@ struct netplay_callbacks* netplay_get_cbs_net(void); struct netplay_callbacks* netplay_get_cbs_spectate(void); +/* Normally called at init time, unless the INITIALIZATION quirk is set */ +bool netplay_init_serialization(netplay_t *netplay); + +/* Force serialization to be ready by fast-forwarding the core */ +bool netplay_wait_and_init_serialization(netplay_t *netplay); + void netplay_simulate_input(netplay_t *netplay, uint32_t sim_ptr); void netplay_log_connection(const struct sockaddr_storage *their_addr, diff --git a/network/netplay/netplay_spectate.c b/network/netplay/netplay_spectate.c index 53ad18b85a..fa05546268 100644 --- a/network/netplay/netplay_spectate.c +++ b/network/netplay/netplay_spectate.c @@ -111,6 +111,16 @@ static bool netplay_spectate_pre_frame(netplay_t *netplay) return true; } + /* Wait until it's safe to serialize */ + if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) + { + netplay->is_replay = true; + netplay->replay_ptr = netplay->self_ptr; + netplay->replay_frame_count = netplay->self_frame_count; + netplay_wait_and_init_serialization(netplay); + netplay->is_replay = false; + } + /* Start them at the current frame */ netplay->spectate.frames[idx] = netplay->self_frame_count; serial_info.data_const = NULL; @@ -197,6 +207,10 @@ static void netplay_spectate_post_frame(netplay_t *netplay) netplay->replay_ptr = netplay->other_ptr; netplay->replay_frame_count = netplay->other_frame_count; + /* Wait until it's safe to serialize */ + if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) + netplay_wait_and_init_serialization(netplay); + serial_info.data = NULL; serial_info.data_const = netplay->buffer[netplay->replay_ptr].state; serial_info.size = netplay->state_size;