mirror of
https://github.com/libretro/RetroArch
synced 2025-03-29 22:20:21 +00:00
First cut of input changes (not yet working)
This commit is contained in:
parent
6d4119690d
commit
ed69916e59
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user