diff --git a/network/netplay/netplay_frontend.c b/network/netplay/netplay_frontend.c index 9c1872b9ca..45b0189d7a 100644 --- a/network/netplay/netplay_frontend.c +++ b/network/netplay/netplay_frontend.c @@ -106,10 +106,10 @@ static bool netplay_can_poll(netplay_t *netplay) static bool get_self_input_state(netplay_t *netplay) { uint32_t state[WORDS_PER_INPUT] = {0, 0, 0}; - struct delta_frame *ptr = &netplay->buffer[netplay->self_ptr]; + struct delta_frame *ptr = &netplay->buffer[netplay->input_ptr]; size_t i; - if (!netplay_delta_frame_ready(netplay, ptr, netplay->self_frame_count)) + if (!netplay_delta_frame_ready(netplay, ptr, netplay->input_frame_count)) return false; if (ptr->have_local) @@ -118,7 +118,7 @@ static bool get_self_input_state(netplay_t *netplay) return true; } - if (!input_driver_is_libretro_input_blocked() && netplay->self_frame_count > 0) + if (!input_driver_is_libretro_input_blocked() && netplay->input_frame_count > 0) { /* First frame we always give zero input since relying on * input from first frame screws up when we use -F 0. */ @@ -205,7 +205,7 @@ static bool netplay_poll(void) netplay_update_unread_ptr(netplay_data); if (netplay_data->stateless_mode && netplay_data->connected_players && - netplay_data->unread_frame_count <= netplay_data->self_frame_count) + netplay_data->unread_frame_count <= netplay_data->run_frame_count) res = netplay_poll_net_input(netplay_data, true); else res = netplay_poll_net_input(netplay_data, false); @@ -218,16 +218,16 @@ static bool netplay_poll(void) } /* Simulate the input if we don't have real input */ - netplay_simulate_input(netplay_data, netplay_data->self_ptr, false); + netplay_simulate_input(netplay_data, netplay_data->run_ptr, false); - /* Consider stalling */ + /* If we're stalled, consider unstalling */ switch (netplay_data->stall) { case NETPLAY_STALL_RUNNING_FAST: { netplay_update_unread_ptr(netplay_data); if (netplay_data->unread_frame_count + NETPLAY_MAX_STALL_FRAMES - 2 - > netplay_data->self_frame_count) + > netplay_data->input_frame_count) { netplay_data->stall = NETPLAY_STALL_NONE; for (i = 0; i < netplay_data->connections_size; i++) @@ -240,6 +240,11 @@ static bool netplay_poll(void) break; } + case NETPLAY_STALL_INPUT_LATENCY: + /* Just let it recalculate momentarily */ + netplay_data->stall = NETPLAY_STALL_NONE; + break; + case NETPLAY_STALL_SERVER_REQUESTED: { /* See if the stall is done */ @@ -261,38 +266,50 @@ static bool netplay_poll(void) break; default: /* not stalling */ - { - /* Are we too far ahead? */ - netplay_update_unread_ptr(netplay_data); - if (netplay_data->unread_frame_count + NETPLAY_MAX_STALL_FRAMES - <= netplay_data->self_frame_count) - { - netplay_data->stall = NETPLAY_STALL_RUNNING_FAST; - netplay_data->stall_time = cpu_features_get_time_usec(); + break; + } - /* Figure out who to blame */ - if (netplay_data->is_server) + /* If we're not stalled, consider stalling */ + if (!netplay_data->stall) + { + netplay_update_unread_ptr(netplay_data); + + /* Have we not reat enough latency frames? */ + if (netplay_data->run_frame_count + NETPLAY_INPUT_LATENCY_FRAMES > netplay_data->input_frame_count) + { + netplay_data->stall = NETPLAY_STALL_INPUT_LATENCY; + netplay_data->stall_time = 0; + } + + /* Are we too far ahead? */ + if (netplay_data->unread_frame_count + NETPLAY_MAX_STALL_FRAMES + <= netplay_data->input_frame_count) + { + netplay_data->stall = NETPLAY_STALL_RUNNING_FAST; + netplay_data->stall_time = cpu_features_get_time_usec(); + + /* Figure out who to blame */ + if (netplay_data->is_server) + { + for (player = 0; player < MAX_USERS; player++) { - for (player = 0; player < MAX_USERS; player++) + if (!(netplay_data->connected_players & (1<read_frame_count[player] > netplay_data->unread_frame_count) continue; + for (i = 0; i < netplay_data->connections_size; i++) { - if (!(netplay_data->connected_players & (1<read_frame_count[player] > netplay_data->unread_frame_count) continue; - for (i = 0; i < netplay_data->connections_size; i++) + struct netplay_connection *connection = &netplay_data->connections[i]; + if (connection->active && + connection->mode == NETPLAY_CONNECTION_PLAYING && + connection->player == player) { - struct netplay_connection *connection = &netplay_data->connections[i]; - if (connection->active && - connection->mode == NETPLAY_CONNECTION_PLAYING && - connection->player == player) - { - connection->stall = NETPLAY_STALL_RUNNING_FAST; - connection->stall_time = netplay_data->stall_time; - break; - } + connection->stall = NETPLAY_STALL_RUNNING_FAST; + connection->stall_time = netplay_data->stall_time; + break; } } } - } + } } @@ -371,7 +388,7 @@ static int16_t netplay_input_state(netplay_t *netplay, unsigned idx, unsigned id) { size_t ptr = netplay->is_replay ? - netplay->replay_ptr : netplay->self_ptr; + netplay->replay_ptr : netplay->run_ptr; const uint32_t *curr_input_state = NULL; @@ -492,7 +509,7 @@ static void netplay_flip_users(netplay_t *netplay) { /* Must be in the future because we may have * already sent this frame's data */ - uint32_t flip_frame = netplay->self_frame_count + 1; + uint32_t flip_frame = netplay->input_frame_count + 1; uint32_t flip_frame_net = htonl(flip_frame); size_t i; @@ -688,7 +705,7 @@ void netplay_send_savestate(netplay_t *netplay, /* Send it to relevant peers */ header[0] = htonl(NETPLAY_CMD_LOAD_SAVESTATE); header[1] = htonl(wn + 2*sizeof(uint32_t)); - header[2] = htonl(netplay->self_frame_count); + header[2] = htonl(netplay->run_frame_count); header[3] = htonl(serial_info->size); for (i = 0; i < netplay->connections_size; i++) @@ -721,16 +738,21 @@ void netplay_load_savestate(netplay_t *netplay, { retro_ctx_serialize_info_t tmp_serial_info; + /* Wherever we're inputting, that's where we consider our state to be loaded + * (FIXME: Need to be more careful about saving it?) */ + netplay->run_ptr = netplay->input_ptr; + netplay->run_frame_count = netplay->input_frame_count; + /* Record it in our own buffer */ if (save || !serial_info) { if (netplay_delta_frame_ready(netplay, - &netplay->buffer[netplay->self_ptr], netplay->self_frame_count)) + &netplay->buffer[netplay->run_ptr], netplay->run_frame_count)) { if (!serial_info) { tmp_serial_info.size = netplay->state_size; - tmp_serial_info.data = netplay->buffer[netplay->self_ptr].state; + tmp_serial_info.data = netplay->buffer[netplay->run_ptr].state; if (!core_serialize(&tmp_serial_info)) return; tmp_serial_info.data_const = tmp_serial_info.data; @@ -740,7 +762,7 @@ void netplay_load_savestate(netplay_t *netplay, { if (serial_info->size <= netplay->state_size) { - memcpy(netplay->buffer[netplay->self_ptr].state, + memcpy(netplay->buffer[netplay->run_ptr].state, serial_info->data_const, serial_info->size); } } @@ -755,29 +777,29 @@ void netplay_load_savestate(netplay_t *netplay, /* We need to ignore any intervening data from the other side, * and never rewind past this */ netplay_update_unread_ptr(netplay); - if (netplay->unread_frame_count < netplay->self_frame_count) + if (netplay->unread_frame_count < netplay->run_frame_count) { uint32_t player; for (player = 0; player < MAX_USERS; player++) { if (!(netplay->connected_players & (1<read_frame_count[player] < netplay->self_frame_count) + if (netplay->read_frame_count[player] < netplay->run_frame_count) { - netplay->read_ptr[player] = netplay->self_ptr; - netplay->read_frame_count[player] = netplay->self_frame_count; + netplay->read_ptr[player] = netplay->run_ptr; + netplay->read_frame_count[player] = netplay->run_frame_count; } } - if (netplay->server_frame_count < netplay->self_frame_count) + if (netplay->server_frame_count < netplay->run_frame_count) { - netplay->server_ptr = netplay->self_ptr; - netplay->server_frame_count = netplay->self_frame_count; + netplay->server_ptr = netplay->run_ptr; + netplay->server_frame_count = netplay->run_frame_count; } netplay_update_unread_ptr(netplay); } - if (netplay->other_frame_count < netplay->self_frame_count) + if (netplay->other_frame_count < netplay->run_frame_count) { - netplay->other_ptr = netplay->self_ptr; - netplay->other_frame_count = netplay->self_frame_count; + netplay->other_ptr = netplay->run_ptr; + netplay->other_frame_count = netplay->run_frame_count; } /* If we can't send it to the peer, loading a state was a bad idea */ @@ -807,7 +829,7 @@ static void netplay_toggle_play_spectate(netplay_t *netplay) uint32_t payload[2]; char msg[512]; const char *dmsg = NULL; - payload[0] = htonl(netplay->self_frame_count); + payload[0] = htonl(netplay->input_frame_count); if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING) { /* Mark us as no longer playing */ diff --git a/network/netplay/netplay_handshake.c b/network/netplay/netplay_handshake.c index 3731dc220d..64d20a89a1 100644 --- a/network/netplay/netplay_handshake.c +++ b/network/netplay/netplay_handshake.c @@ -518,7 +518,7 @@ bool netplay_handshake_sync(netplay_t *netplay, struct netplay_connection *conne cmd[0] = htonl(NETPLAY_CMD_SYNC); cmd[1] = htonl(3*sizeof(uint32_t) + MAX_USERS*sizeof(uint32_t) + NETPLAY_NICK_LEN + mem_info.size); - cmd[2] = htonl(netplay->self_frame_count); + cmd[2] = htonl(netplay->input_frame_count); connected_players = netplay->connected_players; if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING) connected_players |= 1<self_player; @@ -904,22 +904,23 @@ bool netplay_handshake_pre_sync(netplay_t *netplay, netplay->flip_frame = flip_frame; /* Set our frame counters as requested */ - netplay->self_frame_count = netplay->other_frame_count = - netplay->unread_frame_count = netplay->server_frame_count = - new_frame_count; + netplay->input_frame_count = netplay->run_frame_count = + netplay->other_frame_count = netplay->unread_frame_count = + netplay->server_frame_count = new_frame_count; for (i = 0; i < netplay->buffer_size; i++) { struct delta_frame *ptr = &netplay->buffer[i]; ptr->used = false; - if (i == netplay->self_ptr) + if (i == netplay->input_ptr) { /* Clear out any current data but still use this frame */ if (!netplay_delta_frame_ready(netplay, ptr, 0)) return false; ptr->frame = new_frame_count; ptr->have_local = true; - netplay->other_ptr = netplay->unread_ptr = netplay->server_ptr = i; + netplay->run_ptr = netplay->other_ptr = netplay->unread_ptr = + netplay->server_ptr = i; } } @@ -927,8 +928,8 @@ bool netplay_handshake_pre_sync(netplay_t *netplay, { if (connected_players & (1<read_ptr[i] = netplay->self_ptr; - netplay->read_frame_count[i] = netplay->self_frame_count; + netplay->read_ptr[i] = netplay->input_ptr; + netplay->read_frame_count[i] = netplay->input_frame_count; } } diff --git a/network/netplay/netplay_init.c b/network/netplay/netplay_init.c index 89a77b95d9..e96d72178b 100644 --- a/network/netplay/netplay_init.c +++ b/network/netplay/netplay_init.c @@ -321,7 +321,7 @@ bool netplay_try_init_serialization(netplay_t *netplay) /* Check if we can actually save */ serial_info.data_const = NULL; - serial_info.data = netplay->buffer[netplay->self_ptr].state; + serial_info.data = netplay->buffer[netplay->run_ptr].state; serial_info.size = netplay->state_size; if (!core_serialize(&serial_info)) diff --git a/network/netplay/netplay_io.c b/network/netplay/netplay_io.c index 0fbb748fdd..6cb7568b64 100644 --- a/network/netplay/netplay_io.c +++ b/network/netplay/netplay_io.c @@ -38,7 +38,7 @@ static void print_state(netplay_t *netplay) #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)); + APPEND((M, "NETPLAY: S:%u U:%u O:%u", netplay->input_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++) @@ -204,7 +204,7 @@ static bool send_input_frame(netplay_t *netplay, bool netplay_send_cur_input(netplay_t *netplay, struct netplay_connection *connection) { - struct delta_frame *dframe = &netplay->buffer[netplay->self_ptr]; + struct delta_frame *dframe = &netplay->buffer[netplay->input_ptr]; uint32_t player; if (netplay->is_server) @@ -220,7 +220,7 @@ bool netplay_send_cur_input(netplay_t *netplay, if (dframe->have_real[player]) { if (!send_input_frame(netplay, connection, NULL, - netplay->self_frame_count, player, + netplay->input_frame_count, player, dframe->real_input_state[player])) return false; } @@ -230,7 +230,7 @@ bool netplay_send_cur_input(netplay_t *netplay, /* If we're not playing, send a NOINPUT */ if (netplay->self_mode != NETPLAY_CONNECTION_PLAYING) { - uint32_t payload = htonl(netplay->self_frame_count); + uint32_t payload = htonl(netplay->input_frame_count); if (!netplay_send_raw_cmd(netplay, connection, NETPLAY_CMD_NOINPUT, &payload, sizeof(payload))) return false; @@ -242,7 +242,7 @@ bool netplay_send_cur_input(netplay_t *netplay, if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING) { if (!send_input_frame(netplay, connection, NULL, - netplay->self_frame_count, + netplay->input_frame_count, (netplay->is_server ? NETPLAY_CMD_INPUT_BIT_SERVER : 0) | netplay->self_player, dframe->self_state)) return false; @@ -505,7 +505,7 @@ static bool netplay_get_cmd(netplay_t *netplay, if (netplay->is_server) { /* Forward it on if it's past data*/ - if (dframe->frame <= netplay->self_frame_count) + if (dframe->frame <= netplay->input_frame_count) send_input_frame(netplay, NULL, connection, buffer[0], player, dframe->real_input_state[player]); } @@ -585,7 +585,7 @@ static bool netplay_get_cmd(netplay_t *netplay, /* Force a rewind to assure the flip happens: This just prevents us * from skipping other past the flip because our prediction was * correct */ - if (flip_frame < netplay->self_frame_count) + if (flip_frame < netplay->input_frame_count) netplay->force_rewind = true; RARCH_LOG("%s.\n", msg_hash_to_str(MSG_NETPLAY_USERS_HAS_FLIPPED)); @@ -638,7 +638,7 @@ static bool netplay_get_cmd(netplay_t *netplay, { uint32_t payload[2]; uint32_t player = 0; - payload[0] = htonl(netplay->self_frame_count + 1); + payload[0] = htonl(netplay->input_frame_count + 1); if (!netplay->is_server) { @@ -695,8 +695,8 @@ static bool netplay_get_cmd(netplay_t *netplay, netplay_send_raw_cmd(netplay, connection, NETPLAY_CMD_MODE, payload, sizeof(payload)); /* And expect their data */ - netplay->read_ptr[player] = NEXT_PTR(netplay->self_ptr); - netplay->read_frame_count[player] = netplay->self_frame_count + 1; + netplay->read_ptr[player] = NEXT_PTR(netplay->input_ptr); + netplay->read_frame_count[player] = netplay->input_frame_count + 1; break; } @@ -734,7 +734,7 @@ static bool netplay_get_cmd(netplay_t *netplay, frame = ntohl(payload[0]); /* We're changing past input, so must replay it */ - if (frame < netplay->self_frame_count) + if (frame < netplay->input_frame_count) netplay->force_rewind = true; mode = ntohl(payload[1]); @@ -767,16 +767,16 @@ static bool netplay_get_cmd(netplay_t *netplay, netplay->self_player = player; /* Fix up current frame info */ - if (frame <= netplay->self_frame_count) + if (frame <= netplay->input_frame_count) { /* It wanted past frames, better send 'em! */ START(netplay->server_ptr); - while (dframe->used && dframe->frame <= netplay->self_frame_count) + while (dframe->used && dframe->frame <= netplay->input_frame_count) { memcpy(dframe->real_input_state[player], dframe->self_state, sizeof(dframe->self_state)); dframe->have_real[player] = true; send_input_frame(netplay, connection, NULL, dframe->frame, player, dframe->self_state); - if (dframe->frame == netplay->self_frame_count) break; + if (dframe->frame == netplay->input_frame_count) break; NEXT(); } @@ -786,8 +786,8 @@ static bool netplay_get_cmd(netplay_t *netplay, uint32_t frame_count; /* It wants future frames, make sure we don't capture or send intermediate ones */ - START(netplay->self_ptr); - frame_count = netplay->self_frame_count; + START(netplay->input_ptr); + frame_count = netplay->input_frame_count; while (true) { if (!dframe->used) @@ -954,7 +954,7 @@ static bool netplay_get_cmd(netplay_t *netplay, case NETPLAY_CMD_CRC: { uint32_t buffer[2]; - size_t tmp_ptr = netplay->self_ptr; + size_t tmp_ptr = netplay->input_ptr; bool found = false; if (cmd_size != sizeof(buffer)) @@ -985,7 +985,7 @@ static bool netplay_get_cmd(netplay_t *netplay, } tmp_ptr = PREV_PTR(tmp_ptr); - } while (tmp_ptr != netplay->self_ptr); + } while (tmp_ptr != netplay->input_ptr); if (!found) { @@ -1035,8 +1035,8 @@ static bool netplay_get_cmd(netplay_t *netplay, if (!netplay->is_replay) { netplay->is_replay = true; - netplay->replay_ptr = netplay->self_ptr; - netplay->replay_frame_count = netplay->self_frame_count; + netplay->replay_ptr = netplay->run_ptr; + netplay->replay_frame_count = netplay->run_frame_count; netplay_wait_and_init_serialization(netplay); netplay->is_replay = false; } @@ -1134,15 +1134,20 @@ static bool netplay_get_cmd(netplay_t *netplay, true, &rd, &wn, NULL); /* Skip ahead if it's past where we are */ - if (frame > netplay->self_frame_count) + if (frame > netplay->run_frame_count) { /* This is squirrely: We need to assure that when we advance the * frame in post_frame, THEN we're referring to the frame to * load into. If we refer directly to read_ptr, then we'll end * up never reading the input for read_frame_count itself, which * will make the other side unhappy. */ - netplay->self_ptr = PREV_PTR(netplay->read_ptr[connection->player]); - netplay->self_frame_count = frame - 1; + netplay->run_ptr = PREV_PTR(netplay->read_ptr[connection->player]); + netplay->run_frame_count = frame - 1; + if (frame > netplay->input_frame_count) + { + netplay->input_ptr = netplay->run_ptr; + netplay->input_frame_count = netplay->run_frame_count; + } } /* Don't expect earlier data from other clients */ @@ -1308,7 +1313,7 @@ int netplay_poll_net_input(netplay_t *netplay, bool block) netplay_update_unread_ptr(netplay); /* If we were blocked for input, pass if we have this frame's input */ - if (netplay->unread_frame_count > netplay->self_frame_count) + if (netplay->unread_frame_count > netplay->run_frame_count) break; /* If we're supposed to block but we didn't have enough input, wait for it */ @@ -1330,7 +1335,7 @@ int netplay_poll_net_input(netplay_t *netplay, bool block) return -1; RARCH_LOG("Network is stalling at frame %u, count %u of %d ...\n", - netplay->self_frame_count, netplay->timeout_cnt, MAX_RETRIES); + netplay->run_frame_count, netplay->timeout_cnt, MAX_RETRIES); if (netplay->timeout_cnt >= MAX_RETRIES && !netplay->remote_paused) return -1; @@ -1348,7 +1353,7 @@ int netplay_poll_net_input(netplay_t *netplay, bool block) */ bool netplay_flip_port(netplay_t *netplay) { - size_t frame = netplay->self_frame_count; + size_t frame = netplay->input_frame_count; if (netplay->flip_frame == 0) return false; diff --git a/network/netplay/netplay_private.h b/network/netplay/netplay_private.h index 02a7377d98..e899052e71 100644 --- a/network/netplay/netplay_private.h +++ b/network/netplay/netplay_private.h @@ -50,6 +50,9 @@ #define NETPLAY_MAX_REQ_STALL_TIME 60 #define NETPLAY_MAX_REQ_STALL_FREQUENCY 120 +/* TEMPORARY */ +#define NETPLAY_INPUT_LATENCY_FRAMES 5 + #define PREV_PTR(x) ((x) == 0 ? netplay->buffer_size - 1 : (x) - 1) #define NEXT_PTR(x) ((x + 1) % netplay->buffer_size) @@ -210,6 +213,7 @@ enum rarch_netplay_stall_reason { NETPLAY_STALL_NONE = 0, NETPLAY_STALL_RUNNING_FAST, + NETPLAY_STALL_INPUT_LATENCY, NETPLAY_STALL_SERVER_REQUESTED, NETPLAY_STALL_NO_CONNECTION }; @@ -357,9 +361,13 @@ struct netplay /* The size of our packet buffers */ size_t packet_buffer_size; - /* The current frame seen by the frontend */ - size_t self_ptr; - uint32_t self_frame_count; + /* The frame we're currently inputting */ + size_t input_ptr; + uint32_t input_frame_count; + + /* The frame we're currently running */ + size_t run_ptr; + uint32_t run_frame_count; /* The first frame at which some data might be unreliable */ size_t other_ptr; diff --git a/network/netplay/netplay_sync.c b/network/netplay/netplay_sync.c index 9735f12133..ad88eb94a8 100644 --- a/network/netplay/netplay_sync.c +++ b/network/netplay/netplay_sync.c @@ -42,8 +42,8 @@ void netplay_update_unread_ptr(netplay_t *netplay) if (netplay->is_server && !netplay->connected_players) { /* Nothing at all to read! */ - netplay->unread_ptr = netplay->self_ptr; - netplay->unread_frame_count = netplay->self_frame_count; + netplay->unread_ptr = netplay->input_ptr; + netplay->unread_frame_count = netplay->input_frame_count; } else @@ -186,14 +186,14 @@ bool netplay_sync_pre_frame(netplay_t *netplay) { retro_ctx_serialize_info_t serial_info; - if (netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->self_ptr], netplay->self_frame_count)) + if (netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->run_ptr], netplay->run_frame_count)) { serial_info.data_const = NULL; - serial_info.data = netplay->buffer[netplay->self_ptr].state; + serial_info.data = netplay->buffer[netplay->run_ptr].state; serial_info.size = netplay->state_size; memset(serial_info.data, 0, serial_info.size); - if ((netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) || netplay->self_frame_count == 0) + if ((netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) || netplay->run_frame_count == 0) { /* Don't serialize until it's safe */ } @@ -201,8 +201,19 @@ bool netplay_sync_pre_frame(netplay_t *netplay) { if (netplay->force_send_savestate && !netplay->stall && !netplay->remote_paused) { + /* Bring our running frame and input frames into parity so we don't + * send old info */ + if (netplay->run_ptr != netplay->input_ptr) + { + memcpy(netplay->buffer[netplay->input_ptr].state, + netplay->buffer[netplay->run_ptr].state, + netplay->state_size); + netplay->run_ptr = netplay->input_ptr; + netplay->run_frame_count = netplay->input_frame_count; + } + /* Send this along to the other side */ - serial_info.data_const = netplay->buffer[netplay->self_ptr].state; + serial_info.data_const = netplay->buffer[netplay->run_ptr].state; netplay_load_savestate(netplay, &serial_info, false); netplay->force_send_savestate = false; } @@ -216,7 +227,7 @@ bool netplay_sync_pre_frame(netplay_t *netplay) } /* If we can't transmit savestates, we must stall until the client is ready */ - if (netplay->self_frame_count > 0 && + if (netplay->run_frame_count > 0 && (netplay->quirks & (NETPLAY_QUIRK_NO_SAVESTATES|NETPLAY_QUIRK_NO_TRANSMISSION)) && (netplay->connections_size == 0 || !netplay->connections[0].active || netplay->connections[0].mode < NETPLAY_CONNECTION_CONNECTED)) @@ -357,16 +368,24 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled) /* 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++; + netplay->run_ptr = NEXT_PTR(netplay->run_ptr); + netplay->run_frame_count++; + } + + /* We've finished an input frame even if we're stalling, unless we're too + * far ahead of ourselves */ + if (netplay->input_frame_count < netplay->run_frame_count + NETPLAY_INPUT_LATENCY_FRAMES) + { + netplay->input_ptr = NEXT_PTR(netplay->input_ptr); + netplay->input_frame_count++; } /* Only relevant if we're connected */ if ((netplay->is_server && !netplay->connected_players) || (netplay->self_mode < NETPLAY_CONNECTION_CONNECTED)) { - netplay->other_frame_count = netplay->self_frame_count; - netplay->other_ptr = netplay->self_ptr; + netplay->other_frame_count = netplay->input_frame_count; + netplay->other_ptr = netplay->input_ptr; /* FIXME: Duplication */ if (netplay->catch_up) { @@ -383,7 +402,7 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled) /* Skip ahead if we predicted correctly. * Skip until our simulation failed. */ while (netplay->other_frame_count < netplay->unread_frame_count && - netplay->other_frame_count < netplay->self_frame_count) + netplay->other_frame_count < netplay->run_frame_count) { struct delta_frame *ptr = &netplay->buffer[netplay->other_ptr]; size_t i; @@ -406,7 +425,7 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled) /* Now replay the real input if we've gotten ahead of it */ if (netplay->force_rewind || (netplay->other_frame_count < netplay->unread_frame_count && - netplay->other_frame_count < netplay->self_frame_count)) + netplay->other_frame_count < netplay->run_frame_count)) { retro_ctx_serialize_info_t serial_info; @@ -428,7 +447,7 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled) RARCH_ERR("Netplay savestate loading failed: Prepare for desync!\n"); } - while (netplay->replay_frame_count < netplay->self_frame_count) + while (netplay->replay_frame_count < netplay->run_frame_count) { retro_time_t start, tm; @@ -483,15 +502,15 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled) /* Average our time */ netplay->frame_run_time_avg = netplay->frame_run_time_sum / NETPLAY_FRAME_RUN_TIME_WINDOW; - if (netplay->unread_frame_count < netplay->self_frame_count) + if (netplay->unread_frame_count < netplay->run_frame_count) { netplay->other_ptr = netplay->unread_ptr; netplay->other_frame_count = netplay->unread_frame_count; } else { - netplay->other_ptr = netplay->self_ptr; - netplay->other_frame_count = netplay->self_frame_count; + netplay->other_ptr = netplay->run_ptr; + netplay->other_frame_count = netplay->run_frame_count; } netplay->is_replay = false; netplay->force_rewind = false; @@ -520,7 +539,7 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled) if (netplay->catch_up) { /* Are we caught up? */ - if (netplay->self_frame_count >= lo_frame_count) + if (netplay->input_frame_count >= lo_frame_count) { netplay->catch_up = false; input_driver_unset_nonblock_state(); @@ -530,7 +549,7 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled) } else if (!stalled) { - if (netplay->self_frame_count + 2 < lo_frame_count) + if (netplay->input_frame_count + 2 < lo_frame_count) { /* Are we falling behind? */ netplay->catch_up = true; @@ -538,7 +557,7 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled) driver_set_nonblock_state(); } - else if (netplay->self_frame_count + 2 < hi_frame_count) + else if (netplay->input_frame_count + 2 < hi_frame_count) { size_t i; @@ -554,16 +573,16 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled) player = connection->player; /* Are they ahead? */ - if (netplay->self_frame_count + 2 < netplay->read_frame_count[player]) + if (netplay->input_frame_count + 2 < netplay->read_frame_count[player]) { /* Tell them to stall */ if (connection->stall_frame + NETPLAY_MAX_REQ_STALL_FREQUENCY < - netplay->self_frame_count) + netplay->input_frame_count) { - connection->stall_frame = netplay->self_frame_count; + connection->stall_frame = netplay->input_frame_count; netplay_cmd_stall(netplay, connection, netplay->read_frame_count[player] - - netplay->self_frame_count + 1); + netplay->input_frame_count + 1); } } }