diff --git a/network/netplay/README b/network/netplay/README index a31fafe553..b73c7b5550 100644 --- a/network/netplay/README +++ b/network/netplay/README @@ -159,18 +159,16 @@ Command: INPUT Payload: { frame number: uint32 - is server data: 1 bit - client number: 31 bits + client number: 32 bits joypad input: uint32 analog 1 input: uint32 analog 2 input: uint32 } Description: Input state for each frame. Netplay must send an INPUT command for every - frame in order to function at all. Client's player value is ignored. Server - indicates which frames are its own input data because INPUT is a - synchronization point: No synchronization events from the given frame may - arrive after the server's input for the frame. + frame in order to function at all. When sent from the server (client 0), + INPUT is a synchronization point: No synchronization events from the given + frame may arrive after the server's input for the frame. Command: NOINPUT Payload: diff --git a/network/netplay/netplay_delta.c b/network/netplay/netplay_delta.c index eabeb70f5f..2309d4b78d 100644 --- a/network/netplay/netplay_delta.c +++ b/network/netplay/netplay_delta.c @@ -23,6 +23,15 @@ #include "netplay_private.h" +static void clear_input(netplay_input_state_t istate) +{ + while (istate) + { + istate->used = false; + istate = istate->next; + } +} + /** * netplay_delta_frame_ready * @@ -35,7 +44,7 @@ bool netplay_delta_frame_ready(netplay_t *netplay, struct delta_frame *delta, uint32_t frame) { - void *remember_state; + size_t i; if (delta->used) { if (delta->frame == frame) return true; @@ -45,11 +54,21 @@ bool netplay_delta_frame_ready(netplay_t *netplay, struct delta_frame *delta, return false; } } - remember_state = delta->state; - memset(delta, 0, sizeof(struct delta_frame)); delta->used = true; delta->frame = frame; - delta->state = remember_state; + delta->crc = 0; + for (i = 0; i < MAX_INPUT_DEVICES; i++) + { + clear_input(delta->resolved_input[i]); + clear_input(delta->real_input[i]); + clear_input(delta->simulated_input[i]); + } + delta->have_local = false; + for (i = 0; i < MAX_CLIENTS; i++) + { + delta->have_real[i] = false; + delta->used_real[i] = false; + } return true; } @@ -64,3 +83,98 @@ uint32_t netplay_delta_frame_crc(netplay_t *netplay, struct delta_frame *delta) return 0; return encoding_crc32(0L, (const unsigned char*)delta->state, netplay->state_size); } + +/* + * Free an input state list + */ +static void free_input_state(netplay_input_state_t *list) +{ + netplay_input_state_t cur, next; + cur = *list; + while (cur) + { + next = cur->next; + free(cur); + cur = next; + } + *list = NULL; +} + +/** + * netplay_delta_frame_free + * + * Free a delta frame's dependencies + */ +void netplay_delta_frame_free(struct delta_frame *delta) +{ + uint32_t i; + + if (delta->state) + { + free(delta->state); + delta->state = NULL; + } + + for (i = 0; i < MAX_INPUT_DEVICES; i++) + { + free_input_state(&delta->resolved_input[i]); + free_input_state(&delta->real_input[i]); + free_input_state(&delta->simulated_input[i]); + } +} + +/** + * netplay_input_state_for + * + * Get an input state for a particular client + */ +netplay_input_state_t netplay_input_state_for(netplay_input_state_t *list, + uint32_t client_num, size_t size, bool must_create) +{ + netplay_input_state_t ret; + while (*list) + { + ret = *list; + if (!ret->used && ret->size == size) + { + ret->client_num = client_num; + ret->used = true; + memset(ret->data, 0, size*sizeof(uint32_t)); + return ret; + } + else if (ret->used && ret->client_num == client_num) + { + if (!must_create && ret->size == size) + return ret; + return NULL; + } + list = &(ret->next); + } + + /* Couldn't find a slot, allocate a fresh one */ + ret = calloc(1, sizeof(struct netplay_input_state) + (size-1) * sizeof(uint32_t)); + if (!ret) + return NULL; + *list = ret; + ret->client_num = client_num; + ret->used = true; + ret->size = size; + return ret; +} + +/** + * netplay_expected_input_size + * + * Size in words for a given set of devices. + */ +uint32_t netplay_expected_input_size(uint32_t devices) +{ + /* FIXME: For now, we assume all devices are three words, because in the implementation, they are. */ + uint32_t ret = 0; + while (devices) + { + if (devices & 1) ret += 3; + devices >>= 1; + } + return ret; +} diff --git a/network/netplay/netplay_frontend.c b/network/netplay/netplay_frontend.c index fa305e03e8..1a30025b9c 100644 --- a/network/netplay/netplay_frontend.c +++ b/network/netplay/netplay_frontend.c @@ -71,7 +71,7 @@ static bool netplay_is_alive(void) { if (!netplay_data) return false; - return (netplay_data->is_server && (netplay_data->connected_players1>1)) || + return (netplay_data->is_server) || (!netplay_data->is_server && netplay_data->self_mode >= NETPLAY_CONNECTION_CONNECTED); } @@ -232,8 +232,8 @@ static bool netplay_poll(void) if (res == -1) goto catastrophe; - /* Simulate the input if we don't have real input */ - netplay_simulate_input(netplay_data, netplay_data->run_ptr, false); + /* Resolve and/or simulate the input if we don't have real input */ + netplay_resolve_input(netplay_data, netplay_data->run_ptr, false); /* Handle any slaves */ if (netplay_data->is_server && netplay_data->connected_slaves1) @@ -499,7 +499,7 @@ static int16_t netplay_input_state(netplay_t *netplay, /* FIXME: Mixing */ delta = &netplay->buffer[ptr]; istate = delta->real_input[port]; - if (istate && istate->is_real) + if (istate && istate->used) delta->used_real[port] = true; else istate = delta->simulated_input[port]; @@ -1172,8 +1172,8 @@ static void netplay_toggle_play_spectate(netplay_t *netplay) payload[2] = htonl(1<self_mode = NETPLAY_CONNECTION_PLAYING; netplay->connected_players1 |= 1; - netplay->client_devices[0] = (1<device_clients[device] = netplay->self_devices = 1; + netplay->client_devices[0] = netplay->self_devices = (1<device_clients[device] = 1; dmsg = msg; msg[sizeof(msg)-1] = '\0'; @@ -1317,7 +1317,13 @@ bool init_netplay(void *direct_host, const char *server, unsigned port) if (netplay_data) { if (netplay_data->is_server && !settings->bools.netplay_start_as_spectator) + { netplay_data->self_mode = NETPLAY_CONNECTION_PLAYING; + netplay_data->self_devices = 1; + netplay_data->client_devices[0] = 1; + netplay_data->device_clients[0] = 1; + netplay_data->connected_players1 = 1; + } return true; } diff --git a/network/netplay/netplay_handshake.c b/network/netplay/netplay_handshake.c index 00cca88ce5..3afd776b9d 100644 --- a/network/netplay/netplay_handshake.c +++ b/network/netplay/netplay_handshake.c @@ -1012,6 +1012,7 @@ bool netplay_handshake_pre_sync(netplay_t *netplay, RECV(&device, sizeof(device)) return false; device = ntohl(device); + fprintf(stderr, "Device %d: %d\n", (int) i, (int) device); netplay->device_clients[i] = device; netplay->connected_players1 |= device; diff --git a/network/netplay/netplay_init.c b/network/netplay/netplay_init.c index d19373e9df..899ff7a23a 100644 --- a/network/netplay/netplay_init.c +++ b/network/netplay/netplay_init.c @@ -183,12 +183,8 @@ static bool init_tcp_socket(netplay_t *netplay, void *direct_host, while (tmp_info) { - struct sockaddr_storage sad; - int fd; - - memset(&sad, 0, sizeof(sad)); - - fd = init_tcp_connection( + struct sockaddr_storage sad = {0}; + int fd = init_tcp_connection( tmp_info, direct_host || server, (struct sockaddr*)&sad, @@ -538,8 +534,7 @@ void netplay_free(netplay_t *netplay) if (netplay->buffer) { for (i = 0; i < netplay->buffer_size; i++) - if (netplay->buffer[i].state) - free(netplay->buffer[i].state); + netplay_delta_frame_free(&netplay->buffer[i]); free(netplay->buffer); } diff --git a/network/netplay/netplay_io.c b/network/netplay/netplay_io.c index 0c77ba0b42..87d3cbcb0a 100644 --- a/network/netplay/netplay_io.c +++ b/network/netplay/netplay_io.c @@ -28,14 +28,14 @@ #include "../../retroarch.h" #include "../../tasks/tasks_internal.h" -#if 0 +#if 1 #define DEBUG_NETPLAY_STEPS 1 static void print_state(netplay_t *netplay) { char msg[512]; size_t cur = 0; - uint32_t player; + uint32_t client; #define APPEND(out) cur += snprintf out #define M msg + cur, sizeof(msg) - cur @@ -43,10 +43,10 @@ static void print_state(netplay_t *netplay) 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++) + for (client = 0; client < MAX_USERS; client++) { - if ((netplay->connected_players & (1<read_frame_count[player])); + if ((netplay->connected_players1 & (1<read_frame_count1[client])); } APPEND((M, "\n")); msg[sizeof(msg)-1] = '\0'; @@ -239,6 +239,10 @@ static bool send_input_frame(netplay_t *netplay, struct delta_frame *dframe, } buffer[1] = htonl((bufused-2) * sizeof(uint32_t)); +#ifdef DEBUG_NETPLAY_STEPS + RARCH_LOG("Sending input for client %u\n", (unsigned) client_num); +#endif + if (only) { if (!netplay_send(&only->send_packet_buffer, only->fd, buffer, bufused*sizeof(uint32_t))) @@ -279,12 +283,8 @@ static bool send_input_frame(netplay_t *netplay, struct delta_frame *dframe, bool netplay_send_cur_input(netplay_t *netplay, struct netplay_connection *connection) { -#define BUFSZ 16 - uint32_t buffer[BUFSZ]; - size_t bufused; struct delta_frame *dframe = &netplay->buffer[netplay->self_ptr]; uint32_t from_client, to_client; - uint32_t devices, device; size_t i; netplay_input_state_t istate; @@ -302,27 +302,7 @@ bool netplay_send_cur_input(netplay_t *netplay, { if (dframe->have_real[from_client]) { - bufused = 0; - devices = netplay->client_devices[from_client]; - for (device = 0; device < MAX_INPUT_DEVICES; device++) - { - if (!(devices & (1<real_input[device]; - while (istate && istate->client_num != from_client) - istate = istate->next; - if (!istate) - continue; - if (bufused + istate->size >= BUFSZ) - continue; - for (i = 0; i < istate->size; i++) - buffer[bufused+i] = istate->data[i]; - bufused += istate->size; - } - if (!send_input_frame(netplay, connection, NULL, - netplay->self_frame_count, from_client, bufused, buffer)) + if (!send_input_frame(netplay, dframe, connection, NULL, from_client)) return false; } } @@ -343,32 +323,10 @@ bool netplay_send_cur_input(netplay_t *netplay, if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING || netplay->self_mode == NETPLAY_CONNECTION_SLAVE) { - devices = netplay->self_devices; - bufused = 0; - for (device = 0; device < MAX_INPUT_DEVICES; device++) - { - if (!(devices & (1<real_input[device]; - while (istate && istate->client_num != netplay->self_client_num) - istate = istate->next; - if (!istate) - continue; - if (bufused + istate->size >= BUFSZ) - continue; - for (i = 0; i < istate->size; i++) - buffer[bufused+i] = istate->data[i]; - bufused += istate->size; - } - if (!send_input_frame(netplay, connection, NULL, - netplay->self_frame_count, - (netplay->is_server ? NETPLAY_CMD_INPUT_BIT_SERVER : 0) | netplay->self_client_num, - bufused, buffer)) + if (!send_input_frame(netplay, dframe, connection, NULL, + netplay->self_client_num)) return false; } -#undef BUFSZ if (!netplay_send_flush(&connection->send_packet_buffer, connection->fd, false)) @@ -589,7 +547,6 @@ static bool netplay_get_cmd(netplay_t *netplay, case NETPLAY_CMD_INPUT: { uint32_t frame_num, client_num, input_size, devices, device; - bool is_server; unsigned i; struct delta_frame *dframe; @@ -603,9 +560,8 @@ static bool netplay_get_cmd(netplay_t *netplay, return false; RECV(&client_num, sizeof(client_num)) return false; - frame_num = nhtohl(frame_num); + frame_num = ntohl(frame_num); client_num = ntohl(client_num); - is_server = (client_num & NETPLAY_CMD_INPUT_BIT_SERVER)?true:false; client_num &= 0xFFFF; if (netplay->is_server) @@ -617,13 +573,12 @@ static bool netplay_get_cmd(netplay_t *netplay, RARCH_ERR("Netplay input from non-participating player.\n"); return netplay_cmd_nak(netplay, connection); } - is_server = false; client_num = connection - netplay->connections + 1; } if (client_num > MAX_CLIENTS) { - RARCH_ERROR("NETPLAY_CMD_INPUT received data for an unsupported client.\n"); + RARCH_ERR("NETPLAY_CMD_INPUT received data for an unsupported client.\n"); return netplay_cmd_nak(netplay, connection); } @@ -682,7 +637,6 @@ static bool netplay_get_cmd(netplay_t *netplay, return false; for (di = 0; di < dsize; di++) istate->data[di] = ntohl(istate->data[di]); - istate->is_real = true; } dframe->have_real[client_num] = true; @@ -703,7 +657,7 @@ static bool netplay_get_cmd(netplay_t *netplay, } /* If this was server data, advance our server pointer too */ - if (is_server) + if (!netplay->is_server && client_num == 0) { netplay->server_ptr = netplay->read_ptr1[client_num]; netplay->server_frame_count = netplay->read_frame_count1[client_num]; @@ -957,7 +911,7 @@ static bool netplay_get_cmd(netplay_t *netplay, case NETPLAY_CMD_MODE: { uint32_t payload[3]; - uint32_t frame, mode, client_num, devices; + uint32_t frame, mode, client_num, devices, device; size_t ptr; struct delta_frame *dframe; @@ -1089,7 +1043,7 @@ static bool netplay_get_cmd(netplay_t *netplay, runloop_msg_queue_push(msg, 1, 180, false); #ifdef DEBUG_NETPLAY_STEPS - RARCH_LOG("Received mode change self->%u\n", player); + RARCH_LOG("Received mode change self->%X\n", devices); print_state(netplay); #endif @@ -1115,7 +1069,7 @@ static bool netplay_get_cmd(netplay_t *netplay, runloop_msg_queue_push(msg, 1, 180, false); #ifdef DEBUG_NETPLAY_STEPS - RARCH_LOG("Received mode change %u self->spectating\n", netplay->self_player); + RARCH_LOG("Received mode change self->spectating\n"); print_state(netplay); #endif @@ -1149,7 +1103,7 @@ static bool netplay_get_cmd(netplay_t *netplay, runloop_msg_queue_push(msg, 1, 180, false); #ifdef DEBUG_NETPLAY_STEPS - RARCH_LOG("Received mode change spectator->%u\n", player); + RARCH_LOG("Received mode change %u->%u\n", client_num, devices); print_state(netplay); #endif @@ -1168,7 +1122,7 @@ static bool netplay_get_cmd(netplay_t *netplay, runloop_msg_queue_push(msg, 1, 180, false); #ifdef DEBUG_NETPLAY_STEPS - RARCH_LOG("Received mode change %u->spectator\n", player); + RARCH_LOG("Received mode change %u->spectator\n", client_num); print_state(netplay); #endif @@ -1308,9 +1262,11 @@ static bool netplay_get_cmd(netplay_t *netplay, uint32_t frame; uint32_t isize; uint32_t rd, wn; - uint32_t player; + uint32_t client, client_num; struct compression_transcoder *ctrans; + client_num = connection - netplay->connections + 1; + /* Make sure we're ready for it */ if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION) { @@ -1371,14 +1327,14 @@ static bool netplay_get_cmd(netplay_t *netplay, } frame = ntohl(frame); - if ((netplay->is_server && frame != netplay->read_frame_count[connection->player]) || + if ((netplay->is_server && frame != netplay->read_frame_count1[client_num]) || (!netplay->is_server && frame != netplay->server_frame_count)) { RARCH_ERR("CMD_LOAD_SAVESTATE loading a state out of order!\n"); return netplay_cmd_nak(netplay, connection); } - if (!netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->read_ptr[connection->player]], frame)) + if (!netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->read_ptr1[client_num]], frame)) { /* Hopefully it will be after another round of input */ goto shrt; @@ -1418,7 +1374,7 @@ static bool netplay_get_cmd(netplay_t *netplay, ctrans->decompression_backend->set_in(ctrans->decompression_stream, netplay->zbuffer, cmd_size - 2*sizeof(uint32_t)); ctrans->decompression_backend->set_out(ctrans->decompression_stream, - (uint8_t*)netplay->buffer[netplay->read_ptr[connection->player]].state, + (uint8_t*)netplay->buffer[netplay->read_ptr1[client_num]].state, (unsigned)netplay->state_size); ctrans->decompression_backend->trans(ctrans->decompression_stream, true, &rd, &wn, NULL); @@ -1442,7 +1398,7 @@ static bool netplay_get_cmd(netplay_t *netplay, * 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->run_ptr = PREV_PTR(netplay->read_ptr[connection->player]); + netplay->run_ptr = PREV_PTR(netplay->read_ptr1[client_num]); netplay->run_frame_count = frame - 1; if (frame > netplay->self_frame_count) { @@ -1452,19 +1408,19 @@ static bool netplay_get_cmd(netplay_t *netplay, } /* Don't expect earlier data from other clients */ - for (player = 0; player < MAX_USERS; player++) + for (client = 0; client < MAX_CLIENTS; client++) { - if (!(netplay->connected_players & (1< netplay->read_frame_count[player]) + if (!(netplay->connected_players1 & (1< netplay->read_frame_count1[client]) { - netplay->read_ptr[player] = netplay->read_ptr[connection->player]; - netplay->read_frame_count[player] = frame; + netplay->read_ptr1[client] = netplay->read_ptr1[client_num]; + netplay->read_frame_count1[client] = frame; } } /* Make sure our states are correct */ netplay->savestate_request_outstanding = false; - netplay->other_ptr = netplay->read_ptr[connection->player]; + netplay->other_ptr = netplay->read_ptr1[client_num]; netplay->other_frame_count = frame; #ifdef DEBUG_NETPLAY_STEPS @@ -1660,7 +1616,7 @@ int netplay_poll_net_input(netplay_t *netplay, bool block) */ void netplay_handle_slaves(netplay_t *netplay) { - struct delta_frame *frame = &netplay->buffer[netplay->self_ptr]; + struct delta_frame *oframe, *frame = &netplay->buffer[netplay->self_ptr]; size_t i; for (i = 0; i < netplay->connections_size; i++) { @@ -1668,30 +1624,45 @@ void netplay_handle_slaves(netplay_t *netplay) if (connection->active && connection->mode == NETPLAY_CONNECTION_SLAVE) { - int player = connection->player; + uint32_t client_num = i + 1; + uint32_t devices, device; /* This is a slave connection. First, should we do anything at all? If * we've already "read" this data, then we can just ignore it */ - if (netplay->read_frame_count[player] > netplay->self_frame_count) + if (netplay->read_frame_count1[client_num] > netplay->self_frame_count) continue; /* Alright, we have to send something. Do we need to generate it first? */ - if (!frame->have_real[player]) + if (!frame->have_real[client_num]) { + devices = netplay->client_devices[client_num]; + /* Copy the previous frame's data */ - memcpy(frame->real_input_state[player], - netplay->buffer[PREV_PTR(netplay->self_ptr)].real_input_state[player], - WORDS_PER_INPUT*sizeof(uint32_t)); - frame->have_real[player] = true; + oframe = &netplay->buffer[PREV_PTR(netplay->self_ptr)]; + for (device = 0; device < MAX_INPUT_DEVICES; device++) + { + netplay_input_state_t istate_out, istate_in; + if (!(devices & (1<real_input[device]; + while (istate_in && istate_in->client_num != client_num) + istate_in = istate_in->next; + if (!istate_in) + continue; + istate_out = netplay_input_state_for(&frame->real_input[device], + client_num, istate_in->size, true); + memcpy(istate_out->data, istate_in->data, + istate_in->size * sizeof(uint32_t)); + } + frame->have_real[client_num] = true; } /* Send it along */ - send_input_frame(netplay, NULL, NULL, netplay->self_frame_count, - player, frame->real_input_state[player]); + send_input_frame(netplay, frame, NULL, connection, client_num); /* And mark it as "read" */ - netplay->read_ptr[player] = NEXT_PTR(netplay->self_ptr); - netplay->read_frame_count[player] = netplay->self_frame_count + 1; + netplay->read_ptr1[client_num] = NEXT_PTR(netplay->self_ptr); + netplay->read_frame_count1[client_num] = netplay->self_frame_count + 1; } } } diff --git a/network/netplay/netplay_private.h b/network/netplay/netplay_private.h index d58790c848..41473a26d0 100644 --- a/network/netplay/netplay_private.h +++ b/network/netplay/netplay_private.h @@ -183,7 +183,6 @@ enum netplay_cmd NETPLAY_CMD_CFG_ACK = 0x0062 }; -#define NETPLAY_CMD_INPUT_BIT_SERVER (1U<<31) #define NETPLAY_CMD_SYNC_BIT_PAUSED (1U<<31) #define NETPLAY_CMD_PLAY_BIT_SLAVE (1U<<31) #define NETPLAY_CMD_MODE_BIT_SLAVE (1U<<18) @@ -254,12 +253,12 @@ typedef struct netplay_input_state /* The next input state (forming a list) */ struct netplay_input_state *next; + /* Is this a buffer with real data? */ + bool used; + /* Whose data is this? */ uint32_t client_num; - /* Is this real data? */ - bool is_real; - /* How many words of input data do we have? */ uint32_t size; @@ -278,10 +277,9 @@ struct delta_frame /* The CRC-32 of the serialized state if we've calculated it, else 0 */ uint32_t crc; - /* The processed input, i.e., what's actually going to the core. is_real - * here means all input came from real players, none simulated. One list per - * input device. */ - netplay_input_state_t processed_input[MAX_INPUT_DEVICES]; + /* The resolved input, i.e., what's actually going to the core. One input + * per device. */ + netplay_input_state_t resolved_input[MAX_INPUT_DEVICES]; /* The real input */ netplay_input_state_t real_input[MAX_INPUT_DEVICES]; @@ -646,13 +644,27 @@ bool netplay_delta_frame_ready(netplay_t *netplay, struct delta_frame *delta, */ uint32_t netplay_delta_frame_crc(netplay_t *netplay, struct delta_frame *delta); +/** + * netplay_delta_frame_free + * + * Free a delta frame's dependencies + */ +void netplay_delta_frame_free(struct delta_frame *delta); + /** * netplay_input_state_for * * Get an input state for a particular client */ netplay_input_state_t netplay_input_state_for(netplay_input_state_t *list, - uint32_t client_num, size_t size, bool mustCreate); + uint32_t client_num, size_t size, bool must_create); + +/** + * netplay_expected_input_size + * + * Size in words for a given set of devices. + */ +uint32_t netplay_expected_input_size(uint32_t devices); /*************************************************************** @@ -897,15 +909,17 @@ void netplay_init_nat_traversal(netplay_t *netplay); void netplay_update_unread_ptr(netplay_t *netplay); /** - * netplay_simulate_input + * netplay_resolve_input * @netplay : pointer to netplay object - * @sim_ptr : frame index for which to simulate input + * @sim_ptr : frame pointer for which to resolve input * @resim : are we resimulating, or simulating this frame for the * first time? * * "Simulate" input by assuming it hasn't changed since the last read input. + * Returns true if the resolved input changed from the last time it was + * resolved. */ -void netplay_simulate_input(netplay_t *netplay, size_t sim_ptr, bool resim); +bool netplay_resolve_input(netplay_t *netplay, size_t sim_ptr, bool resim); /** * netplay_sync_pre_frame diff --git a/network/netplay/netplay_sync.c b/network/netplay/netplay_sync.c index fb88534a71..ab80ad3bcf 100644 --- a/network/netplay/netplay_sync.c +++ b/network/netplay/netplay_sync.c @@ -83,20 +83,24 @@ void netplay_update_unread_ptr(netplay_t *netplay) } /** - * netplay_simulate_input + * netplay_resolve_input * @netplay : pointer to netplay object - * @sim_ptr : frame index for which to simulate input + * @sim_ptr : frame pointer for which to resolve input * @resim : are we resimulating, or simulating this frame for the * first time? * * "Simulate" input by assuming it hasn't changed since the last read input. + * Returns true if the resolved input changed from the last time it was + * resolved. */ -void netplay_simulate_input(netplay_t *netplay, size_t sim_ptr, bool resim) +bool netplay_resolve_input(netplay_t *netplay, size_t sim_ptr, bool resim) { uint32_t client; size_t prev; struct delta_frame *simframe, *pframe; netplay_input_state_t simstate, pstate; + uint32_t devices, device; + bool ret = false; simframe = &netplay->buffer[sim_ptr]; @@ -106,46 +110,60 @@ void netplay_simulate_input(netplay_t *netplay, size_t sim_ptr, bool resim) // FIXME: Maybe this is the right time to do resolved data? if (simframe->have_real[client]) continue; - simstate = netplay_input_state_for(&simframe->simulated_input, client, 3 /* FIXME */, false); - if (!simstate) - continue; + devices = netplay->client_devices[client]; - prev = PREV_PTR(netplay->read_ptr1[client]); - pframe = &netplay->buffer[prev]; - pstate = netplay_input_state_for(&pframe->real_input, client, 3 /* FIXME */, false); - if (!pstate) - continue; + for (device = 0; device < MAX_INPUT_DEVICES; device++) + { + if (!(devices & device)) continue; - if (resim) - { - /* In resimulation mode, we only copy the buttons. The reason for this - * is nonobvious: - * - * If we resimulated nothing, then the /duration/ with which any input - * was pressed would be approximately correct, since the original - * simulation came in as the input came in, but the /number of times/ - * the input was pressed would be wrong, as there would be an - * advancing wavefront of real data overtaking the simulated data - * (which is really just real data offset by some frames). - * - * That's acceptable for arrows in most situations, since the amount - * you move is tied to the duration, but unacceptable for buttons, - * which will seem to jerkily be pressed numerous times with those - * wavefronts. - */ - const uint32_t keep = (1U<data[0] &= keep; - simstate->data[0] |= pstate->data[0] & ~keep; - } - else - { - memcpy(simstate->data, pstate->data, - simstate->size * sizeof(uint32_t)); + simstate = netplay_input_state_for(&simframe->simulated_input[device], client, 3 /* FIXME */, false); + if (!simstate) + continue; + + prev = PREV_PTR(netplay->read_ptr1[client]); + pframe = &netplay->buffer[prev]; + pstate = netplay_input_state_for(&pframe->real_input[device], client, 3 /* FIXME */, false); + if (!pstate) + continue; + + if (resim) + { + /* In resimulation mode, we only copy the buttons. The reason for this + * is nonobvious: + * + * If we resimulated nothing, then the /duration/ with which any input + * was pressed would be approximately correct, since the original + * simulation came in as the input came in, but the /number of times/ + * the input was pressed would be wrong, as there would be an + * advancing wavefront of real data overtaking the simulated data + * (which is really just real data offset by some frames). + * + * That's acceptable for arrows in most situations, since the amount + * you move is tied to the duration, but unacceptable for buttons, + * which will seem to jerkily be pressed numerous times with those + * wavefronts. + */ + const uint32_t keep = (1U<data[0]; + simstate->data[0] &= keep; + simstate->data[0] |= pstate->data[0] & ~keep; + if (prev != simstate->data[0]) + ret = true; + } + else + { + if (memcmp(simstate->data, pstate->data, simstate->size * sizeof(uint32_t))) + ret = true; + memcpy(simstate->data, pstate->data, + simstate->size * sizeof(uint32_t)); + } } } + + return ret; } static void netplay_handle_frame_hash(netplay_t *netplay, struct delta_frame *delta) @@ -432,14 +450,10 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled) struct delta_frame *ptr = &netplay->buffer[netplay->other_ptr]; size_t i; - for (i = 0; i < MAX_USERS; i++) - { - if (memcmp(ptr->simulated_input_state[i], ptr->real_input_state[i], - sizeof(ptr->real_input_state[i])) != 0 - && !ptr->used_real[i]) - break; - } - if (i != MAX_USERS) break; + /* If resolving the input changes it, we used bad input */ + if (netplay_resolve_input(netplay, netplay->other_ptr, true)) + break; + netplay_handle_frame_hash(netplay, ptr); netplay->other_ptr = NEXT_PTR(netplay->other_ptr); netplay->other_frame_count++; @@ -490,7 +504,7 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled) netplay_handle_frame_hash(netplay, ptr); /* Re-simulate this frame's input */ - netplay_simulate_input(netplay, netplay->replay_ptr, true); + netplay_resolve_input(netplay, netplay->replay_ptr, true); autosave_lock(); core_run(); @@ -543,16 +557,16 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled) if (netplay->is_server) { - uint32_t player; + uint32_t client; lo_frame_count = hi_frame_count = netplay->unread_frame_count; /* Look for players that are ahead of us */ - for (player = 0; player < MAX_USERS; player++) + for (client = 0; client < MAX_CLIENTS; client++) { - if (!(netplay->connected_players & (1<read_frame_count[player] > hi_frame_count) - hi_frame_count = netplay->read_frame_count[player]; + if (!(netplay->connected_players1 & (1<read_frame_count1[client] > hi_frame_count) + hi_frame_count = netplay->read_frame_count1[client]; } } else @@ -618,14 +632,14 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled) for (i = 0; i < netplay->connections_size; i++) { struct netplay_connection *connection = &netplay->connections[i]; - int player; + uint32_t client_num; if (!connection->active || connection->mode != NETPLAY_CONNECTION_PLAYING) continue; - player = connection->player; + client_num = i + 1; /* Are they ahead? */ - if (netplay->self_frame_count + 3 < netplay->read_frame_count[player]) + if (netplay->self_frame_count + 3 < netplay->read_frame_count1[client_num]) { /* Tell them to stall */ if (connection->stall_frame + NETPLAY_MAX_REQ_STALL_FREQUENCY < @@ -633,7 +647,7 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled) { connection->stall_frame = netplay->self_frame_count; netplay_cmd_stall(netplay, connection, - netplay->read_frame_count[player] - + netplay->read_frame_count1[client_num] - netplay->self_frame_count + 1); } }