mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-25 17:10:12 +00:00
Bugfixes to bring Netplay Nouveau from "kinda working" to "stably
working": (1) Fixups to the stall logic to make sure it always receives frames while stalling :) (2) Disused the used_real field. It was misconfigured and would frequently claim to be using real data when real data hadn't been used... this means more replays for now, but used_real will be readded. (TODO) (3) Stall duration is now related to sync frames, and thus configurable. (4) Delta frames were having the good ol' initialization problem, as frame==0 was indistinguishable from unused. Quickfixed by adding a "used" field, but maybe there's a better way. (5) If serialization fails, switch immediately to blocking mode (stall_frames = 0). Blocking mode barely works, but if serialization fails, no mode will work! (6) I'm not sure which bug my replaying-from-previous-frame was trying to fix, but the correct behavior is to replay from the last frame we had vital information, not the frame prior. Notionally this should just be an efficiency thing, but unsigned arithmetic at 0 made this a "just ignore all input from now on" thing.
This commit is contained in:
parent
07e869ccae
commit
c7d0bf90f6
@ -143,7 +143,7 @@ static bool send_chunk(netplay_t *netplay)
|
||||
**/
|
||||
static bool get_self_input_state(netplay_t *netplay)
|
||||
{
|
||||
uint32_t state[WORDS_PER_FRAME - 1] = {0};
|
||||
uint32_t state[WORDS_PER_FRAME - 1] = {0, 0, 0};
|
||||
struct delta_frame *ptr = &netplay->buffer[netplay->self_ptr];
|
||||
|
||||
if (!netplay_delta_frame_ready(netplay, ptr, netplay->self_frame_count))
|
||||
@ -261,9 +261,9 @@ static bool netplay_get_cmd(netplay_t *netplay)
|
||||
uint32_t flip_frame;
|
||||
uint32_t cmd_size;
|
||||
|
||||
/* If we're not ready for input, wait until we are. Could fill the TCP buffer, stalling the other side. */
|
||||
if (!netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->read_ptr], netplay->read_frame_count))
|
||||
return false;
|
||||
/* FIXME: This depends on delta_frame_ready */
|
||||
|
||||
netplay->timeout_cnt = 0;
|
||||
|
||||
if (!socket_receive_all_blocking(netplay->fd, &cmd, sizeof(cmd)))
|
||||
return false;
|
||||
@ -314,7 +314,6 @@ static bool netplay_get_cmd(netplay_t *netplay)
|
||||
memcpy(netplay->buffer[netplay->read_ptr].real_input_state, buffer + 1, sizeof(buffer) - sizeof(uint32_t));
|
||||
netplay->read_ptr = NEXT_PTR(netplay->read_ptr);
|
||||
netplay->read_frame_count++;
|
||||
netplay->timeout_cnt = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -409,9 +408,13 @@ static int poll_input(netplay_t *netplay, bool block)
|
||||
* but we aren't using the TCP connection for anything useful atm. */
|
||||
if (FD_ISSET(netplay->fd, &fds))
|
||||
{
|
||||
had_input = true;
|
||||
if (!netplay_get_cmd(netplay))
|
||||
return -1;
|
||||
/* If we're not ready for input, wait until we are. Could fill the TCP buffer, stalling the other side. */
|
||||
if (netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->read_ptr], netplay->read_frame_count))
|
||||
{
|
||||
had_input = true;
|
||||
if (!netplay_get_cmd(netplay))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
@ -431,9 +434,9 @@ static int poll_input(netplay_t *netplay, bool block)
|
||||
}
|
||||
#endif
|
||||
|
||||
RARCH_LOG("Network is stalling, resending packet... Count %u of %d ...\n",
|
||||
netplay->timeout_cnt, MAX_RETRIES);
|
||||
} while (had_input);
|
||||
RARCH_LOG("Network is stalling at frame %u, count %u of %d ...\n",
|
||||
netplay->self_frame_count, netplay->timeout_cnt, MAX_RETRIES);
|
||||
} while (had_input || (block && (netplay->read_frame_count <= netplay->self_frame_count)));
|
||||
|
||||
/*if (block)
|
||||
return -1;*/
|
||||
@ -521,9 +524,13 @@ static bool netplay_poll(netplay_t *netplay)
|
||||
|
||||
netplay->can_poll = false;
|
||||
|
||||
#if 0
|
||||
if (!get_self_input_state(netplay))
|
||||
return false;
|
||||
#endif
|
||||
get_self_input_state(netplay);
|
||||
|
||||
#if 0
|
||||
/* We skip reading the first frame so the host has a chance to grab
|
||||
* our host info so we don't block forever :') */
|
||||
if (netplay->self_frame_count == 0)
|
||||
@ -538,9 +545,11 @@ static bool netplay_poll(netplay_t *netplay)
|
||||
netplay->read_frame_count++;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Read Netplay input */
|
||||
res = poll_input(netplay, 0); /* FIXME: configure stalling intervals */
|
||||
/* Read Netplay input, block if we're configured to stall for input every
|
||||
* frame */
|
||||
res = poll_input(netplay, netplay->stall_frames == 0);
|
||||
if (res == -1)
|
||||
{
|
||||
netplay->has_connection = false;
|
||||
@ -580,8 +589,8 @@ static bool netplay_poll(netplay_t *netplay)
|
||||
|
||||
if (netplay->read_frame_count < netplay->self_frame_count)
|
||||
simulate_input(netplay);
|
||||
else
|
||||
netplay->buffer[PREV_PTR(netplay->self_ptr)].used_real = true;
|
||||
/*else
|
||||
netplay->buffer[PREV_PTR(netplay->self_ptr)].used_real = true;*/
|
||||
|
||||
/* Consider stalling */
|
||||
switch (netplay->stall) {
|
||||
@ -591,7 +600,7 @@ static bool netplay_poll(netplay_t *netplay)
|
||||
break;
|
||||
|
||||
default: /* not stalling */
|
||||
if (netplay->read_frame_count < netplay->self_frame_count - 10)
|
||||
if (netplay->read_frame_count + netplay->stall_frames <= netplay->self_frame_count)
|
||||
netplay->stall = RARCH_NETPLAY_STALL_RUNNING_FAST;
|
||||
}
|
||||
|
||||
@ -774,6 +783,9 @@ static int init_tcp_connection(const struct addrinfo *res,
|
||||
{
|
||||
bool ret = true;
|
||||
int fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
int flag = 1;
|
||||
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int));
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
@ -937,11 +949,9 @@ netplay_t *netplay_new(const char *server, uint16_t port,
|
||||
bool spectate,
|
||||
const char *nick)
|
||||
{
|
||||
uint32_t buffer_frames;
|
||||
netplay_t *netplay = NULL;
|
||||
|
||||
/*if (frames > UDP_FRAME_PACKETS)
|
||||
frames = UDP_FRAME_PACKETS;*/
|
||||
|
||||
netplay = (netplay_t*)calloc(1, sizeof(*netplay));
|
||||
if (!netplay)
|
||||
return NULL;
|
||||
@ -953,6 +963,7 @@ netplay_t *netplay_new(const char *server, uint16_t port,
|
||||
netplay->spectate.enabled = spectate;
|
||||
netplay->is_server = server == NULL;
|
||||
strlcpy(netplay->nick, nick, sizeof(netplay->nick));
|
||||
netplay->stall_frames = frames;
|
||||
|
||||
if(spectate)
|
||||
netplay->net_cbs = netplay_get_cbs_spectate();
|
||||
|
@ -348,14 +348,18 @@ bool netplay_is_spectate(netplay_t* netplay)
|
||||
bool netplay_delta_frame_ready(netplay_t *netplay, struct delta_frame *delta, uint32_t frame)
|
||||
{
|
||||
void *remember_state;
|
||||
if (delta->frame == frame) return true;
|
||||
if (netplay->other_frame_count <= delta->frame)
|
||||
if (delta->used)
|
||||
{
|
||||
/* We haven't even replayed this frame yet, so we can't overwrite it! */
|
||||
return false;
|
||||
if (delta->frame == frame) return true;
|
||||
if (netplay->other_frame_count <= delta->frame)
|
||||
{
|
||||
/* We haven't even replayed this frame yet, so we can't overwrite it! */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
remember_state = delta->state;
|
||||
memset(delta, 0, sizeof(struct delta_frame));
|
||||
delta->used = true;
|
||||
delta->frame = frame;
|
||||
delta->state = remember_state;
|
||||
return true;
|
||||
|
@ -36,7 +36,12 @@ static void netplay_net_pre_frame(netplay_t *netplay)
|
||||
serial_info.data = netplay->buffer[netplay->self_ptr].state;
|
||||
serial_info.size = netplay->state_size;
|
||||
|
||||
core_serialize(&serial_info);
|
||||
if (!core_serialize(&serial_info))
|
||||
{
|
||||
/* If the core can't serialize properly, we must stall for the
|
||||
* remote input on EVERY frame, because we can't recover */
|
||||
netplay->stall_frames = 0;
|
||||
}
|
||||
}
|
||||
|
||||
netplay->can_poll = true;
|
||||
@ -55,9 +60,11 @@ static void netplay_net_post_frame(netplay_t *netplay)
|
||||
{
|
||||
netplay->self_frame_count++;
|
||||
|
||||
#if 0
|
||||
/* Nothing to do... */
|
||||
if (netplay->other_frame_count == netplay->read_frame_count)
|
||||
return;
|
||||
#endif
|
||||
|
||||
/* Skip ahead if we predicted correctly.
|
||||
* Skip until our simulation failed. */
|
||||
@ -80,8 +87,8 @@ static void netplay_net_post_frame(netplay_t *netplay)
|
||||
|
||||
/* Replay frames. */
|
||||
netplay->is_replay = true;
|
||||
netplay->replay_ptr = PREV_PTR(netplay->other_ptr);
|
||||
netplay->replay_frame_count = netplay->other_frame_count - 1;
|
||||
netplay->replay_ptr = netplay->other_ptr;
|
||||
netplay->replay_frame_count = netplay->other_frame_count;
|
||||
|
||||
if (netplay->replay_frame_count < netplay->self_frame_count)
|
||||
{
|
||||
@ -114,7 +121,7 @@ static void netplay_net_post_frame(netplay_t *netplay)
|
||||
/* For the remainder of the frames up to the read count, we can use the real data */
|
||||
while (netplay->replay_frame_count < netplay->read_frame_count)
|
||||
{
|
||||
netplay->buffer[netplay->replay_ptr].used_real = true;
|
||||
/*netplay->buffer[netplay->replay_ptr].used_real = true;*/
|
||||
netplay->replay_ptr = NEXT_PTR(netplay->replay_ptr);
|
||||
netplay->replay_frame_count++;
|
||||
}
|
||||
@ -222,7 +229,11 @@ static bool netplay_net_info_cb(netplay_t* netplay, unsigned frames)
|
||||
return false;
|
||||
}
|
||||
|
||||
netplay->buffer_size = frames + 1;
|
||||
/* * 2 + 1 because:
|
||||
* Self sits in the middle,
|
||||
* Other is allowed to drift as much as 'frames' frames behind
|
||||
* Read is allowed to drift as much as 'frames' frames ahead */
|
||||
netplay->buffer_size = frames * 2 + 1;
|
||||
|
||||
if (!netplay_net_init_buffers(netplay))
|
||||
return false;
|
||||
|
@ -41,6 +41,7 @@
|
||||
|
||||
struct delta_frame
|
||||
{
|
||||
bool used; /* a bit derpy, but this is how we know if the delta's been used at all */
|
||||
uint32_t frame;
|
||||
|
||||
void *state;
|
||||
@ -143,6 +144,7 @@ struct netplay
|
||||
uint32_t pause_frame;
|
||||
|
||||
/* And stalling */
|
||||
uint32_t stall_frames;
|
||||
int stall;
|
||||
|
||||
struct netplay_callbacks* net_cbs;
|
||||
|
Loading…
Reference in New Issue
Block a user