New approach to input latency
This commit is contained in:
parent
2b3343a687
commit
c4cb94db19
|
@ -106,10 +106,10 @@ static bool netplay_can_poll(netplay_t *netplay)
|
||||||
static bool get_self_input_state(netplay_t *netplay)
|
static bool get_self_input_state(netplay_t *netplay)
|
||||||
{
|
{
|
||||||
uint32_t state[WORDS_PER_INPUT] = {0, 0, 0};
|
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;
|
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;
|
return false;
|
||||||
|
|
||||||
if (ptr->have_local)
|
if (ptr->have_local)
|
||||||
|
@ -118,7 +118,7 @@ static bool get_self_input_state(netplay_t *netplay)
|
||||||
return true;
|
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
|
/* First frame we always give zero input since relying on
|
||||||
* input from first frame screws up when we use -F 0. */
|
* 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);
|
netplay_update_unread_ptr(netplay_data);
|
||||||
if (netplay_data->stateless_mode &&
|
if (netplay_data->stateless_mode &&
|
||||||
netplay_data->connected_players &&
|
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);
|
res = netplay_poll_net_input(netplay_data, true);
|
||||||
else
|
else
|
||||||
res = netplay_poll_net_input(netplay_data, false);
|
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 */
|
/* 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)
|
switch (netplay_data->stall)
|
||||||
{
|
{
|
||||||
case NETPLAY_STALL_RUNNING_FAST:
|
case NETPLAY_STALL_RUNNING_FAST:
|
||||||
{
|
{
|
||||||
netplay_update_unread_ptr(netplay_data);
|
netplay_update_unread_ptr(netplay_data);
|
||||||
if (netplay_data->unread_frame_count + NETPLAY_MAX_STALL_FRAMES - 2
|
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;
|
netplay_data->stall = NETPLAY_STALL_NONE;
|
||||||
for (i = 0; i < netplay_data->connections_size; i++)
|
for (i = 0; i < netplay_data->connections_size; i++)
|
||||||
|
@ -240,6 +240,11 @@ static bool netplay_poll(void)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case NETPLAY_STALL_INPUT_LATENCY:
|
||||||
|
/* Just let it recalculate momentarily */
|
||||||
|
netplay_data->stall = NETPLAY_STALL_NONE;
|
||||||
|
break;
|
||||||
|
|
||||||
case NETPLAY_STALL_SERVER_REQUESTED:
|
case NETPLAY_STALL_SERVER_REQUESTED:
|
||||||
{
|
{
|
||||||
/* See if the stall is done */
|
/* See if the stall is done */
|
||||||
|
@ -261,11 +266,24 @@ static bool netplay_poll(void)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: /* not stalling */
|
default: /* not stalling */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we're not stalled, consider stalling */
|
||||||
|
if (!netplay_data->stall)
|
||||||
{
|
{
|
||||||
/* Are we too far ahead? */
|
|
||||||
netplay_update_unread_ptr(netplay_data);
|
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
|
if (netplay_data->unread_frame_count + NETPLAY_MAX_STALL_FRAMES
|
||||||
<= netplay_data->self_frame_count)
|
<= netplay_data->input_frame_count)
|
||||||
{
|
{
|
||||||
netplay_data->stall = NETPLAY_STALL_RUNNING_FAST;
|
netplay_data->stall = NETPLAY_STALL_RUNNING_FAST;
|
||||||
netplay_data->stall_time = cpu_features_get_time_usec();
|
netplay_data->stall_time = cpu_features_get_time_usec();
|
||||||
|
@ -294,7 +312,6 @@ static bool netplay_poll(void)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* If we're stalling, consider disconnection */
|
/* If we're stalling, consider disconnection */
|
||||||
if (netplay_data->stall && netplay_data->stall_time)
|
if (netplay_data->stall && netplay_data->stall_time)
|
||||||
|
@ -371,7 +388,7 @@ static int16_t netplay_input_state(netplay_t *netplay,
|
||||||
unsigned idx, unsigned id)
|
unsigned idx, unsigned id)
|
||||||
{
|
{
|
||||||
size_t ptr = netplay->is_replay ?
|
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;
|
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
|
/* Must be in the future because we may have
|
||||||
* already sent this frame's data */
|
* 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);
|
uint32_t flip_frame_net = htonl(flip_frame);
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
@ -688,7 +705,7 @@ void netplay_send_savestate(netplay_t *netplay,
|
||||||
/* Send it to relevant peers */
|
/* Send it to relevant peers */
|
||||||
header[0] = htonl(NETPLAY_CMD_LOAD_SAVESTATE);
|
header[0] = htonl(NETPLAY_CMD_LOAD_SAVESTATE);
|
||||||
header[1] = htonl(wn + 2*sizeof(uint32_t));
|
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);
|
header[3] = htonl(serial_info->size);
|
||||||
|
|
||||||
for (i = 0; i < netplay->connections_size; i++)
|
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;
|
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 */
|
/* Record it in our own buffer */
|
||||||
if (save || !serial_info)
|
if (save || !serial_info)
|
||||||
{
|
{
|
||||||
if (netplay_delta_frame_ready(netplay,
|
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)
|
if (!serial_info)
|
||||||
{
|
{
|
||||||
tmp_serial_info.size = netplay->state_size;
|
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))
|
if (!core_serialize(&tmp_serial_info))
|
||||||
return;
|
return;
|
||||||
tmp_serial_info.data_const = tmp_serial_info.data;
|
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)
|
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);
|
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,
|
/* We need to ignore any intervening data from the other side,
|
||||||
* and never rewind past this */
|
* and never rewind past this */
|
||||||
netplay_update_unread_ptr(netplay);
|
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;
|
uint32_t player;
|
||||||
for (player = 0; player < MAX_USERS; player++)
|
for (player = 0; player < MAX_USERS; player++)
|
||||||
{
|
{
|
||||||
if (!(netplay->connected_players & (1<<player))) continue;
|
if (!(netplay->connected_players & (1<<player))) continue;
|
||||||
if (netplay->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_ptr[player] = netplay->run_ptr;
|
||||||
netplay->read_frame_count[player] = netplay->self_frame_count;
|
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_ptr = netplay->run_ptr;
|
||||||
netplay->server_frame_count = netplay->self_frame_count;
|
netplay->server_frame_count = netplay->run_frame_count;
|
||||||
}
|
}
|
||||||
netplay_update_unread_ptr(netplay);
|
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_ptr = netplay->run_ptr;
|
||||||
netplay->other_frame_count = netplay->self_frame_count;
|
netplay->other_frame_count = netplay->run_frame_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we can't send it to the peer, loading a state was a bad idea */
|
/* 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];
|
uint32_t payload[2];
|
||||||
char msg[512];
|
char msg[512];
|
||||||
const char *dmsg = NULL;
|
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)
|
if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING)
|
||||||
{
|
{
|
||||||
/* Mark us as no longer playing */
|
/* Mark us as no longer playing */
|
||||||
|
|
|
@ -518,7 +518,7 @@ bool netplay_handshake_sync(netplay_t *netplay, struct netplay_connection *conne
|
||||||
cmd[0] = htonl(NETPLAY_CMD_SYNC);
|
cmd[0] = htonl(NETPLAY_CMD_SYNC);
|
||||||
cmd[1] = htonl(3*sizeof(uint32_t) + MAX_USERS*sizeof(uint32_t) +
|
cmd[1] = htonl(3*sizeof(uint32_t) + MAX_USERS*sizeof(uint32_t) +
|
||||||
NETPLAY_NICK_LEN + mem_info.size);
|
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;
|
connected_players = netplay->connected_players;
|
||||||
if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING)
|
if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING)
|
||||||
connected_players |= 1<<netplay->self_player;
|
connected_players |= 1<<netplay->self_player;
|
||||||
|
@ -904,22 +904,23 @@ bool netplay_handshake_pre_sync(netplay_t *netplay,
|
||||||
netplay->flip_frame = flip_frame;
|
netplay->flip_frame = flip_frame;
|
||||||
|
|
||||||
/* Set our frame counters as requested */
|
/* Set our frame counters as requested */
|
||||||
netplay->self_frame_count = netplay->other_frame_count =
|
netplay->input_frame_count = netplay->run_frame_count =
|
||||||
netplay->unread_frame_count = netplay->server_frame_count =
|
netplay->other_frame_count = netplay->unread_frame_count =
|
||||||
new_frame_count;
|
netplay->server_frame_count = new_frame_count;
|
||||||
for (i = 0; i < netplay->buffer_size; i++)
|
for (i = 0; i < netplay->buffer_size; i++)
|
||||||
{
|
{
|
||||||
struct delta_frame *ptr = &netplay->buffer[i];
|
struct delta_frame *ptr = &netplay->buffer[i];
|
||||||
ptr->used = false;
|
ptr->used = false;
|
||||||
|
|
||||||
if (i == netplay->self_ptr)
|
if (i == netplay->input_ptr)
|
||||||
{
|
{
|
||||||
/* Clear out any current data but still use this frame */
|
/* Clear out any current data but still use this frame */
|
||||||
if (!netplay_delta_frame_ready(netplay, ptr, 0))
|
if (!netplay_delta_frame_ready(netplay, ptr, 0))
|
||||||
return false;
|
return false;
|
||||||
ptr->frame = new_frame_count;
|
ptr->frame = new_frame_count;
|
||||||
ptr->have_local = true;
|
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<<i))
|
if (connected_players & (1<<i))
|
||||||
{
|
{
|
||||||
netplay->read_ptr[i] = netplay->self_ptr;
|
netplay->read_ptr[i] = netplay->input_ptr;
|
||||||
netplay->read_frame_count[i] = netplay->self_frame_count;
|
netplay->read_frame_count[i] = netplay->input_frame_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -321,7 +321,7 @@ bool netplay_try_init_serialization(netplay_t *netplay)
|
||||||
|
|
||||||
/* Check if we can actually save */
|
/* Check if we can actually save */
|
||||||
serial_info.data_const = NULL;
|
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;
|
serial_info.size = netplay->state_size;
|
||||||
|
|
||||||
if (!core_serialize(&serial_info))
|
if (!core_serialize(&serial_info))
|
||||||
|
|
|
@ -38,7 +38,7 @@ static void print_state(netplay_t *netplay)
|
||||||
#define APPEND(out) cur += snprintf out
|
#define APPEND(out) cur += snprintf out
|
||||||
#define M msg + cur, sizeof(msg) - cur
|
#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)
|
if (!netplay->is_server)
|
||||||
APPEND((M, " H:%u", netplay->server_frame_count));
|
APPEND((M, " H:%u", netplay->server_frame_count));
|
||||||
for (player = 0; player < MAX_USERS; player++)
|
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,
|
bool netplay_send_cur_input(netplay_t *netplay,
|
||||||
struct netplay_connection *connection)
|
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;
|
uint32_t player;
|
||||||
|
|
||||||
if (netplay->is_server)
|
if (netplay->is_server)
|
||||||
|
@ -220,7 +220,7 @@ bool netplay_send_cur_input(netplay_t *netplay,
|
||||||
if (dframe->have_real[player])
|
if (dframe->have_real[player])
|
||||||
{
|
{
|
||||||
if (!send_input_frame(netplay, connection, NULL,
|
if (!send_input_frame(netplay, connection, NULL,
|
||||||
netplay->self_frame_count, player,
|
netplay->input_frame_count, player,
|
||||||
dframe->real_input_state[player]))
|
dframe->real_input_state[player]))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -230,7 +230,7 @@ bool netplay_send_cur_input(netplay_t *netplay,
|
||||||
/* If we're not playing, send a NOINPUT */
|
/* If we're not playing, send a NOINPUT */
|
||||||
if (netplay->self_mode != NETPLAY_CONNECTION_PLAYING)
|
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,
|
if (!netplay_send_raw_cmd(netplay, connection, NETPLAY_CMD_NOINPUT,
|
||||||
&payload, sizeof(payload)))
|
&payload, sizeof(payload)))
|
||||||
return false;
|
return false;
|
||||||
|
@ -242,7 +242,7 @@ bool netplay_send_cur_input(netplay_t *netplay,
|
||||||
if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING)
|
if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING)
|
||||||
{
|
{
|
||||||
if (!send_input_frame(netplay, connection, NULL,
|
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,
|
(netplay->is_server ? NETPLAY_CMD_INPUT_BIT_SERVER : 0) | netplay->self_player,
|
||||||
dframe->self_state))
|
dframe->self_state))
|
||||||
return false;
|
return false;
|
||||||
|
@ -505,7 +505,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
if (netplay->is_server)
|
if (netplay->is_server)
|
||||||
{
|
{
|
||||||
/* Forward it on if it's past data*/
|
/* 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],
|
send_input_frame(netplay, NULL, connection, buffer[0],
|
||||||
player, dframe->real_input_state[player]);
|
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
|
/* Force a rewind to assure the flip happens: This just prevents us
|
||||||
* from skipping other past the flip because our prediction was
|
* from skipping other past the flip because our prediction was
|
||||||
* correct */
|
* correct */
|
||||||
if (flip_frame < netplay->self_frame_count)
|
if (flip_frame < netplay->input_frame_count)
|
||||||
netplay->force_rewind = true;
|
netplay->force_rewind = true;
|
||||||
|
|
||||||
RARCH_LOG("%s.\n", msg_hash_to_str(MSG_NETPLAY_USERS_HAS_FLIPPED));
|
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 payload[2];
|
||||||
uint32_t player = 0;
|
uint32_t player = 0;
|
||||||
payload[0] = htonl(netplay->self_frame_count + 1);
|
payload[0] = htonl(netplay->input_frame_count + 1);
|
||||||
|
|
||||||
if (!netplay->is_server)
|
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));
|
netplay_send_raw_cmd(netplay, connection, NETPLAY_CMD_MODE, payload, sizeof(payload));
|
||||||
|
|
||||||
/* And expect their data */
|
/* And expect their data */
|
||||||
netplay->read_ptr[player] = NEXT_PTR(netplay->self_ptr);
|
netplay->read_ptr[player] = NEXT_PTR(netplay->input_ptr);
|
||||||
netplay->read_frame_count[player] = netplay->self_frame_count + 1;
|
netplay->read_frame_count[player] = netplay->input_frame_count + 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -734,7 +734,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
frame = ntohl(payload[0]);
|
frame = ntohl(payload[0]);
|
||||||
|
|
||||||
/* We're changing past input, so must replay it */
|
/* 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;
|
netplay->force_rewind = true;
|
||||||
|
|
||||||
mode = ntohl(payload[1]);
|
mode = ntohl(payload[1]);
|
||||||
|
@ -767,16 +767,16 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
netplay->self_player = player;
|
netplay->self_player = player;
|
||||||
|
|
||||||
/* Fix up current frame info */
|
/* Fix up current frame info */
|
||||||
if (frame <= netplay->self_frame_count)
|
if (frame <= netplay->input_frame_count)
|
||||||
{
|
{
|
||||||
/* It wanted past frames, better send 'em! */
|
/* It wanted past frames, better send 'em! */
|
||||||
START(netplay->server_ptr);
|
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));
|
memcpy(dframe->real_input_state[player], dframe->self_state, sizeof(dframe->self_state));
|
||||||
dframe->have_real[player] = true;
|
dframe->have_real[player] = true;
|
||||||
send_input_frame(netplay, connection, NULL, dframe->frame, player, dframe->self_state);
|
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();
|
NEXT();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -786,8 +786,8 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
uint32_t frame_count;
|
uint32_t frame_count;
|
||||||
|
|
||||||
/* It wants future frames, make sure we don't capture or send intermediate ones */
|
/* It wants future frames, make sure we don't capture or send intermediate ones */
|
||||||
START(netplay->self_ptr);
|
START(netplay->input_ptr);
|
||||||
frame_count = netplay->self_frame_count;
|
frame_count = netplay->input_frame_count;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (!dframe->used)
|
if (!dframe->used)
|
||||||
|
@ -954,7 +954,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
case NETPLAY_CMD_CRC:
|
case NETPLAY_CMD_CRC:
|
||||||
{
|
{
|
||||||
uint32_t buffer[2];
|
uint32_t buffer[2];
|
||||||
size_t tmp_ptr = netplay->self_ptr;
|
size_t tmp_ptr = netplay->input_ptr;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
if (cmd_size != sizeof(buffer))
|
if (cmd_size != sizeof(buffer))
|
||||||
|
@ -985,7 +985,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp_ptr = PREV_PTR(tmp_ptr);
|
tmp_ptr = PREV_PTR(tmp_ptr);
|
||||||
} while (tmp_ptr != netplay->self_ptr);
|
} while (tmp_ptr != netplay->input_ptr);
|
||||||
|
|
||||||
if (!found)
|
if (!found)
|
||||||
{
|
{
|
||||||
|
@ -1035,8 +1035,8 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
if (!netplay->is_replay)
|
if (!netplay->is_replay)
|
||||||
{
|
{
|
||||||
netplay->is_replay = true;
|
netplay->is_replay = true;
|
||||||
netplay->replay_ptr = netplay->self_ptr;
|
netplay->replay_ptr = netplay->run_ptr;
|
||||||
netplay->replay_frame_count = netplay->self_frame_count;
|
netplay->replay_frame_count = netplay->run_frame_count;
|
||||||
netplay_wait_and_init_serialization(netplay);
|
netplay_wait_and_init_serialization(netplay);
|
||||||
netplay->is_replay = false;
|
netplay->is_replay = false;
|
||||||
}
|
}
|
||||||
|
@ -1134,15 +1134,20 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
true, &rd, &wn, NULL);
|
true, &rd, &wn, NULL);
|
||||||
|
|
||||||
/* Skip ahead if it's past where we are */
|
/* 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
|
/* This is squirrely: We need to assure that when we advance the
|
||||||
* frame in post_frame, THEN we're referring to the frame to
|
* 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
|
* load into. If we refer directly to read_ptr, then we'll end
|
||||||
* up never reading the input for read_frame_count itself, which
|
* up never reading the input for read_frame_count itself, which
|
||||||
* will make the other side unhappy. */
|
* will make the other side unhappy. */
|
||||||
netplay->self_ptr = PREV_PTR(netplay->read_ptr[connection->player]);
|
netplay->run_ptr = PREV_PTR(netplay->read_ptr[connection->player]);
|
||||||
netplay->self_frame_count = frame - 1;
|
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 */
|
/* 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);
|
netplay_update_unread_ptr(netplay);
|
||||||
|
|
||||||
/* If we were blocked for input, pass if we have this frame's input */
|
/* 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;
|
break;
|
||||||
|
|
||||||
/* If we're supposed to block but we didn't have enough input, wait for it */
|
/* 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;
|
return -1;
|
||||||
|
|
||||||
RARCH_LOG("Network is stalling at frame %u, count %u of %d ...\n",
|
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)
|
if (netplay->timeout_cnt >= MAX_RETRIES && !netplay->remote_paused)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1348,7 +1353,7 @@ int netplay_poll_net_input(netplay_t *netplay, bool block)
|
||||||
*/
|
*/
|
||||||
bool netplay_flip_port(netplay_t *netplay)
|
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)
|
if (netplay->flip_frame == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -50,6 +50,9 @@
|
||||||
#define NETPLAY_MAX_REQ_STALL_TIME 60
|
#define NETPLAY_MAX_REQ_STALL_TIME 60
|
||||||
#define NETPLAY_MAX_REQ_STALL_FREQUENCY 120
|
#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 PREV_PTR(x) ((x) == 0 ? netplay->buffer_size - 1 : (x) - 1)
|
||||||
#define NEXT_PTR(x) ((x + 1) % netplay->buffer_size)
|
#define NEXT_PTR(x) ((x + 1) % netplay->buffer_size)
|
||||||
|
|
||||||
|
@ -210,6 +213,7 @@ enum rarch_netplay_stall_reason
|
||||||
{
|
{
|
||||||
NETPLAY_STALL_NONE = 0,
|
NETPLAY_STALL_NONE = 0,
|
||||||
NETPLAY_STALL_RUNNING_FAST,
|
NETPLAY_STALL_RUNNING_FAST,
|
||||||
|
NETPLAY_STALL_INPUT_LATENCY,
|
||||||
NETPLAY_STALL_SERVER_REQUESTED,
|
NETPLAY_STALL_SERVER_REQUESTED,
|
||||||
NETPLAY_STALL_NO_CONNECTION
|
NETPLAY_STALL_NO_CONNECTION
|
||||||
};
|
};
|
||||||
|
@ -357,9 +361,13 @@ struct netplay
|
||||||
/* The size of our packet buffers */
|
/* The size of our packet buffers */
|
||||||
size_t packet_buffer_size;
|
size_t packet_buffer_size;
|
||||||
|
|
||||||
/* The current frame seen by the frontend */
|
/* The frame we're currently inputting */
|
||||||
size_t self_ptr;
|
size_t input_ptr;
|
||||||
uint32_t self_frame_count;
|
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 */
|
/* The first frame at which some data might be unreliable */
|
||||||
size_t other_ptr;
|
size_t other_ptr;
|
||||||
|
|
|
@ -42,8 +42,8 @@ void netplay_update_unread_ptr(netplay_t *netplay)
|
||||||
if (netplay->is_server && !netplay->connected_players)
|
if (netplay->is_server && !netplay->connected_players)
|
||||||
{
|
{
|
||||||
/* Nothing at all to read! */
|
/* Nothing at all to read! */
|
||||||
netplay->unread_ptr = netplay->self_ptr;
|
netplay->unread_ptr = netplay->input_ptr;
|
||||||
netplay->unread_frame_count = netplay->self_frame_count;
|
netplay->unread_frame_count = netplay->input_frame_count;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -186,14 +186,14 @@ bool netplay_sync_pre_frame(netplay_t *netplay)
|
||||||
{
|
{
|
||||||
retro_ctx_serialize_info_t serial_info;
|
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_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;
|
serial_info.size = netplay->state_size;
|
||||||
|
|
||||||
memset(serial_info.data, 0, serial_info.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 */
|
/* 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)
|
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 */
|
/* 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_load_savestate(netplay, &serial_info, false);
|
||||||
netplay->force_send_savestate = 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 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->quirks & (NETPLAY_QUIRK_NO_SAVESTATES|NETPLAY_QUIRK_NO_TRANSMISSION)) &&
|
||||||
(netplay->connections_size == 0 || !netplay->connections[0].active ||
|
(netplay->connections_size == 0 || !netplay->connections[0].active ||
|
||||||
netplay->connections[0].mode < NETPLAY_CONNECTION_CONNECTED))
|
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 */
|
/* Unless we're stalling, we've just finished running a frame */
|
||||||
if (!stalled)
|
if (!stalled)
|
||||||
{
|
{
|
||||||
netplay->self_ptr = NEXT_PTR(netplay->self_ptr);
|
netplay->run_ptr = NEXT_PTR(netplay->run_ptr);
|
||||||
netplay->self_frame_count++;
|
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 */
|
/* Only relevant if we're connected */
|
||||||
if ((netplay->is_server && !netplay->connected_players) ||
|
if ((netplay->is_server && !netplay->connected_players) ||
|
||||||
(netplay->self_mode < NETPLAY_CONNECTION_CONNECTED))
|
(netplay->self_mode < NETPLAY_CONNECTION_CONNECTED))
|
||||||
{
|
{
|
||||||
netplay->other_frame_count = netplay->self_frame_count;
|
netplay->other_frame_count = netplay->input_frame_count;
|
||||||
netplay->other_ptr = netplay->self_ptr;
|
netplay->other_ptr = netplay->input_ptr;
|
||||||
/* FIXME: Duplication */
|
/* FIXME: Duplication */
|
||||||
if (netplay->catch_up)
|
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 ahead if we predicted correctly.
|
||||||
* Skip until our simulation failed. */
|
* Skip until our simulation failed. */
|
||||||
while (netplay->other_frame_count < netplay->unread_frame_count &&
|
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];
|
struct delta_frame *ptr = &netplay->buffer[netplay->other_ptr];
|
||||||
size_t i;
|
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 */
|
/* Now replay the real input if we've gotten ahead of it */
|
||||||
if (netplay->force_rewind ||
|
if (netplay->force_rewind ||
|
||||||
(netplay->other_frame_count < netplay->unread_frame_count &&
|
(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;
|
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");
|
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;
|
retro_time_t start, tm;
|
||||||
|
|
||||||
|
@ -483,15 +502,15 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
|
||||||
/* Average our time */
|
/* Average our time */
|
||||||
netplay->frame_run_time_avg = netplay->frame_run_time_sum / NETPLAY_FRAME_RUN_TIME_WINDOW;
|
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_ptr = netplay->unread_ptr;
|
||||||
netplay->other_frame_count = netplay->unread_frame_count;
|
netplay->other_frame_count = netplay->unread_frame_count;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
netplay->other_ptr = netplay->self_ptr;
|
netplay->other_ptr = netplay->run_ptr;
|
||||||
netplay->other_frame_count = netplay->self_frame_count;
|
netplay->other_frame_count = netplay->run_frame_count;
|
||||||
}
|
}
|
||||||
netplay->is_replay = false;
|
netplay->is_replay = false;
|
||||||
netplay->force_rewind = false;
|
netplay->force_rewind = false;
|
||||||
|
@ -520,7 +539,7 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
|
||||||
if (netplay->catch_up)
|
if (netplay->catch_up)
|
||||||
{
|
{
|
||||||
/* Are we caught 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;
|
netplay->catch_up = false;
|
||||||
input_driver_unset_nonblock_state();
|
input_driver_unset_nonblock_state();
|
||||||
|
@ -530,7 +549,7 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
|
||||||
}
|
}
|
||||||
else if (!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? */
|
/* Are we falling behind? */
|
||||||
netplay->catch_up = true;
|
netplay->catch_up = true;
|
||||||
|
@ -538,7 +557,7 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
|
||||||
driver_set_nonblock_state();
|
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;
|
size_t i;
|
||||||
|
|
||||||
|
@ -554,16 +573,16 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
|
||||||
player = connection->player;
|
player = connection->player;
|
||||||
|
|
||||||
/* Are they ahead? */
|
/* 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 */
|
/* Tell them to stall */
|
||||||
if (connection->stall_frame + NETPLAY_MAX_REQ_STALL_FREQUENCY <
|
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_cmd_stall(netplay, connection,
|
||||||
netplay->read_frame_count[player] -
|
netplay->read_frame_count[player] -
|
||||||
netplay->self_frame_count + 1);
|
netplay->input_frame_count + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue