First cut of input changes (not yet working)

This commit is contained in:
Gregor Richards 2017-09-09 20:44:12 -04:00
parent 6d4119690d
commit ed69916e59
8 changed files with 295 additions and 182 deletions

View File

@ -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:

View File

@ -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;
}

View File

@ -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<<device);
netplay->self_mode = NETPLAY_CONNECTION_PLAYING;
netplay->connected_players1 |= 1;
netplay->client_devices[0] = (1<<device);
netplay->device_clients[device] = netplay->self_devices = 1;
netplay->client_devices[0] = netplay->self_devices = (1<<device);
netplay->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;
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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<<player)))
APPEND((M, " %u:%u", player, netplay->read_frame_count[player]));
if ((netplay->connected_players1 & (1<<client)))
APPEND((M, " %u:%u", client, netplay->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<<device)))
continue;
// Add this device's input
istate = dframe->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<<device)))
continue;
// Add this device's input (FIXME: refactor)
istate = dframe->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<<player))) continue;
if (frame > netplay->read_frame_count[player])
if (!(netplay->connected_players1 & (1<<client))) continue;
if (frame > 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<<device)))
continue;
istate_in = oframe->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;
}
}
}

View File

@ -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

View File

@ -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<<RETRO_DEVICE_ID_JOYPAD_UP) |
(1U<<RETRO_DEVICE_ID_JOYPAD_DOWN) |
(1U<<RETRO_DEVICE_ID_JOYPAD_LEFT) |
(1U<<RETRO_DEVICE_ID_JOYPAD_RIGHT);
simstate->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<<RETRO_DEVICE_ID_JOYPAD_UP) |
(1U<<RETRO_DEVICE_ID_JOYPAD_DOWN) |
(1U<<RETRO_DEVICE_ID_JOYPAD_LEFT) |
(1U<<RETRO_DEVICE_ID_JOYPAD_RIGHT);
uint32_t prev = simstate->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<<player))) continue;
if (netplay->read_frame_count[player] > hi_frame_count)
hi_frame_count = netplay->read_frame_count[player];
if (!(netplay->connected_players1 & (1<<client))) continue;
if (netplay->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);
}
}