diff --git a/network/netplay/netplay_frontend.c b/network/netplay/netplay_frontend.c index ff68b1daee..8f5c0300cc 100644 --- a/network/netplay/netplay_frontend.c +++ b/network/netplay/netplay_frontend.c @@ -521,6 +521,8 @@ static void netplay_frontend_paused(netplay_t *netplay, bool paused) **/ bool netplay_pre_frame(netplay_t *netplay) { + bool sync_stalled; + retro_assert(netplay); /* FIXME: This is an ugly way to learn we're not paused anymore */ @@ -556,11 +558,18 @@ bool netplay_pre_frame(netplay_t *netplay) } } - if (!netplay_sync_pre_frame(netplay)) - return false; + sync_stalled = !netplay_sync_pre_frame(netplay); - return (!netplay->connected_players || - (!netplay->stall && !netplay->remote_paused)); + if (sync_stalled || + (netplay->connected_players && + (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; } /** @@ -576,7 +585,7 @@ void netplay_post_frame(netplay_t *netplay) size_t i; retro_assert(netplay); netplay_update_unread_ptr(netplay); - netplay_sync_post_frame(netplay); + netplay_sync_post_frame(netplay, false); for (i = 0; i < netplay->connections_size; i++) { diff --git a/network/netplay/netplay_io.c b/network/netplay/netplay_io.c index 48db63fc94..b5419ba7f1 100644 --- a/network/netplay/netplay_io.c +++ b/network/netplay/netplay_io.c @@ -26,6 +26,33 @@ #include "../../runloop.h" +#if 1 +#define DEBUG_NETPLAY_STEPS 1 + +static void print_state(netplay_t *netplay) +{ + char msg[512]; + size_t cur = 0; + uint32_t player; + +#define APPEND(out) cur += snprintf out +#define M msg + cur, sizeof(msg) - cur + + APPEND((M, "NETPLAY: S:%u U:%u O:%u", netplay->self_frame_count, netplay->unread_frame_count, netplay->other_frame_count)); + if (!netplay->is_server) + APPEND((M, " H:%u", netplay->server_frame_count)); + for (player = 0; player < MAX_USERS; player++) + { + if ((netplay->connected_players & (1<read_frame_count[player])); + } + APPEND((M, "\n")); + msg[sizeof(msg)-1] = '\0'; + + RARCH_LOG("%s\n", msg); +} +#endif + /** * remote_unpaused * @@ -362,8 +389,6 @@ static bool netplay_get_cmd(netplay_t *netplay, if (connection->mode < NETPLAY_CONNECTION_CONNECTED) return netplay_handshake(netplay, connection, had_input); - /* FIXME: This depends on delta_frame_ready */ - #define RECV(buf, sz) \ recvd = netplay_recv(&connection->recv_packet_buffer, connection->fd, (buf), \ (sz), false); \ @@ -452,7 +477,7 @@ static bool netplay_get_cmd(netplay_t *netplay, if (!netplay_delta_frame_ready(netplay, dframe, netplay->read_frame_count[player])) { /* FIXME: Catastrophe! */ - RARCH_ERR("Netplay input without a ready delta frame!\n"); + RARCH_ERR("Netplay input from %u without a ready delta frame!\n", player); return netplay_cmd_nak(netplay, connection); } memcpy(dframe->real_input_state[player], buffer + 2, @@ -475,6 +500,11 @@ static bool netplay_get_cmd(netplay_t *netplay, netplay->server_ptr = netplay->read_ptr[player]; netplay->server_frame_count = netplay->read_frame_count[player]; } + +#ifdef DEBUG_NETPLAY_STEPS + RARCH_LOG("Received input from %u\n", player); + print_state(netplay); +#endif break; } @@ -737,14 +767,33 @@ static bool netplay_get_cmd(netplay_t *netplay, } else { + uint32_t frame_count; + /* It wants future frames, make sure we don't capture or send intermediate ones */ START(netplay->self_ptr); - while (dframe->used && dframe->frame < frame) + frame_count = netplay->self_frame_count; + while (true) { + if (!dframe->used) + { + /* Make sure it's ready */ + if (!netplay_delta_frame_ready(netplay, dframe, frame_count)) + { + RARCH_ERR("Received mode change but delta frame isn't ready!\n"); + return netplay_cmd_nak(netplay, connection); + } + } + memset(dframe->self_state, 0, sizeof(dframe->self_state)); memset(dframe->real_input_state[player], 0, sizeof(dframe->self_state)); dframe->have_local = true; + + /* Go on to the next delta frame */ NEXT(); + frame_count++; + + if (frame_count >= frame) + break; } } @@ -755,6 +804,11 @@ static bool netplay_get_cmd(netplay_t *netplay, RARCH_LOG("%s\n", msg); runloop_msg_queue_push(msg, 1, 180, false); +#ifdef DEBUG_NETPLAY_STEPS + RARCH_LOG("Received mode change self->%u\n", player); + print_state(netplay); +#endif + } else /* YOU && !PLAYING */ { @@ -770,6 +824,11 @@ static bool netplay_get_cmd(netplay_t *netplay, RARCH_LOG("%s\n", msg); runloop_msg_queue_push(msg, 1, 180, false); +#ifdef DEBUG_NETPLAY_STEPS + RARCH_LOG("Received mode change %u self->spectating\n", netplay->self_player); + print_state(netplay); +#endif + } } @@ -795,6 +854,11 @@ static bool netplay_get_cmd(netplay_t *netplay, RARCH_LOG("%s\n", msg); runloop_msg_queue_push(msg, 1, 180, false); +#ifdef DEBUG_NETPLAY_STEPS + RARCH_LOG("Received mode change spectator->%u\n", player); + print_state(netplay); +#endif + } else { @@ -805,6 +869,12 @@ static bool netplay_get_cmd(netplay_t *netplay, snprintf(msg, sizeof(msg)-1, "Player %d has left", player+1); RARCH_LOG("%s\n", msg); runloop_msg_queue_push(msg, 1, 180, false); + +#ifdef DEBUG_NETPLAY_STEPS + RARCH_LOG("Received mode change %u->spectator\n", player); + print_state(netplay); +#endif + } } @@ -1003,6 +1073,12 @@ static bool netplay_get_cmd(netplay_t *netplay, return netplay_cmd_nak(netplay, connection); } + if (!netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->read_ptr[connection->player]], frame)) + { + RARCH_ERR("CMD_LOAD_SAVESTATE with unready delta frame.\n"); + return netplay_cmd_nak(netplay, connection); + } + RECV(&isize, sizeof(isize)) { RARCH_ERR("CMD_LOAD_SAVESTATE failed to receive inflated size.\n"); @@ -1059,6 +1135,12 @@ static bool netplay_get_cmd(netplay_t *netplay, netplay->savestate_request_outstanding = false; netplay->other_ptr = netplay->read_ptr[connection->player]; netplay->other_frame_count = frame; + +#ifdef DEBUG_NETPLAY_STEPS + RARCH_LOG("Loading state at %u\n", frame); + print_state(netplay); +#endif + break; } @@ -1154,21 +1236,15 @@ int netplay_poll_net_input(netplay_t *netplay, bool block) /* Make sure we're actually ready for data */ if (netplay->self_mode >= NETPLAY_CONNECTION_CONNECTED) { - netplay_update_unread_ptr(netplay); - if (!netplay_delta_frame_ready(netplay, - &netplay->buffer[netplay->unread_ptr], netplay->unread_frame_count)) - { - fprintf(stderr, "CATASTROPHE: Cannot load %u (%lu) while at %u (%lu)\n", netplay->self_frame_count, netplay->self_ptr, netplay->unread_frame_count, netplay->unread_ptr); - break; - } - if (!netplay->is_server && - !netplay_delta_frame_ready(netplay, - &netplay->buffer[netplay->server_ptr], - netplay->server_frame_count)) - { - fprintf(stderr, "CATASTROPHE DEUX\n"); - break; - } + netplay_update_unread_ptr(netplay); + if (!netplay_delta_frame_ready(netplay, + &netplay->buffer[netplay->unread_ptr], netplay->unread_frame_count)) + { + fprintf(stderr, "CATASTROPHE: Cannot load %u (%lu=%u) while at %u (%lu)\n", + netplay->unread_frame_count, netplay->unread_ptr, netplay->buffer[netplay->unread_ptr].frame, + netplay->self_frame_count, netplay->self_ptr); + break; + } } /* Read input from each connection */ diff --git a/network/netplay/netplay_private.h b/network/netplay/netplay_private.h index 05f65039bb..cf94284b53 100644 --- a/network/netplay/netplay_private.h +++ b/network/netplay/netplay_private.h @@ -777,10 +777,11 @@ bool netplay_sync_pre_frame(netplay_t *netplay); /** * 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); +void netplay_sync_post_frame(netplay_t *netplay, bool stalled); #endif diff --git a/network/netplay/netplay_sync.c b/network/netplay/netplay_sync.c index 3eb85af91a..8e572ef6ef 100644 --- a/network/netplay/netplay_sync.c +++ b/network/netplay/netplay_sync.c @@ -342,10 +342,14 @@ process: * 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) +void netplay_sync_post_frame(netplay_t *netplay, bool stalled) { - netplay->self_ptr = NEXT_PTR(netplay->self_ptr); - netplay->self_frame_count++; + /* Unless we're stalling, we've just finished running a frame */ + if (!stalled) + { + netplay->self_ptr = NEXT_PTR(netplay->self_ptr); + netplay->self_frame_count++; + } /* Only relevant if we're connected */ if ((netplay->is_server && !netplay->connected_players) || @@ -505,20 +509,4 @@ void netplay_sync_post_frame(netplay_t *netplay) driver_ctl(RARCH_DRIVER_CTL_SET_NONBLOCK_STATE, NULL); } } - - /* If we're supposed to stall, rewind (we shouldn't get this far if we're - * stalled, so this is a last resort) */ - if (netplay->stall) - { - retro_ctx_serialize_info_t serial_info; - - netplay->self_ptr = PREV_PTR(netplay->self_ptr); - netplay->self_frame_count--; - - serial_info.data = NULL; - serial_info.data_const = netplay->buffer[netplay->self_ptr].state; - serial_info.size = netplay->state_size; - - core_unserialize(&serial_info); - } }