mirror of
https://github.com/CTCaer/RetroArch.git
synced 2025-01-09 20:41:19 +00:00
First step (not yet compiling) of changing around Netplay input.
This commit is contained in:
parent
f677a7ad7e
commit
6d4119690d
@ -106,6 +106,10 @@ early (i.e., it only forwards data on the frame it's reached), it must also
|
||||
inform all clients of its own current frame even if it has no input. The
|
||||
NOINPUT command is provided for that purpose.
|
||||
|
||||
Each client has a client number, and the server is always client number 0.
|
||||
Client numbers are currently limited to 0-31, as they're used in 32-bit
|
||||
bitmaps.
|
||||
|
||||
The handshake procedure (this part is done by both server and client):
|
||||
1) Send connection header
|
||||
2) Receive and verify connection header
|
||||
@ -156,7 +160,7 @@ Payload:
|
||||
{
|
||||
frame number: uint32
|
||||
is server data: 1 bit
|
||||
player: 31 bits
|
||||
client number: 31 bits
|
||||
joypad input: uint32
|
||||
analog 1 input: uint32
|
||||
analog 2 input: uint32
|
||||
@ -213,9 +217,9 @@ Payload:
|
||||
{
|
||||
frame number: uint32
|
||||
paused?: 1 bit
|
||||
connected players: 31 bits
|
||||
flip frame: uint32
|
||||
client number: 31 bits
|
||||
controller devices: uint32[16]
|
||||
controller-client mapping: uint32[16]
|
||||
client nick: char[32]
|
||||
sram: variable
|
||||
}
|
||||
@ -236,13 +240,16 @@ Description:
|
||||
Command: PLAY
|
||||
Payload:
|
||||
{
|
||||
reserved: 31 bits
|
||||
as slave?: 1 bit
|
||||
reserved: 15 bits
|
||||
requested device(s): 16 bits
|
||||
}
|
||||
Description:
|
||||
Request to enter player mode. The client must wait for a MODE command
|
||||
before sending input. Server may refuse or force slave connections, so the
|
||||
request is not necessarily honored. Payload may be elided if zero.
|
||||
request is not necessarily honored. If no devices are explicitly requested,
|
||||
the server may choose how to assign; the default is to assign the first
|
||||
unassigned device. Payload may be elided if zero.
|
||||
|
||||
Command: MODE
|
||||
Payload:
|
||||
@ -252,7 +259,8 @@ Payload:
|
||||
slave: 1 bit
|
||||
playing: 1 bit
|
||||
you: 1 bit
|
||||
player number: uint16
|
||||
client number: uint16
|
||||
device bitmap: uint32
|
||||
}
|
||||
Description:
|
||||
Inform of a connection mode change (possibly of the receiving client). Only
|
||||
|
@ -71,7 +71,7 @@ static bool netplay_is_alive(void)
|
||||
{
|
||||
if (!netplay_data)
|
||||
return false;
|
||||
return (netplay_data->is_server && !!netplay_data->connected_players) ||
|
||||
return (netplay_data->is_server && (netplay_data->connected_players1>1)) ||
|
||||
(!netplay_data->is_server && netplay_data->self_mode >= NETPLAY_CONNECTION_CONNECTED);
|
||||
}
|
||||
|
||||
@ -115,8 +115,9 @@ static bool netplay_can_poll(netplay_t *netplay)
|
||||
*/
|
||||
static bool get_self_input_state(netplay_t *netplay)
|
||||
{
|
||||
uint32_t state[WORDS_PER_INPUT] = {0, 0, 0};
|
||||
struct delta_frame *ptr = &netplay->buffer[netplay->self_ptr];
|
||||
netplay_input_state_t istate = NULL;
|
||||
uint32_t devices, devi;
|
||||
size_t i;
|
||||
|
||||
if (!netplay_delta_frame_ready(netplay, ptr, netplay->self_frame_count))
|
||||
@ -128,39 +129,43 @@ static bool get_self_input_state(netplay_t *netplay)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!input_driver_is_libretro_input_blocked() && netplay->self_frame_count > 0)
|
||||
devices = netplay->self_devices;
|
||||
for (devi = 0; devi < MAX_INPUT_DEVICES; devi++)
|
||||
{
|
||||
/* First frame we always give zero input since relying on
|
||||
* input from first frame screws up when we use -F 0. */
|
||||
retro_input_state_t cb = netplay->cbs.state_cb;
|
||||
for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++)
|
||||
{
|
||||
int16_t tmp = cb(0,
|
||||
RETRO_DEVICE_JOYPAD, 0, (unsigned)i);
|
||||
state[0] |= tmp ? 1 << i : 0;
|
||||
}
|
||||
if (!(devices & (1<<devi)))
|
||||
continue;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
istate = netplay_input_state_for(&ptr->real_input[devi],
|
||||
netplay->self_client_num, 3 /* FIXME */, true);
|
||||
if (!istate)
|
||||
continue; /* FIXME: More severe? */
|
||||
|
||||
if (!input_driver_is_libretro_input_blocked() && netplay->self_frame_count > 0)
|
||||
{
|
||||
int16_t tmp_x = cb(0,
|
||||
RETRO_DEVICE_ANALOG, (unsigned)i, 0);
|
||||
int16_t tmp_y = cb(0,
|
||||
RETRO_DEVICE_ANALOG, (unsigned)i, 1);
|
||||
state[1 + i] = (uint16_t)tmp_x | (((uint16_t)tmp_y) << 16);
|
||||
/* First frame we always give zero input since relying on
|
||||
* input from first frame screws up when we use -F 0. */
|
||||
uint32_t *state = istate->data;
|
||||
retro_input_state_t cb = netplay->cbs.state_cb;
|
||||
for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++)
|
||||
{
|
||||
int16_t tmp = cb(0,
|
||||
RETRO_DEVICE_JOYPAD, 0, (unsigned)i);
|
||||
state[0] |= tmp ? 1 << i : 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
int16_t tmp_x = cb(0,
|
||||
RETRO_DEVICE_ANALOG, (unsigned)i, 0);
|
||||
int16_t tmp_y = cb(0,
|
||||
RETRO_DEVICE_ANALOG, (unsigned)i, 1);
|
||||
state[1 + i] = (uint16_t)tmp_x | (((uint16_t)tmp_y) << 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(ptr->self_state, state, sizeof(state));
|
||||
ptr->have_local = true;
|
||||
|
||||
/* If we're playing, copy it in as real input */
|
||||
if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING)
|
||||
{
|
||||
memcpy(ptr->real_input_state[netplay->self_player], state,
|
||||
sizeof(state));
|
||||
ptr->have_real[netplay->self_player] = true;
|
||||
}
|
||||
|
||||
/* And send this input to our peers */
|
||||
for (i = 0; i < netplay->connections_size; i++)
|
||||
{
|
||||
@ -203,7 +208,7 @@ bool init_netplay_deferred(const char* server, unsigned port)
|
||||
static bool netplay_poll(void)
|
||||
{
|
||||
int res;
|
||||
uint32_t player;
|
||||
uint32_t client;
|
||||
size_t i;
|
||||
|
||||
netplay_data->can_poll = false;
|
||||
@ -219,7 +224,7 @@ static bool netplay_poll(void)
|
||||
* frame */
|
||||
netplay_update_unread_ptr(netplay_data);
|
||||
if (netplay_data->stateless_mode &&
|
||||
netplay_data->connected_players &&
|
||||
(netplay_data->connected_players1>1) &&
|
||||
netplay_data->unread_frame_count <= netplay_data->run_frame_count)
|
||||
res = netplay_poll_net_input(netplay_data, true);
|
||||
else
|
||||
@ -231,7 +236,7 @@ static bool netplay_poll(void)
|
||||
netplay_simulate_input(netplay_data, netplay_data->run_ptr, false);
|
||||
|
||||
/* Handle any slaves */
|
||||
if (netplay_data->is_server && netplay_data->connected_slaves)
|
||||
if (netplay_data->is_server && netplay_data->connected_slaves1)
|
||||
netplay_handle_slaves(netplay_data);
|
||||
|
||||
netplay_update_unread_ptr(netplay_data);
|
||||
@ -352,7 +357,7 @@ static bool netplay_poll(void)
|
||||
{
|
||||
/* Have we not read enough latency frames? */
|
||||
if (netplay_data->self_mode == NETPLAY_CONNECTION_PLAYING &&
|
||||
netplay_data->connected_players &&
|
||||
netplay_data->connected_players1 &&
|
||||
netplay_data->run_frame_count + netplay_data->input_latency_frames > netplay_data->self_frame_count)
|
||||
{
|
||||
netplay_data->stall = NETPLAY_STALL_INPUT_LATENCY;
|
||||
@ -369,21 +374,19 @@ static bool netplay_poll(void)
|
||||
/* Figure out who to blame */
|
||||
if (netplay_data->is_server)
|
||||
{
|
||||
for (player = 0; player < MAX_USERS; player++)
|
||||
for (client = 1; client < MAX_CLIENTS; client++)
|
||||
{
|
||||
if (!(netplay_data->connected_players & (1<<player))) continue;
|
||||
if (netplay_data->read_frame_count[player] > netplay_data->unread_frame_count) continue;
|
||||
for (i = 0; i < netplay_data->connections_size; i++)
|
||||
struct netplay_connection *connection;
|
||||
if (!(netplay_data->connected_players1 & (1<<client)))
|
||||
continue;
|
||||
if (netplay_data->read_frame_count1[client] > netplay_data->unread_frame_count)
|
||||
continue;
|
||||
connection = &netplay_data->connections[client-1];
|
||||
if (connection->active &&
|
||||
connection->mode == NETPLAY_CONNECTION_PLAYING)
|
||||
{
|
||||
struct netplay_connection *connection = &netplay_data->connections[i];
|
||||
if (connection->active &&
|
||||
connection->mode == NETPLAY_CONNECTION_PLAYING &&
|
||||
connection->player == player)
|
||||
{
|
||||
connection->stall = NETPLAY_STALL_RUNNING_FAST;
|
||||
connection->stall_time = netplay_data->stall_time;
|
||||
break;
|
||||
}
|
||||
connection->stall = NETPLAY_STALL_RUNNING_FAST;
|
||||
connection->stall_time = netplay_data->stall_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -480,32 +483,30 @@ static int16_t netplay_input_state(netplay_t *netplay,
|
||||
{
|
||||
size_t ptr = netplay->is_replay ?
|
||||
netplay->replay_ptr : netplay->run_ptr;
|
||||
struct delta_frame *delta;
|
||||
netplay_input_state_t istate;
|
||||
|
||||
const uint32_t *curr_input_state = NULL;
|
||||
|
||||
if (port <= 1)
|
||||
{
|
||||
/* Possibly flip the port */
|
||||
if (netplay_flip_port(netplay))
|
||||
port ^= 1;
|
||||
}
|
||||
else if (port >= MAX_USERS)
|
||||
if (port >= MAX_INPUT_DEVICES)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (port > netplay->player_max)
|
||||
netplay->player_max = port;
|
||||
if (port > netplay->input_device_max)
|
||||
netplay->input_device_max = port;
|
||||
|
||||
if (netplay->buffer[ptr].have_real[port])
|
||||
{
|
||||
netplay->buffer[ptr].used_real[port] = true;
|
||||
curr_input_state = netplay->buffer[ptr].real_input_state[port];
|
||||
}
|
||||
/* FIXME: Mixing */
|
||||
delta = &netplay->buffer[ptr];
|
||||
istate = delta->real_input[port];
|
||||
if (istate && istate->is_real)
|
||||
delta->used_real[port] = true;
|
||||
else
|
||||
{
|
||||
curr_input_state = netplay->buffer[ptr].simulated_input_state[port];
|
||||
}
|
||||
istate = delta->simulated_input[port];
|
||||
if (!istate)
|
||||
return 0;
|
||||
|
||||
curr_input_state = istate->data;
|
||||
|
||||
switch (device)
|
||||
{
|
||||
@ -889,7 +890,7 @@ bool netplay_pre_frame(netplay_t *netplay)
|
||||
}
|
||||
|
||||
if (sync_stalled ||
|
||||
((!netplay->is_server || netplay->connected_players) &&
|
||||
((!netplay->is_server || (netplay->connected_players1>1)) &&
|
||||
(netplay->stall || netplay->remote_paused)))
|
||||
{
|
||||
/* We may have received data even if we're stalled, so run post-frame
|
||||
@ -942,19 +943,20 @@ static void netplay_force_future(netplay_t *netplay)
|
||||
netplay->run_ptr = netplay->self_ptr;
|
||||
netplay->run_frame_count = netplay->self_frame_count;
|
||||
|
||||
|
||||
/* We need to ignore any intervening data from the other side,
|
||||
* and never rewind past this */
|
||||
netplay_update_unread_ptr(netplay);
|
||||
if (netplay->unread_frame_count < netplay->run_frame_count)
|
||||
{
|
||||
uint32_t player;
|
||||
for (player = 0; player < MAX_USERS; player++)
|
||||
uint32_t client;
|
||||
for (client = 0; client < MAX_CLIENTS; client++)
|
||||
{
|
||||
if (!(netplay->connected_players & (1<<player))) continue;
|
||||
if (netplay->read_frame_count[player] < netplay->run_frame_count)
|
||||
if (!(netplay->connected_players1 & (1<<client))) continue;
|
||||
if (netplay->read_frame_count1[client] < netplay->run_frame_count)
|
||||
{
|
||||
netplay->read_ptr[player] = netplay->run_ptr;
|
||||
netplay->read_frame_count[player] = netplay->run_frame_count;
|
||||
netplay->read_ptr1[client] = netplay->run_ptr;
|
||||
netplay->read_frame_count1[client] = netplay->run_frame_count;
|
||||
}
|
||||
}
|
||||
if (netplay->server_frame_count < netplay->run_frame_count)
|
||||
@ -1128,10 +1130,12 @@ static void netplay_core_reset(netplay_t *netplay)
|
||||
*/
|
||||
static void netplay_toggle_play_spectate(netplay_t *netplay)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (netplay->is_server)
|
||||
{
|
||||
/* FIXME: Duplication */
|
||||
uint32_t payload[2];
|
||||
uint32_t payload[3];
|
||||
char msg[512];
|
||||
const char *dmsg = NULL;
|
||||
payload[0] = htonl(netplay->self_frame_count);
|
||||
@ -1139,28 +1143,41 @@ static void netplay_toggle_play_spectate(netplay_t *netplay)
|
||||
netplay->self_mode == NETPLAY_CONNECTION_SLAVE)
|
||||
{
|
||||
/* Mark us as no longer playing */
|
||||
payload[1] = htonl(netplay->self_player);
|
||||
/* FIXME: Refactor this */
|
||||
payload[1] = htonl(netplay->self_client_num);
|
||||
payload[2] = htonl(0);
|
||||
netplay->self_mode = NETPLAY_CONNECTION_SPECTATING;
|
||||
netplay->connected_players1 |= ~(1L);
|
||||
netplay->connected_slaves1 |= ~(1L);
|
||||
netplay->client_devices[0] = 0;
|
||||
for (i = 0; i < MAX_INPUT_DEVICES; i++)
|
||||
netplay->device_clients[i] |= ~(1L);
|
||||
netplay->self_devices = 0;
|
||||
|
||||
dmsg = msg_hash_to_str(MSG_NETPLAY_YOU_HAVE_LEFT_THE_GAME);
|
||||
|
||||
}
|
||||
else if (netplay->self_mode == NETPLAY_CONNECTION_SPECTATING)
|
||||
{
|
||||
uint32_t player;
|
||||
uint32_t device;
|
||||
|
||||
/* Take a player number */
|
||||
for (player = 0; player < MAX_USERS; player++)
|
||||
if (!(netplay->connected_players & (1<<player))) break;
|
||||
if (player == MAX_USERS) return; /* Failure! */
|
||||
/* Take an input device */
|
||||
for (device = 0; device < MAX_INPUT_DEVICES; device++)
|
||||
if (!(netplay->device_clients[device]))
|
||||
break;
|
||||
if (device == MAX_INPUT_DEVICES)
|
||||
return; /* Failure! */
|
||||
|
||||
payload[1] = htonl(NETPLAY_CMD_MODE_BIT_PLAYING | player);
|
||||
payload[1] = htonl(NETPLAY_CMD_MODE_BIT_PLAYING | device);
|
||||
payload[2] = htonl(1<<device);
|
||||
netplay->self_mode = NETPLAY_CONNECTION_PLAYING;
|
||||
netplay->self_player = player;
|
||||
netplay->connected_players1 |= 1;
|
||||
netplay->client_devices[0] = (1<<device);
|
||||
netplay->device_clients[device] = netplay->self_devices = 1;
|
||||
|
||||
dmsg = msg;
|
||||
msg[sizeof(msg)-1] = '\0';
|
||||
snprintf(msg, sizeof(msg)-1, msg_hash_to_str(MSG_NETPLAY_YOU_HAVE_JOINED_AS_PLAYER_N), player+1);
|
||||
snprintf(msg, sizeof(msg)-1, msg_hash_to_str(MSG_NETPLAY_YOU_HAVE_JOINED_AS_PLAYER_N), device+1);
|
||||
}
|
||||
|
||||
RARCH_LOG("[netplay] %s\n", dmsg);
|
||||
|
@ -529,10 +529,10 @@ bool netplay_handshake_sync(netplay_t *netplay,
|
||||
/* If we're the server, now we send sync info */
|
||||
size_t i;
|
||||
int matchct;
|
||||
uint32_t cmd[5];
|
||||
uint32_t cmd[4];
|
||||
retro_ctx_memory_info_t mem_info;
|
||||
uint32_t client_num = 0;
|
||||
uint32_t device = 0;
|
||||
uint32_t connected_players = 0;
|
||||
size_t nicklen, nickmangle = 0;
|
||||
bool nick_matched = false;
|
||||
|
||||
@ -543,30 +543,43 @@ bool netplay_handshake_sync(netplay_t *netplay,
|
||||
|
||||
/* Send basic sync info */
|
||||
cmd[0] = htonl(NETPLAY_CMD_SYNC);
|
||||
cmd[1] = htonl(3*sizeof(uint32_t) + MAX_USERS*sizeof(uint32_t) +
|
||||
NETPLAY_NICK_LEN + mem_info.size);
|
||||
cmd[1] = htonl(2*sizeof(uint32_t)
|
||||
/* Controller devices */
|
||||
+ MAX_INPUT_DEVICES*sizeof(uint32_t)
|
||||
|
||||
/* Device-client mapping */
|
||||
+ MAX_INPUT_DEVICES*sizeof(uint32_t)
|
||||
|
||||
/* Client nick */
|
||||
+ NETPLAY_NICK_LEN
|
||||
|
||||
/* And finally, sram */
|
||||
+ mem_info.size);
|
||||
cmd[2] = htonl(netplay->self_frame_count);
|
||||
connected_players = netplay->connected_players;
|
||||
if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING)
|
||||
connected_players |= 1<<netplay->self_player;
|
||||
client_num = connection - netplay->connections + 1;
|
||||
if (netplay->local_paused || netplay->remote_paused)
|
||||
connected_players |= NETPLAY_CMD_SYNC_BIT_PAUSED;
|
||||
cmd[3] = htonl(connected_players);
|
||||
if (netplay->flip)
|
||||
cmd[4] = htonl(netplay->flip_frame);
|
||||
else
|
||||
cmd[4] = htonl(0);
|
||||
client_num |= NETPLAY_CMD_SYNC_BIT_PAUSED;
|
||||
cmd[3] = htonl(client_num);
|
||||
|
||||
if (!netplay_send(&connection->send_packet_buffer, connection->fd, cmd,
|
||||
sizeof(cmd)))
|
||||
return false;
|
||||
|
||||
/* Now send the device info */
|
||||
for (i = 0; i < MAX_USERS; i++)
|
||||
for (i = 0; i < MAX_INPUT_DEVICES; i++)
|
||||
{
|
||||
device = htonl(input_config_get_device((unsigned)i));
|
||||
if (!netplay_send(&connection->send_packet_buffer, connection->fd,
|
||||
&device, sizeof(device)))
|
||||
&device, sizeof(device)))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Then the device-client mapping */
|
||||
for (i = 0; i < MAX_INPUT_DEVICES; i++)
|
||||
{
|
||||
device = htonl(netplay->device_clients[i]);
|
||||
if (!netplay_send(&connection->send_packet_buffer, connection->fd,
|
||||
&device, sizeof(device)))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -901,10 +914,10 @@ bool netplay_handshake_pre_sync(netplay_t *netplay,
|
||||
struct netplay_connection *connection, bool *had_input)
|
||||
{
|
||||
uint32_t cmd[2];
|
||||
uint32_t new_frame_count, connected_players, flip_frame;
|
||||
uint32_t new_frame_count, client_num, flip_frame;
|
||||
uint32_t device;
|
||||
uint32_t local_sram_size, remote_sram_size;
|
||||
size_t i;
|
||||
size_t i, j;
|
||||
ssize_t recvd;
|
||||
retro_ctx_controller_info_t pad;
|
||||
char new_nick[NETPLAY_NICK_LEN];
|
||||
@ -920,8 +933,8 @@ bool netplay_handshake_pre_sync(netplay_t *netplay,
|
||||
}
|
||||
|
||||
/* Only expecting a sync command */
|
||||
if (ntohl(cmd[0]) != NETPLAY_CMD_SYNC ||
|
||||
ntohl(cmd[1]) < 3*sizeof(uint32_t) + MAX_USERS*sizeof(uint32_t) +
|
||||
if (ntohl(cmd[0]) != NETPLAY_CMD_SYNC||
|
||||
ntohl(cmd[1]) < (2+2*MAX_INPUT_DEVICES)*sizeof(uint32_t) +
|
||||
NETPLAY_NICK_LEN)
|
||||
{
|
||||
RARCH_ERR("%s\n",
|
||||
@ -934,30 +947,23 @@ bool netplay_handshake_pre_sync(netplay_t *netplay,
|
||||
return false;
|
||||
new_frame_count = ntohl(new_frame_count);
|
||||
|
||||
/* Get the connected players and pause mode */
|
||||
RECV(&connected_players, sizeof(connected_players))
|
||||
/* Get our client number and pause mode */
|
||||
RECV(&client_num, sizeof(client_num))
|
||||
return false;
|
||||
connected_players = ntohl(connected_players);
|
||||
if (connected_players & NETPLAY_CMD_SYNC_BIT_PAUSED)
|
||||
client_num = ntohl(client_num);
|
||||
if (client_num & NETPLAY_CMD_SYNC_BIT_PAUSED)
|
||||
{
|
||||
netplay->remote_paused = true;
|
||||
connected_players ^= NETPLAY_CMD_SYNC_BIT_PAUSED;
|
||||
client_num ^= NETPLAY_CMD_SYNC_BIT_PAUSED;
|
||||
}
|
||||
netplay->connected_players = connected_players;
|
||||
|
||||
/* And the flip state */
|
||||
RECV(&flip_frame, sizeof(flip_frame))
|
||||
return false;
|
||||
|
||||
flip_frame = ntohl(flip_frame);
|
||||
netplay->flip = !!flip_frame;
|
||||
netplay->flip_frame = flip_frame;
|
||||
netplay->self_client_num = client_num;
|
||||
|
||||
/* Set our frame counters as requested */
|
||||
netplay->self_frame_count = netplay->run_frame_count =
|
||||
netplay->other_frame_count = netplay->unread_frame_count =
|
||||
netplay->server_frame_count = new_frame_count;
|
||||
|
||||
/* And clear out the framebuffer */
|
||||
for (i = 0; i < netplay->buffer_size; i++)
|
||||
{
|
||||
struct delta_frame *ptr = &netplay->buffer[i];
|
||||
@ -977,17 +983,14 @@ bool netplay_handshake_pre_sync(netplay_t *netplay,
|
||||
|
||||
}
|
||||
}
|
||||
for (i = 0; i < MAX_USERS; i++)
|
||||
for (i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if (connected_players & (1<<i))
|
||||
{
|
||||
netplay->read_ptr[i] = netplay->self_ptr;
|
||||
netplay->read_frame_count[i] = netplay->self_frame_count;
|
||||
}
|
||||
netplay->read_ptr1[i] = netplay->self_ptr;
|
||||
netplay->read_frame_count1[i] = netplay->self_frame_count;
|
||||
}
|
||||
|
||||
/* Get and set each pad */
|
||||
for (i = 0; i < MAX_USERS; i++)
|
||||
/* Get and set each input device */
|
||||
for (i = 0; i < MAX_INPUT_DEVICES; i++)
|
||||
{
|
||||
RECV(&device, sizeof(device))
|
||||
return false;
|
||||
@ -998,6 +1001,27 @@ bool netplay_handshake_pre_sync(netplay_t *netplay,
|
||||
core_set_controller_port_device(&pad);
|
||||
}
|
||||
|
||||
/* Get the client-controller mapping */
|
||||
netplay->connected_players1 =
|
||||
netplay->connected_slaves1 =
|
||||
netplay->self_devices = 0;
|
||||
for (i = 0; i < MAX_CLIENTS; i++)
|
||||
netplay->client_devices[i] = 0;
|
||||
for (i = 0; i < MAX_INPUT_DEVICES; i++)
|
||||
{
|
||||
RECV(&device, sizeof(device))
|
||||
return false;
|
||||
device = ntohl(device);
|
||||
|
||||
netplay->device_clients[i] = device;
|
||||
netplay->connected_players1 |= device;
|
||||
for (j = 0; j < MAX_CLIENTS; j++)
|
||||
{
|
||||
if (device & (1<<j))
|
||||
netplay->client_devices[j] |= 1<<i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get our nick */
|
||||
RECV(new_nick, NETPLAY_NICK_LEN)
|
||||
return false;
|
||||
@ -1018,8 +1042,8 @@ bool netplay_handshake_pre_sync(netplay_t *netplay,
|
||||
core_get_memory(&mem_info);
|
||||
|
||||
local_sram_size = (unsigned)mem_info.size;
|
||||
remote_sram_size = ntohl(cmd[1]) - 3*sizeof(uint32_t) -
|
||||
MAX_USERS*sizeof(uint32_t) - NETPLAY_NICK_LEN;
|
||||
remote_sram_size = ntohl(cmd[1]) -
|
||||
(2+2*MAX_INPUT_DEVICES)*sizeof(uint32_t) - NETPLAY_NICK_LEN;
|
||||
|
||||
if (local_sram_size != 0 && local_sram_size == remote_sram_size)
|
||||
{
|
||||
|
@ -243,7 +243,7 @@ static bool netplay_init_socket_buffers(netplay_t *netplay)
|
||||
* frames of input data, plus the headers for each of them */
|
||||
size_t i;
|
||||
size_t packet_buffer_size = netplay->zbuffer_size +
|
||||
NETPLAY_MAX_STALL_FRAMES * WORDS_PER_FRAME + (NETPLAY_MAX_STALL_FRAMES+1)*3;
|
||||
NETPLAY_MAX_STALL_FRAMES * 16;
|
||||
netplay->packet_buffer_size = packet_buffer_size;
|
||||
|
||||
for (i = 0; i < netplay->connections_size; i++)
|
||||
@ -430,8 +430,7 @@ netplay_t *netplay_new(void *direct_host, const char *server, uint16_t port,
|
||||
netplay->listen_fd = -1;
|
||||
netplay->tcp_port = port;
|
||||
netplay->cbs = *cb;
|
||||
netplay->connected_players = 0;
|
||||
netplay->player_max = 1;
|
||||
netplay->input_device_max = 1;
|
||||
netplay->is_server = (direct_host == NULL && server == NULL);
|
||||
netplay->is_connected = false;;
|
||||
netplay->nat_traversal = netplay->is_server ? nat_traversal : false;
|
||||
|
@ -91,6 +91,7 @@ void netplay_hangup(netplay_t *netplay, struct netplay_connection *connection)
|
||||
{
|
||||
char msg[512];
|
||||
const char *dmsg;
|
||||
size_t i;
|
||||
|
||||
if (!netplay)
|
||||
return;
|
||||
@ -124,12 +125,22 @@ void netplay_hangup(netplay_t *netplay, struct netplay_connection *connection)
|
||||
if (!netplay->is_server)
|
||||
{
|
||||
netplay->self_mode = NETPLAY_CONNECTION_NONE;
|
||||
netplay->connected_players = 0;
|
||||
netplay->connected_players1 &= (1L<<netplay->self_client_num);
|
||||
for (i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if (i == netplay->self_client_num)
|
||||
continue;
|
||||
netplay->client_devices[i] = 0;
|
||||
}
|
||||
for (i = 0; i < MAX_INPUT_DEVICES; i++)
|
||||
netplay->device_clients[i] &= (1L<<netplay->self_client_num);
|
||||
netplay->stall = NETPLAY_STALL_NONE;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t client_num = connection - netplay->connections + 1;
|
||||
|
||||
/* Mark the player for removal */
|
||||
if (connection->mode == NETPLAY_CONNECTION_PLAYING ||
|
||||
connection->mode == NETPLAY_CONNECTION_SLAVE)
|
||||
@ -137,11 +148,14 @@ void netplay_hangup(netplay_t *netplay, struct netplay_connection *connection)
|
||||
/* This special mode keeps the connection object alive long enough to
|
||||
* send the disconnection message at the correct time */
|
||||
connection->mode = NETPLAY_CONNECTION_DELAYED_DISCONNECT;
|
||||
connection->delay_frame = netplay->read_frame_count[connection->player];
|
||||
connection->delay_frame = netplay->read_frame_count1[client_num];
|
||||
|
||||
/* Mark them as not playing anymore */
|
||||
netplay->connected_players &= ~(1<<connection->player);
|
||||
netplay->connected_slaves &= ~(1<<connection->player);
|
||||
netplay->connected_players1 &= ~(1L<<client_num);
|
||||
netplay->connected_slaves1 &= ~(1L<<client_num);
|
||||
netplay->client_devices[client_num] = 0;
|
||||
for (i = 0; i < MAX_INPUT_DEVICES; i++)
|
||||
netplay->device_clients[i] &= ~(1L<<client_num);
|
||||
|
||||
}
|
||||
|
||||
@ -165,15 +179,17 @@ void netplay_delayed_state_change(netplay_t *netplay)
|
||||
|
||||
for (i = 0; i < netplay->connections_size; i++)
|
||||
{
|
||||
uint32_t client_num = i+1;
|
||||
connection = &netplay->connections[i];
|
||||
if ((connection->active || connection->mode == NETPLAY_CONNECTION_DELAYED_DISCONNECT) &&
|
||||
connection->delay_frame &&
|
||||
connection->delay_frame <= netplay->self_frame_count)
|
||||
{
|
||||
/* Something was delayed! Prepare the MODE command */
|
||||
uint32_t payload[2];
|
||||
uint32_t payload[3];
|
||||
payload[0] = htonl(connection->delay_frame);
|
||||
payload[1] = htonl(connection->player);
|
||||
payload[1] = htonl(client_num);
|
||||
payload[2] = htonl(0);
|
||||
|
||||
/* Remove the connection entirely if relevant */
|
||||
if (connection->mode == NETPLAY_CONNECTION_DELAYED_DISCONNECT)
|
||||
@ -189,24 +205,43 @@ void netplay_delayed_state_change(netplay_t *netplay)
|
||||
}
|
||||
|
||||
/* Send the specified input data */
|
||||
static bool send_input_frame(netplay_t *netplay,
|
||||
struct netplay_connection *only, struct netplay_connection *except,
|
||||
uint32_t frame, uint32_t player, uint32_t *state)
|
||||
static bool send_input_frame(netplay_t *netplay, struct delta_frame *dframe,
|
||||
struct netplay_connection *only, struct netplay_connection *except,
|
||||
uint32_t client_num)
|
||||
{
|
||||
uint32_t buffer[2 + WORDS_PER_FRAME];
|
||||
size_t i;
|
||||
#define BUFSZ 16 /* FIXME: Arbitrary restriction */
|
||||
uint32_t buffer[BUFSZ], devices, device;
|
||||
size_t bufused, i;
|
||||
|
||||
/* Set up the basic buffer */
|
||||
bufused = 4;
|
||||
buffer[0] = htonl(NETPLAY_CMD_INPUT);
|
||||
buffer[1] = htonl(WORDS_PER_FRAME * sizeof(uint32_t));
|
||||
buffer[2] = htonl(frame);
|
||||
buffer[3] = htonl(player);
|
||||
buffer[4] = htonl(state[0]);
|
||||
buffer[5] = htonl(state[1]);
|
||||
buffer[6] = htonl(state[2]);
|
||||
buffer[2] = htonl(dframe->frame);
|
||||
buffer[3] = htonl(client_num);
|
||||
|
||||
/* Add the device data */
|
||||
devices = netplay->client_devices[client_num];
|
||||
for (device = 0; device < devices; device++)
|
||||
{
|
||||
netplay_input_state_t istate;
|
||||
if (!(devices & (1<<device)))
|
||||
continue;
|
||||
istate = dframe->real_input[device];
|
||||
while (istate && istate->client_num != client_num)
|
||||
istate = istate->next;
|
||||
if (!istate)
|
||||
continue;
|
||||
if (bufused + istate->size >= BUFSZ)
|
||||
continue; /* FIXME: More severe? */
|
||||
for (i = 0; i < istate->size; i++)
|
||||
buffer[bufused+i] = htonl(istate->data[i]);
|
||||
bufused += istate->size;
|
||||
}
|
||||
buffer[1] = htonl((bufused-2) * sizeof(uint32_t));
|
||||
|
||||
if (only)
|
||||
{
|
||||
if (!netplay_send(&only->send_packet_buffer, only->fd, buffer, sizeof(buffer)))
|
||||
if (!netplay_send(&only->send_packet_buffer, only->fd, buffer, bufused*sizeof(uint32_t)))
|
||||
{
|
||||
netplay_hangup(netplay, only);
|
||||
return false;
|
||||
@ -221,16 +256,17 @@ static bool send_input_frame(netplay_t *netplay,
|
||||
if (connection->active &&
|
||||
connection->mode >= NETPLAY_CONNECTION_CONNECTED &&
|
||||
(connection->mode != NETPLAY_CONNECTION_PLAYING ||
|
||||
connection->player != player))
|
||||
i+1 != client_num))
|
||||
{
|
||||
if (!netplay_send(&connection->send_packet_buffer, connection->fd,
|
||||
buffer, sizeof(buffer)))
|
||||
buffer, bufused*sizeof(uint32_t)))
|
||||
netplay_hangup(netplay, connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
#undef BUFSZ
|
||||
}
|
||||
|
||||
/**
|
||||
@ -243,24 +279,50 @@ static bool send_input_frame(netplay_t *netplay,
|
||||
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 player;
|
||||
uint32_t from_client, to_client;
|
||||
uint32_t devices, device;
|
||||
size_t i;
|
||||
netplay_input_state_t istate;
|
||||
|
||||
to_client = connection - netplay->connections + 1;
|
||||
|
||||
if (netplay->is_server)
|
||||
{
|
||||
/* Send the other players' input data */
|
||||
for (player = 0; player < MAX_USERS; player++)
|
||||
/* Send the other players' input data (FIXME: This involves an
|
||||
* unacceptable amount of recalculating) */
|
||||
for (from_client = 1; from_client < MAX_CLIENTS; from_client++)
|
||||
{
|
||||
if (connection->mode == NETPLAY_CONNECTION_PLAYING &&
|
||||
connection->player == player)
|
||||
if (from_client == to_client)
|
||||
continue;
|
||||
if ((netplay->connected_players & (1<<player)))
|
||||
if ((netplay->connected_players1 & (1<<from_client)))
|
||||
{
|
||||
if (dframe->have_real[player])
|
||||
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, player,
|
||||
dframe->real_input_state[player]))
|
||||
netplay->self_frame_count, from_client, bufused, buffer))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -281,12 +343,32 @@ 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_player,
|
||||
dframe->self_state))
|
||||
(netplay->is_server ? NETPLAY_CMD_INPUT_BIT_SERVER : 0) | netplay->self_client_num,
|
||||
bufused, buffer))
|
||||
return false;
|
||||
}
|
||||
#undef BUFSZ
|
||||
|
||||
if (!netplay_send_flush(&connection->send_packet_buffer, connection->fd,
|
||||
false))
|
||||
@ -436,7 +518,7 @@ bool netplay_cmd_mode(netplay_t *netplay,
|
||||
case NETPLAY_CONNECTION_SLAVE:
|
||||
payload = &payloadBuf;
|
||||
payloadBuf = htonl(NETPLAY_CMD_PLAY_BIT_SLAVE);
|
||||
/* Intentional fallthrough */
|
||||
/* no break */
|
||||
|
||||
case NETPLAY_CONNECTION_PLAYING:
|
||||
cmd = NETPLAY_CMD_PLAY;
|
||||
@ -506,43 +588,56 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
|
||||
case NETPLAY_CMD_INPUT:
|
||||
{
|
||||
uint32_t buffer[WORDS_PER_FRAME];
|
||||
uint32_t player;
|
||||
uint32_t frame_num, client_num, input_size, devices, device;
|
||||
bool is_server;
|
||||
unsigned i;
|
||||
struct delta_frame *dframe;
|
||||
|
||||
if (cmd_size != WORDS_PER_FRAME * sizeof(uint32_t))
|
||||
if (cmd_size < 2*sizeof(uint32_t))
|
||||
{
|
||||
RARCH_ERR("NETPLAY_CMD_INPUT received an unexpected payload size.\n");
|
||||
RARCH_ERR("NETPLAY_CMD_INPUT too short, no frame/client number.");
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
}
|
||||
|
||||
RECV(buffer, sizeof(buffer))
|
||||
{
|
||||
RARCH_ERR("Failed to receive NETPLAY_CMD_INPUT input.\n");
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
}
|
||||
|
||||
for (i = 0; i < WORDS_PER_FRAME; i++)
|
||||
buffer[i] = ntohl(buffer[i]);
|
||||
RECV(&frame_num, sizeof(frame_num))
|
||||
return false;
|
||||
RECV(&client_num, sizeof(client_num))
|
||||
return false;
|
||||
frame_num = nhtohl(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)
|
||||
{
|
||||
/* Ignore the claimed player #, must be this client */
|
||||
/* Ignore the claimed client #, must be this client */
|
||||
if (connection->mode != NETPLAY_CONNECTION_PLAYING &&
|
||||
connection->mode != NETPLAY_CONNECTION_SLAVE)
|
||||
{
|
||||
RARCH_ERR("Netplay input from non-participating player.\n");
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
}
|
||||
player = connection->player;
|
||||
}
|
||||
else
|
||||
{
|
||||
player = buffer[1] & ~NETPLAY_CMD_INPUT_BIT_SERVER;
|
||||
is_server = false;
|
||||
client_num = connection - netplay->connections + 1;
|
||||
}
|
||||
|
||||
if (player >= MAX_USERS || !(netplay->connected_players & (1<<player)))
|
||||
if (client_num > MAX_CLIENTS)
|
||||
{
|
||||
RARCH_ERROR("NETPLAY_CMD_INPUT received data for an unsupported client.\n");
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
}
|
||||
|
||||
/* Figure out how much input is expected */
|
||||
devices = netplay->client_devices[client_num];
|
||||
input_size = netplay_expected_input_size(devices);
|
||||
|
||||
if (cmd_size != (2+input_size) * sizeof(uint32_t))
|
||||
{
|
||||
RARCH_ERR("NETPLAY_CMD_INPUT received an unexpected payload size.\n");
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
}
|
||||
|
||||
if (client_num >= MAX_CLIENTS || !(netplay->connected_players1 & (1<<client_num)))
|
||||
{
|
||||
RARCH_ERR("Invalid NETPLAY_CMD_INPUT player number.\n");
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
@ -551,12 +646,12 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
/* Check the frame number only if they're not in slave mode */
|
||||
if (connection->mode == NETPLAY_CONNECTION_PLAYING)
|
||||
{
|
||||
if (buffer[0] < netplay->read_frame_count[player])
|
||||
if (frame_num < netplay->read_frame_count1[client_num])
|
||||
{
|
||||
/* We already had this, so ignore the new transmission */
|
||||
break;
|
||||
}
|
||||
else if (buffer[0] > netplay->read_frame_count[player])
|
||||
else if (frame_num > netplay->read_frame_count1[client_num])
|
||||
{
|
||||
/* Out of order = out of luck */
|
||||
RARCH_ERR("Netplay input out of order.\n");
|
||||
@ -565,42 +660,57 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
}
|
||||
|
||||
/* The data's good! */
|
||||
dframe = &netplay->buffer[netplay->read_ptr[player]];
|
||||
if (!netplay_delta_frame_ready(netplay, dframe, netplay->read_frame_count[player]))
|
||||
dframe = &netplay->buffer[netplay->read_ptr1[client_num]];
|
||||
if (!netplay_delta_frame_ready(netplay, dframe, netplay->read_frame_count1[client_num]))
|
||||
{
|
||||
/* Hopefully we'll be ready after another round of input */
|
||||
goto shrt;
|
||||
}
|
||||
memcpy(dframe->real_input_state[player], buffer + 2,
|
||||
WORDS_PER_INPUT*sizeof(uint32_t));
|
||||
dframe->have_real[player] = true;
|
||||
|
||||
/* Copy in the input */
|
||||
for (device = 0; device < MAX_INPUT_DEVICES; device++)
|
||||
{
|
||||
netplay_input_state_t istate;
|
||||
uint32_t dsize, di;
|
||||
if (!(devices & (1<<device)))
|
||||
continue;
|
||||
|
||||
dsize = netplay_expected_input_size(1 << device);
|
||||
istate = netplay_input_state_for(&dframe->real_input[device],
|
||||
client_num, dsize, true);
|
||||
RECV(istate->data, dsize*sizeof(uint32_t))
|
||||
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;
|
||||
|
||||
/* Slaves may go through several packets of data in the same frame
|
||||
* if latency is choppy, so we advance and send their data after
|
||||
* handling all network data this frame */
|
||||
if (connection->mode == NETPLAY_CONNECTION_PLAYING)
|
||||
{
|
||||
netplay->read_ptr[player] = NEXT_PTR(netplay->read_ptr[player]);
|
||||
netplay->read_frame_count[player]++;
|
||||
netplay->read_ptr1[client_num] = NEXT_PTR(netplay->read_ptr1[client_num]);
|
||||
netplay->read_frame_count1[client_num]++;
|
||||
|
||||
if (netplay->is_server)
|
||||
{
|
||||
/* Forward it on if it's past data*/
|
||||
/* Forward it on if it's past data */
|
||||
if (dframe->frame <= netplay->self_frame_count)
|
||||
send_input_frame(netplay, NULL, connection, buffer[0],
|
||||
player, dframe->real_input_state[player]);
|
||||
send_input_frame(netplay, dframe, NULL, connection, client_num);
|
||||
}
|
||||
}
|
||||
|
||||
/* If this was server data, advance our server pointer too */
|
||||
if (!netplay->is_server && (buffer[1] & NETPLAY_CMD_INPUT_BIT_SERVER))
|
||||
if (is_server)
|
||||
{
|
||||
netplay->server_ptr = netplay->read_ptr[player];
|
||||
netplay->server_frame_count = netplay->read_frame_count[player];
|
||||
netplay->server_ptr = netplay->read_ptr1[client_num];
|
||||
netplay->server_frame_count = netplay->read_frame_count1[client_num];
|
||||
}
|
||||
|
||||
#ifdef DEBUG_NETPLAY_STEPS
|
||||
RARCH_LOG("Received input from %u\n", player);
|
||||
RARCH_LOG("Received input from %u\n", client_num);
|
||||
print_state(netplay);
|
||||
#endif
|
||||
break;
|
||||
@ -685,7 +795,9 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
|
||||
case NETPLAY_CMD_SPECTATE:
|
||||
{
|
||||
uint32_t payload[2];
|
||||
uint32_t payload[3];
|
||||
uint32_t client_num;
|
||||
size_t i;
|
||||
|
||||
if (!netplay->is_server)
|
||||
{
|
||||
@ -693,20 +805,25 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
}
|
||||
|
||||
client_num = connection - netplay->connections + 1;
|
||||
|
||||
if (connection->mode == NETPLAY_CONNECTION_PLAYING ||
|
||||
connection->mode == NETPLAY_CONNECTION_SLAVE)
|
||||
{
|
||||
/* The frame we haven't received is their end frame */
|
||||
connection->delay_frame = netplay->read_frame_count[connection->player];
|
||||
connection->delay_frame = netplay->read_frame_count1[client_num];
|
||||
|
||||
/* Mark them as not playing anymore */
|
||||
connection->mode = NETPLAY_CONNECTION_SPECTATING;
|
||||
netplay->connected_players &= ~(1<<connection->player);
|
||||
netplay->connected_slaves &= ~(1<<connection->player);
|
||||
netplay->connected_players1 &= ~(1<<client_num);
|
||||
netplay->connected_slaves1 &= ~(1<<client_num);
|
||||
netplay->client_devices[client_num] = 0;
|
||||
for (i = 0; i < MAX_INPUT_DEVICES; i++)
|
||||
netplay->device_clients[client_num] &= ~(1<<client_num);
|
||||
|
||||
/* Announce it */
|
||||
msg[sizeof(msg)-1] = '\0';
|
||||
snprintf(msg, sizeof(msg)-1, "Player %d has left", connection->player+1);
|
||||
snprintf(msg, sizeof(msg)-1, "Player %d has left", client_num+1);
|
||||
RARCH_LOG("%s\n", msg);
|
||||
runloop_msg_queue_push(msg, 1, 180, false);
|
||||
}
|
||||
@ -716,30 +833,32 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
}
|
||||
|
||||
/* Tell the player even if they were confused */
|
||||
payload[1] = htonl(NETPLAY_CMD_MODE_BIT_YOU | connection->player);
|
||||
payload[1] = htonl(NETPLAY_CMD_MODE_BIT_YOU | client_num);
|
||||
payload[2] = htonl(0);
|
||||
netplay_send_raw_cmd(netplay, connection, NETPLAY_CMD_MODE, payload, sizeof(payload));
|
||||
break;
|
||||
}
|
||||
|
||||
case NETPLAY_CMD_PLAY:
|
||||
{
|
||||
uint32_t payload[2];
|
||||
uint32_t player = 0;
|
||||
uint32_t devices = 0, device, client_num;
|
||||
uint32_t payload[3];
|
||||
bool slave = false;
|
||||
settings_t *settings = config_get_ptr();
|
||||
|
||||
/* Check if they requested slave mode */
|
||||
if (cmd_size == sizeof(uint32_t))
|
||||
{
|
||||
RECV(payload, sizeof(uint32_t))
|
||||
RECV(&devices, sizeof(devices))
|
||||
{
|
||||
RARCH_ERR("Failed to receive NETPLAY_CMD_PLAY payload.\n");
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
}
|
||||
|
||||
payload[0] = ntohl(payload[0]);
|
||||
if (payload[0] & NETPLAY_CMD_PLAY_BIT_SLAVE)
|
||||
devices = ntohl(devices);
|
||||
if (devices & NETPLAY_CMD_PLAY_BIT_SLAVE)
|
||||
slave = true;
|
||||
devices &= ~(NETPLAY_CMD_PLAY_BIT_SLAVE);
|
||||
}
|
||||
else if (cmd_size != 0)
|
||||
{
|
||||
@ -760,6 +879,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
RARCH_ERR("NETPLAY_CMD_PLAY from a server.\n");
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
}
|
||||
client_num = connection - netplay->connections + 1;
|
||||
|
||||
if (connection->delay_frame)
|
||||
{
|
||||
@ -777,21 +897,20 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
break;
|
||||
}
|
||||
|
||||
/* Find an available player slot */
|
||||
for (player = 0; player <= netplay->player_max; player++)
|
||||
/* Find an available device (FIXME: Honor device request) */
|
||||
for (device = 0; device <= netplay->input_device_max; device++)
|
||||
{
|
||||
if (!(netplay->self_mode == NETPLAY_CONNECTION_PLAYING &&
|
||||
netplay->self_player == player) &&
|
||||
!(netplay->connected_players & (1<<player)))
|
||||
if (!netplay->device_clients[device])
|
||||
break;
|
||||
}
|
||||
if (player > netplay->player_max)
|
||||
if (device > netplay->input_device_max)
|
||||
{
|
||||
/* No slots free! */
|
||||
payload[0] = htonl(NETPLAY_CMD_MODE_REFUSED_REASON_NO_SLOTS);
|
||||
netplay_send_raw_cmd(netplay, connection, NETPLAY_CMD_MODE_REFUSED, payload, sizeof(uint32_t));
|
||||
break;
|
||||
}
|
||||
payload[2] = htonl(1<<device);
|
||||
|
||||
if (connection->mode != NETPLAY_CONNECTION_PLAYING &&
|
||||
connection->mode != NETPLAY_CONNECTION_SLAVE)
|
||||
@ -799,20 +918,22 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
/* Mark them as playing */
|
||||
connection->mode = slave ? NETPLAY_CONNECTION_SLAVE :
|
||||
NETPLAY_CONNECTION_PLAYING;
|
||||
connection->player = player;
|
||||
netplay->connected_players |= 1<<player;
|
||||
|
||||
netplay->connected_players1 |= 1<<client_num;
|
||||
if (slave)
|
||||
netplay->connected_slaves |= 1<<player;
|
||||
netplay->connected_slaves1 |= 1<<client_num;
|
||||
netplay->client_devices[client_num] |= 1<<device;
|
||||
netplay->device_clients[device] |= 1<<client_num;
|
||||
|
||||
/* Tell everyone */
|
||||
payload[1] = htonl(NETPLAY_CMD_MODE_BIT_PLAYING |
|
||||
(slave?NETPLAY_CMD_MODE_BIT_SLAVE:0) |
|
||||
connection->player);
|
||||
client_num);
|
||||
netplay_send_raw_cmd_all(netplay, connection, NETPLAY_CMD_MODE, payload, sizeof(payload));
|
||||
|
||||
/* Announce it */
|
||||
msg[sizeof(msg)-1] = '\0';
|
||||
snprintf(msg, sizeof(msg)-1, "Player %d has joined", player+1);
|
||||
snprintf(msg, sizeof(msg)-1, "Player %d has joined", client_num+1);
|
||||
RARCH_LOG("%s\n", msg);
|
||||
runloop_msg_queue_push(msg, 1, 180, false);
|
||||
|
||||
@ -823,19 +944,20 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
((connection->mode == NETPLAY_CONNECTION_SLAVE)?
|
||||
NETPLAY_CMD_MODE_BIT_SLAVE:0) |
|
||||
NETPLAY_CMD_MODE_BIT_YOU |
|
||||
connection->player);
|
||||
client_num);
|
||||
payload[2] = htonl(1<<device);
|
||||
netplay_send_raw_cmd(netplay, connection, NETPLAY_CMD_MODE, payload, sizeof(payload));
|
||||
|
||||
/* And expect their data */
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
||||
case NETPLAY_CMD_MODE:
|
||||
{
|
||||
uint32_t payload[2];
|
||||
uint32_t frame, mode, player;
|
||||
uint32_t payload[3];
|
||||
uint32_t frame, mode, client_num, devices;
|
||||
size_t ptr;
|
||||
struct delta_frame *dframe;
|
||||
|
||||
@ -870,13 +992,15 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
netplay->force_rewind = true;
|
||||
|
||||
mode = ntohl(payload[1]);
|
||||
player = mode & 0xFFFF;
|
||||
if (player >= MAX_USERS)
|
||||
client_num = mode & 0xFFFF;
|
||||
if (client_num >= MAX_CLIENTS)
|
||||
{
|
||||
RARCH_ERR("Received NETPLAY_CMD_MODE for a higher player number than we support.\n");
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
}
|
||||
|
||||
devices = ntohl(payload[2]);
|
||||
|
||||
if (mode & NETPLAY_CMD_MODE_BIT_YOU)
|
||||
{
|
||||
/* A change to me! */
|
||||
@ -897,24 +1021,22 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
|
||||
/* Our mode is based on whether we have the slave bit set */
|
||||
if (mode & NETPLAY_CMD_MODE_BIT_SLAVE)
|
||||
{
|
||||
netplay->self_mode = NETPLAY_CONNECTION_SLAVE;
|
||||
|
||||
/* In slave mode we receive the data from the remote side, so
|
||||
* we actually consider ourself a connected player */
|
||||
netplay->connected_players |= (1<<player);
|
||||
netplay->read_ptr[player] = netplay->server_ptr;
|
||||
netplay->read_frame_count[player] = netplay->server_frame_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
netplay->self_mode = NETPLAY_CONNECTION_PLAYING;
|
||||
}
|
||||
netplay->self_player = player;
|
||||
|
||||
netplay->connected_players1 |= (1<<client_num);
|
||||
netplay->client_devices[client_num] = devices;
|
||||
for (device = 0; device < MAX_INPUT_DEVICES; device++)
|
||||
if (devices & (1<<device))
|
||||
netplay->device_clients[device] |= (1<<client_num);
|
||||
netplay->self_devices = devices;
|
||||
|
||||
/* Fix up current frame info */
|
||||
if (frame <= netplay->self_frame_count)
|
||||
{
|
||||
/* FIXME: Must generate frames with 0 data */
|
||||
#if 0
|
||||
/* It wanted past frames, better send 'em! */
|
||||
START(netplay->server_ptr);
|
||||
while (dframe->used && dframe->frame <= netplay->self_frame_count)
|
||||
@ -925,11 +1047,13 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
if (dframe->frame == netplay->self_frame_count) break;
|
||||
NEXT();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t frame_count;
|
||||
netplay_input_state_t istate;
|
||||
|
||||
/* It wants future frames, make sure we don't capture or send intermediate ones */
|
||||
START(netplay->self_ptr);
|
||||
@ -946,8 +1070,6 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
}
|
||||
}
|
||||
|
||||
memset(dframe->self_state, 0, sizeof(dframe->self_state));
|
||||
memset(dframe->real_input_state[player], 0, sizeof(dframe->self_state));
|
||||
dframe->have_local = true;
|
||||
|
||||
/* Go on to the next delta frame */
|
||||
@ -962,7 +1084,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
|
||||
/* Announce it */
|
||||
msg[sizeof(msg)-1] = '\0';
|
||||
snprintf(msg, sizeof(msg)-1, "You have joined as player %d", player+1);
|
||||
snprintf(msg, sizeof(msg)-1, "You have joined as player %d", client_num+1);
|
||||
RARCH_LOG("%s\n", msg);
|
||||
runloop_msg_queue_push(msg, 1, 180, false);
|
||||
|
||||
@ -982,7 +1104,10 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
}
|
||||
|
||||
/* Unmark ourself, in case we were in slave mode */
|
||||
netplay->connected_players &= ~(1<<player);
|
||||
netplay->connected_players1 &= ~(1<<client_num);
|
||||
netplay->client_devices[client_num] = 0;
|
||||
for (device = 0; device < MAX_INPUT_DEVICES; device++)
|
||||
netplay->device_clients[device] &= ~(1<<client_num);
|
||||
|
||||
/* Announce it */
|
||||
strlcpy(msg, "You have left the game", sizeof(msg));
|
||||
@ -1008,14 +1133,18 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
}
|
||||
|
||||
netplay->connected_players |= (1<<player);
|
||||
netplay->connected_players1 |= (1<<client_num);
|
||||
netplay->client_devices[client_num] = devices;
|
||||
for (device = 0; device < MAX_INPUT_DEVICES; device++)
|
||||
if (devices & (1<<device))
|
||||
netplay->device_clients[device] |= (1<<client_num);
|
||||
|
||||
netplay->read_ptr[player] = netplay->server_ptr;
|
||||
netplay->read_frame_count[player] = netplay->server_frame_count;
|
||||
netplay->read_ptr1[client_num] = netplay->server_ptr;
|
||||
netplay->read_frame_count1[client_num] = netplay->server_frame_count;
|
||||
|
||||
/* Announce it */
|
||||
msg[sizeof(msg)-1] = '\0';
|
||||
snprintf(msg, sizeof(msg)-1, "Player %d has joined", player+1);
|
||||
snprintf(msg, sizeof(msg)-1, "Player %d has joined", client_num+1);
|
||||
RARCH_LOG("%s\n", msg);
|
||||
runloop_msg_queue_push(msg, 1, 180, false);
|
||||
|
||||
@ -1027,11 +1156,14 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
}
|
||||
else
|
||||
{
|
||||
netplay->connected_players &= ~(1<<player);
|
||||
netplay->connected_players1 &= ~(1<<client_num);
|
||||
netplay->client_devices[client_num] = 0;
|
||||
for (device = 0; device < MAX_INPUT_DEVICES; device++)
|
||||
netplay->device_clients[device] &= ~(1<<client_num);
|
||||
|
||||
/* Announce it */
|
||||
msg[sizeof(msg)-1] = '\0';
|
||||
snprintf(msg, sizeof(msg)-1, "Player %d has left", player+1);
|
||||
snprintf(msg, sizeof(msg)-1, "Player %d has left", client_num+1);
|
||||
RARCH_LOG("%s\n", msg);
|
||||
runloop_msg_queue_push(msg, 1, 180, false);
|
||||
|
||||
|
@ -28,10 +28,7 @@
|
||||
#include "../../msg_hash.h"
|
||||
#include "../../verbosity.h"
|
||||
|
||||
#define WORDS_PER_INPUT 3 /* Buttons, left stick, right stick */
|
||||
#define WORDS_PER_FRAME (WORDS_PER_INPUT+2) /* + frameno, playerno */
|
||||
|
||||
#define NETPLAY_PROTOCOL_VERSION 4
|
||||
#define NETPLAY_PROTOCOL_VERSION 5
|
||||
|
||||
#define RARCH_DEFAULT_PORT 55435
|
||||
#define RARCH_DEFAULT_NICK "Anonymous"
|
||||
@ -45,6 +42,17 @@
|
||||
#define CATCH_UP_CHECK_TIME_USEC (500*1000)
|
||||
#define MAX_RETRIES 16
|
||||
#define RETRY_MS 500
|
||||
#define MAX_INPUT_DEVICES 16
|
||||
#undef MAX_USERS /* FIXME: Temporary */
|
||||
|
||||
/* We allow only 32 clients to fit into a 32-bit bitmap */
|
||||
#define MAX_CLIENTS 32
|
||||
typedef uint32_t client_bitmap_t;
|
||||
|
||||
/* For now we only support the normal or analog gamepad */
|
||||
#define NETPLAY_SUPPORTED_DEVICES ( \
|
||||
(1<<RETRO_DEVICE_JOYPAD) | \
|
||||
(1<<RETRO_DEVICE_ANALOG))
|
||||
|
||||
#define NETPLAY_MAX_STALL_FRAMES 60
|
||||
#define NETPLAY_FRAME_RUN_TIME_WINDOW 120
|
||||
@ -177,7 +185,7 @@ enum netplay_cmd
|
||||
|
||||
#define NETPLAY_CMD_INPUT_BIT_SERVER (1U<<31)
|
||||
#define NETPLAY_CMD_SYNC_BIT_PAUSED (1U<<31)
|
||||
#define NETPLAY_CMD_PLAY_BIT_SLAVE (1U)
|
||||
#define NETPLAY_CMD_PLAY_BIT_SLAVE (1U<<31)
|
||||
#define NETPLAY_CMD_MODE_BIT_SLAVE (1U<<18)
|
||||
#define NETPLAY_CMD_MODE_BIT_PLAYING (1U<<17)
|
||||
#define NETPLAY_CMD_MODE_BIT_YOU (1U<<16)
|
||||
@ -240,7 +248,24 @@ enum rarch_netplay_stall_reason
|
||||
NETPLAY_STALL_NO_CONNECTION
|
||||
};
|
||||
|
||||
typedef uint32_t netplay_input_state_t[WORDS_PER_INPUT];
|
||||
/* Input state for a particular client-device pair */
|
||||
typedef struct netplay_input_state
|
||||
{
|
||||
/* The next input state (forming a list) */
|
||||
struct netplay_input_state *next;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* The input data itself (note: should expand beyond 1 by overallocating). */
|
||||
uint32_t data[1];
|
||||
} *netplay_input_state_t;
|
||||
|
||||
struct delta_frame
|
||||
{
|
||||
@ -253,20 +278,26 @@ struct delta_frame
|
||||
/* The CRC-32 of the serialized state if we've calculated it, else 0 */
|
||||
uint32_t crc;
|
||||
|
||||
/* The real, simulated and local input. If we're playing, self_state is
|
||||
* mirrored to the appropriate real_input_state player. */
|
||||
netplay_input_state_t real_input_state[MAX_USERS];
|
||||
netplay_input_state_t simulated_input_state[MAX_USERS];
|
||||
netplay_input_state_t self_state;
|
||||
/* 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 real input */
|
||||
netplay_input_state_t real_input[MAX_INPUT_DEVICES];
|
||||
|
||||
/* The simulated input. is_real here means the simulation is done, i.e.,
|
||||
* it's a real simulation, not real input. */
|
||||
netplay_input_state_t simulated_input[MAX_INPUT_DEVICES];
|
||||
|
||||
/* Have we read local input? */
|
||||
bool have_local;
|
||||
|
||||
/* Have we read the real (remote) input? */
|
||||
bool have_real[MAX_USERS];
|
||||
bool have_real[MAX_CLIENTS];
|
||||
|
||||
/* Is the current state as of self_frame_count using the real (remote) data? */
|
||||
bool used_real[MAX_USERS];
|
||||
bool used_real[MAX_CLIENTS];
|
||||
};
|
||||
|
||||
struct socket_buffer
|
||||
@ -309,9 +340,6 @@ struct netplay_connection
|
||||
* to wait for, or 0 if no delay is active. */
|
||||
uint32_t delay_frame;
|
||||
|
||||
/* Player # of connected player */
|
||||
uint32_t player;
|
||||
|
||||
/* What compression does this peer support? */
|
||||
uint32_t compression_supported;
|
||||
|
||||
@ -350,8 +378,8 @@ struct netplay
|
||||
/* TCP connection for listening (server only) */
|
||||
int listen_fd;
|
||||
|
||||
/* Our player number */
|
||||
uint32_t self_player;
|
||||
/* Our client number */
|
||||
uint32_t self_client_num;
|
||||
|
||||
/* Our mode and status */
|
||||
enum rarch_netplay_connection_mode self_mode;
|
||||
@ -361,19 +389,28 @@ struct netplay
|
||||
size_t connections_size;
|
||||
struct netplay_connection one_connection; /* Client only */
|
||||
|
||||
/* Bitmap of players with controllers (low bit is player 1) */
|
||||
uint32_t connected_players;
|
||||
/* Bitmap of clients with input devices */
|
||||
uint32_t connected_players1;
|
||||
|
||||
/* Bitmap of players playing in slave mode (should be a subset of
|
||||
/* Bitmap of clients playing in slave mode (should be a subset of
|
||||
* connected_players) */
|
||||
uint32_t connected_slaves;
|
||||
uint32_t connected_slaves1;
|
||||
|
||||
/* For each client, the bitmap of devices they're connected to */
|
||||
uint32_t client_devices[MAX_CLIENTS];
|
||||
|
||||
/* For each device, the bitmap of clients connected */
|
||||
client_bitmap_t device_clients[MAX_INPUT_DEVICES];
|
||||
|
||||
/* Our own device bitmap */
|
||||
uint32_t self_devices;
|
||||
|
||||
/* Number of desync operations we're currently performing. If set, we don't
|
||||
* attempt to stay in sync. */
|
||||
uint32_t desync;
|
||||
|
||||
/* Maximum player number */
|
||||
uint32_t player_max;
|
||||
/* Maximum input device number */
|
||||
uint32_t input_device_max;
|
||||
|
||||
struct retro_callbacks cbs;
|
||||
|
||||
@ -418,9 +455,9 @@ struct netplay
|
||||
size_t unread_ptr;
|
||||
uint32_t unread_frame_count;
|
||||
|
||||
/* Pointer to the next frame to read from each player */
|
||||
size_t read_ptr[MAX_USERS];
|
||||
uint32_t read_frame_count[MAX_USERS];
|
||||
/* Pointer to the next frame to read from each client */
|
||||
size_t read_ptr1[MAX_CLIENTS];
|
||||
uint32_t read_frame_count1[MAX_CLIENTS];
|
||||
|
||||
/* Pointer to the next frame to read from the server (as it might not be a
|
||||
* player but still synchronizes) */
|
||||
@ -457,7 +494,8 @@ struct netplay
|
||||
bool savestate_request_outstanding;
|
||||
|
||||
/* A buffer for outgoing input packets. */
|
||||
uint32_t input_packet_buffer[2 + WORDS_PER_FRAME];
|
||||
size_t input_packet_buffer_size;
|
||||
uint32_t *input_packet_buffer1;
|
||||
|
||||
/* Our local socket info */
|
||||
struct addrinfo *addr;
|
||||
@ -608,6 +646,14 @@ 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_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);
|
||||
|
||||
|
||||
/***************************************************************
|
||||
* NETPLAY-DISCOVERY.C
|
||||
|
@ -39,7 +39,7 @@
|
||||
*/
|
||||
void netplay_update_unread_ptr(netplay_t *netplay)
|
||||
{
|
||||
if (netplay->is_server && !netplay->connected_players)
|
||||
if (netplay->is_server && netplay->connected_players1<=1)
|
||||
{
|
||||
/* Nothing at all to read! */
|
||||
netplay->unread_ptr = netplay->self_ptr;
|
||||
@ -50,16 +50,16 @@ void netplay_update_unread_ptr(netplay_t *netplay)
|
||||
{
|
||||
size_t new_unread_ptr = 0;
|
||||
uint32_t new_unread_frame_count = (uint32_t) -1;
|
||||
uint32_t player;
|
||||
uint32_t client;
|
||||
|
||||
for (player = 0; player < MAX_USERS; player++)
|
||||
for (client = 0; client < MAX_CLIENTS; client++)
|
||||
{
|
||||
if (!(netplay->connected_players & (1<<player))) continue;
|
||||
if ((netplay->connected_slaves & (1<<player))) continue;
|
||||
if (netplay->read_frame_count[player] < new_unread_frame_count)
|
||||
if (!(netplay->connected_players1 & (1<<client))) continue;
|
||||
if ((netplay->connected_slaves1 & (1<<client))) continue;
|
||||
if (netplay->read_frame_count1[client] < new_unread_frame_count)
|
||||
{
|
||||
new_unread_ptr = netplay->read_ptr[player];
|
||||
new_unread_frame_count = netplay->read_frame_count[player];
|
||||
new_unread_ptr = netplay->read_ptr1[client];
|
||||
new_unread_frame_count = netplay->read_frame_count1[client];
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,19 +93,28 @@ void netplay_update_unread_ptr(netplay_t *netplay)
|
||||
*/
|
||||
void netplay_simulate_input(netplay_t *netplay, size_t sim_ptr, bool resim)
|
||||
{
|
||||
uint32_t player;
|
||||
uint32_t client;
|
||||
size_t prev;
|
||||
struct delta_frame *simframe, *pframe;
|
||||
netplay_input_state_t simstate, pstate;
|
||||
|
||||
simframe = &netplay->buffer[sim_ptr];
|
||||
|
||||
for (player = 0; player < MAX_USERS; player++)
|
||||
for (client = 0; client < MAX_CLIENTS; client++)
|
||||
{
|
||||
if (!(netplay->connected_players & (1<<player))) continue;
|
||||
if (simframe->have_real[player]) continue;
|
||||
if (!(netplay->connected_players1 & (1<<client))) continue;
|
||||
// FIXME: Maybe this is the right time to do resolved data?
|
||||
if (simframe->have_real[client]) continue;
|
||||
|
||||
prev = PREV_PTR(netplay->read_ptr[player]);
|
||||
simstate = netplay_input_state_for(&simframe->simulated_input, 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, client, 3 /* FIXME */, false);
|
||||
if (!pstate)
|
||||
continue;
|
||||
|
||||
if (resim)
|
||||
{
|
||||
@ -128,15 +137,13 @@ void netplay_simulate_input(netplay_t *netplay, size_t sim_ptr, bool resim)
|
||||
(1U<<RETRO_DEVICE_ID_JOYPAD_DOWN) |
|
||||
(1U<<RETRO_DEVICE_ID_JOYPAD_LEFT) |
|
||||
(1U<<RETRO_DEVICE_ID_JOYPAD_RIGHT);
|
||||
uint32_t sim_state = simframe->simulated_input_state[player][0] & keep;
|
||||
sim_state |= pframe->real_input_state[player][0] & ~keep;
|
||||
simframe->simulated_input_state[player][0] = sim_state;
|
||||
simstate->data[0] &= keep;
|
||||
simstate->data[0] |= pstate->data[0] & ~keep;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(simframe->simulated_input_state[player],
|
||||
pframe->real_input_state[player],
|
||||
WORDS_PER_INPUT * sizeof(uint32_t));
|
||||
memcpy(simstate->data, pstate->data,
|
||||
simstate->size * sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -391,7 +398,7 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
|
||||
}
|
||||
|
||||
/* Only relevant if we're connected and not in a desynching operation */
|
||||
if ((netplay->is_server && !netplay->connected_players) ||
|
||||
if ((netplay->is_server && (netplay->connected_players1>1)) ||
|
||||
(netplay->self_mode < NETPLAY_CONNECTION_CONNECTED) ||
|
||||
(netplay->desync))
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user