Initial implementation of Netplay master/slave mode.
This commit is contained in:
parent
bd9e2e5fc7
commit
e70ee045bf
|
@ -234,16 +234,22 @@ Description:
|
||||||
itself to be in spectator mode and send no further input.
|
itself to be in spectator mode and send no further input.
|
||||||
|
|
||||||
Command: PLAY
|
Command: PLAY
|
||||||
Payload: None
|
Payload:
|
||||||
|
{
|
||||||
|
reserved: 31 bits
|
||||||
|
as slave?: 1 bit
|
||||||
|
}
|
||||||
Description:
|
Description:
|
||||||
Request to enter player mode. The client must wait for a MODE command
|
Request to enter player mode. The client must wait for a MODE command
|
||||||
before sending input.
|
before sending input. Server may refuse or force slave connections, so the
|
||||||
|
request is not necessarily honored. Payload may be elided if zero.
|
||||||
|
|
||||||
Command: MODE
|
Command: MODE
|
||||||
Payload:
|
Payload:
|
||||||
{
|
{
|
||||||
frame number: uint32
|
frame number: uint32
|
||||||
reserved: 14 bits
|
reserved: 13 bits
|
||||||
|
slave: 1 bit
|
||||||
playing: 1 bit
|
playing: 1 bit
|
||||||
you: 1 bit
|
you: 1 bit
|
||||||
player number: uint16
|
player number: uint16
|
||||||
|
|
|
@ -220,6 +220,10 @@ static bool netplay_poll(void)
|
||||||
/* Simulate the input if we don't have real input */
|
/* Simulate the input if we don't have real input */
|
||||||
netplay_simulate_input(netplay_data, netplay_data->run_ptr, false);
|
netplay_simulate_input(netplay_data, netplay_data->run_ptr, false);
|
||||||
|
|
||||||
|
/* Handle any slaves */
|
||||||
|
if (netplay_data->is_server && netplay_data->connected_slaves)
|
||||||
|
netplay_handle_slaves(netplay_data);
|
||||||
|
|
||||||
netplay_update_unread_ptr(netplay_data);
|
netplay_update_unread_ptr(netplay_data);
|
||||||
|
|
||||||
/* Figure out how many frames of input latency we should be using to hide
|
/* Figure out how many frames of input latency we should be using to hide
|
||||||
|
@ -331,7 +335,7 @@ static bool netplay_poll(void)
|
||||||
/* If we're not stalled, consider stalling */
|
/* If we're not stalled, consider stalling */
|
||||||
if (!netplay_data->stall)
|
if (!netplay_data->stall)
|
||||||
{
|
{
|
||||||
/* Have we not reat enough latency frames? */
|
/* Have we not read enough latency frames? */
|
||||||
if (netplay_data->self_mode == NETPLAY_CONNECTION_PLAYING &&
|
if (netplay_data->self_mode == NETPLAY_CONNECTION_PLAYING &&
|
||||||
netplay_data->connected_players &&
|
netplay_data->connected_players &&
|
||||||
netplay_data->run_frame_count + netplay_data->input_latency_frames > netplay_data->self_frame_count)
|
netplay_data->run_frame_count + netplay_data->input_latency_frames > netplay_data->self_frame_count)
|
||||||
|
@ -943,7 +947,8 @@ static void netplay_toggle_play_spectate(netplay_t *netplay)
|
||||||
char msg[512];
|
char msg[512];
|
||||||
const char *dmsg = NULL;
|
const char *dmsg = NULL;
|
||||||
payload[0] = htonl(netplay->self_frame_count);
|
payload[0] = htonl(netplay->self_frame_count);
|
||||||
if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING)
|
if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING ||
|
||||||
|
netplay->self_mode == NETPLAY_CONNECTION_SLAVE)
|
||||||
{
|
{
|
||||||
/* Mark us as no longer playing */
|
/* Mark us as no longer playing */
|
||||||
payload[1] = htonl(netplay->self_player);
|
payload[1] = htonl(netplay->self_player);
|
||||||
|
@ -980,7 +985,8 @@ static void netplay_toggle_play_spectate(netplay_t *netplay)
|
||||||
{
|
{
|
||||||
uint32_t cmd;
|
uint32_t cmd;
|
||||||
|
|
||||||
if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING)
|
if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING ||
|
||||||
|
netplay->self_mode == NETPLAY_CONNECTION_SLAVE)
|
||||||
{
|
{
|
||||||
/* Switch to spectator mode immediately */
|
/* Switch to spectator mode immediately */
|
||||||
netplay->self_mode = NETPLAY_CONNECTION_SPECTATING;
|
netplay->self_mode = NETPLAY_CONNECTION_SPECTATING;
|
||||||
|
|
|
@ -129,9 +129,11 @@ void netplay_hangup(netplay_t *netplay, struct netplay_connection *connection)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Remove this player */
|
/* Remove this player */
|
||||||
if (connection->mode == NETPLAY_CONNECTION_PLAYING)
|
if (connection->mode == NETPLAY_CONNECTION_PLAYING ||
|
||||||
|
connection->mode == NETPLAY_CONNECTION_SLAVE)
|
||||||
{
|
{
|
||||||
netplay->connected_players &= ~(1<<connection->player);
|
netplay->connected_players &= ~(1<<connection->player);
|
||||||
|
netplay->connected_slaves &= ~(1<<connection->player);
|
||||||
|
|
||||||
/* FIXME: Duplication */
|
/* FIXME: Duplication */
|
||||||
if (netplay->is_server)
|
if (netplay->is_server)
|
||||||
|
@ -240,7 +242,8 @@ bool netplay_send_cur_input(netplay_t *netplay,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send our own data */
|
/* Send our own data */
|
||||||
if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING)
|
if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING ||
|
||||||
|
netplay->self_mode == NETPLAY_CONNECTION_SLAVE)
|
||||||
{
|
{
|
||||||
if (!send_input_frame(netplay, connection, NULL,
|
if (!send_input_frame(netplay, connection, NULL,
|
||||||
netplay->self_frame_count,
|
netplay->self_frame_count,
|
||||||
|
@ -364,12 +367,18 @@ bool netplay_cmd_mode(netplay_t *netplay,
|
||||||
enum rarch_netplay_connection_mode mode)
|
enum rarch_netplay_connection_mode mode)
|
||||||
{
|
{
|
||||||
uint32_t cmd;
|
uint32_t cmd;
|
||||||
|
uint32_t payloadBuf, *payload = NULL;
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case NETPLAY_CONNECTION_SPECTATING:
|
case NETPLAY_CONNECTION_SPECTATING:
|
||||||
cmd = NETPLAY_CMD_SPECTATE;
|
cmd = NETPLAY_CMD_SPECTATE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NETPLAY_CONNECTION_SLAVE:
|
||||||
|
payload = &payloadBuf;
|
||||||
|
payloadBuf = htonl(NETPLAY_CMD_PLAY_BIT_SLAVE);
|
||||||
|
/* Intentional fallthrough */
|
||||||
|
|
||||||
case NETPLAY_CONNECTION_PLAYING:
|
case NETPLAY_CONNECTION_PLAYING:
|
||||||
cmd = NETPLAY_CMD_PLAY;
|
cmd = NETPLAY_CMD_PLAY;
|
||||||
break;
|
break;
|
||||||
|
@ -377,7 +386,8 @@ bool netplay_cmd_mode(netplay_t *netplay,
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return netplay_send_raw_cmd(netplay, connection, cmd, NULL, 0);
|
return netplay_send_raw_cmd(netplay, connection, cmd, payload,
|
||||||
|
payload ? sizeof(uint32_t) : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -460,7 +470,8 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
if (netplay->is_server)
|
if (netplay->is_server)
|
||||||
{
|
{
|
||||||
/* Ignore the claimed player #, must be this client */
|
/* Ignore the claimed player #, must be this client */
|
||||||
if (connection->mode != NETPLAY_CONNECTION_PLAYING)
|
if (connection->mode != NETPLAY_CONNECTION_PLAYING &&
|
||||||
|
connection->mode != NETPLAY_CONNECTION_SLAVE)
|
||||||
{
|
{
|
||||||
RARCH_ERR("Netplay input from non-participating player.\n");
|
RARCH_ERR("Netplay input from non-participating player.\n");
|
||||||
return netplay_cmd_nak(netplay, connection);
|
return netplay_cmd_nak(netplay, connection);
|
||||||
|
@ -478,16 +489,20 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
return netplay_cmd_nak(netplay, connection);
|
return netplay_cmd_nak(netplay, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer[0] < netplay->read_frame_count[player])
|
/* Check the frame number only if they're not in slave mode */
|
||||||
|
if (connection->mode == NETPLAY_CONNECTION_PLAYING)
|
||||||
{
|
{
|
||||||
/* We already had this, so ignore the new transmission */
|
if (buffer[0] < netplay->read_frame_count[player])
|
||||||
break;
|
{
|
||||||
}
|
/* We already had this, so ignore the new transmission */
|
||||||
else if (buffer[0] > netplay->read_frame_count[player])
|
break;
|
||||||
{
|
}
|
||||||
/* Out of order = out of luck */
|
else if (buffer[0] > netplay->read_frame_count[player])
|
||||||
RARCH_ERR("Netplay input out of order.\n");
|
{
|
||||||
return netplay_cmd_nak(netplay, connection);
|
/* Out of order = out of luck */
|
||||||
|
RARCH_ERR("Netplay input out of order.\n");
|
||||||
|
return netplay_cmd_nak(netplay, connection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The data's good! */
|
/* The data's good! */
|
||||||
|
@ -500,15 +515,22 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
memcpy(dframe->real_input_state[player], buffer + 2,
|
memcpy(dframe->real_input_state[player], buffer + 2,
|
||||||
WORDS_PER_INPUT*sizeof(uint32_t));
|
WORDS_PER_INPUT*sizeof(uint32_t));
|
||||||
dframe->have_real[player] = true;
|
dframe->have_real[player] = true;
|
||||||
netplay->read_ptr[player] = NEXT_PTR(netplay->read_ptr[player]);
|
|
||||||
netplay->read_frame_count[player]++;
|
|
||||||
|
|
||||||
if (netplay->is_server)
|
/* 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)
|
||||||
{
|
{
|
||||||
/* Forward it on if it's past data*/
|
netplay->read_ptr[player] = NEXT_PTR(netplay->read_ptr[player]);
|
||||||
if (dframe->frame <= netplay->self_frame_count)
|
netplay->read_frame_count[player]++;
|
||||||
send_input_frame(netplay, NULL, connection, buffer[0],
|
|
||||||
player, dframe->real_input_state[player]);
|
if (netplay->is_server)
|
||||||
|
{
|
||||||
|
/* 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]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If this was server data, advance our server pointer too */
|
/* If this was server data, advance our server pointer too */
|
||||||
|
@ -605,7 +627,8 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
return netplay_cmd_nak(netplay, connection);
|
return netplay_cmd_nak(netplay, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connection->mode == NETPLAY_CONNECTION_PLAYING)
|
if (connection->mode == NETPLAY_CONNECTION_PLAYING ||
|
||||||
|
connection->mode == NETPLAY_CONNECTION_SLAVE)
|
||||||
{
|
{
|
||||||
/* The frame we haven't received is their end frame */
|
/* The frame we haven't received is their end frame */
|
||||||
payload[0] = htonl(netplay->read_frame_count[connection->player]);
|
payload[0] = htonl(netplay->read_frame_count[connection->player]);
|
||||||
|
@ -613,6 +636,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
/* Mark them as not playing anymore */
|
/* Mark them as not playing anymore */
|
||||||
connection->mode = NETPLAY_CONNECTION_SPECTATING;
|
connection->mode = NETPLAY_CONNECTION_SPECTATING;
|
||||||
netplay->connected_players &= ~(1<<connection->player);
|
netplay->connected_players &= ~(1<<connection->player);
|
||||||
|
netplay->connected_slaves &= ~(1<<connection->player);
|
||||||
|
|
||||||
/* Tell everyone */
|
/* Tell everyone */
|
||||||
payload[1] = htonl(connection->player);
|
payload[1] = htonl(connection->player);
|
||||||
|
@ -639,6 +663,27 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
{
|
{
|
||||||
uint32_t payload[2];
|
uint32_t payload[2];
|
||||||
uint32_t player = 0;
|
uint32_t player = 0;
|
||||||
|
bool slave = false;
|
||||||
|
|
||||||
|
/* Check if they requested slave mode */
|
||||||
|
if (cmd_size == sizeof(uint32_t))
|
||||||
|
{
|
||||||
|
RECV(payload, sizeof(uint32_t))
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
slave = true;
|
||||||
|
}
|
||||||
|
else if (cmd_size != 0)
|
||||||
|
{
|
||||||
|
RARCH_ERR("Invalid payload size for NETPLAY_CMD_PLAY.\n");
|
||||||
|
return netplay_cmd_nak(netplay, connection);
|
||||||
|
}
|
||||||
|
|
||||||
payload[0] = htonl(netplay->self_frame_count + 1);
|
payload[0] = htonl(netplay->self_frame_count + 1);
|
||||||
|
|
||||||
if (!netplay->is_server)
|
if (!netplay->is_server)
|
||||||
|
@ -671,15 +716,21 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connection->mode != NETPLAY_CONNECTION_PLAYING)
|
if (connection->mode != NETPLAY_CONNECTION_PLAYING &&
|
||||||
|
connection->mode != NETPLAY_CONNECTION_SLAVE)
|
||||||
{
|
{
|
||||||
/* Mark them as playing */
|
/* Mark them as playing */
|
||||||
connection->mode = NETPLAY_CONNECTION_PLAYING;
|
connection->mode = slave ? NETPLAY_CONNECTION_SLAVE :
|
||||||
|
NETPLAY_CONNECTION_PLAYING;
|
||||||
connection->player = player;
|
connection->player = player;
|
||||||
netplay->connected_players |= 1<<player;
|
netplay->connected_players |= 1<<player;
|
||||||
|
if (slave)
|
||||||
|
netplay->connected_slaves |= 1<<player;
|
||||||
|
|
||||||
/* Tell everyone */
|
/* Tell everyone */
|
||||||
payload[1] = htonl(NETPLAY_CMD_MODE_BIT_PLAYING | connection->player);
|
payload[1] = htonl(NETPLAY_CMD_MODE_BIT_PLAYING |
|
||||||
|
(slave?NETPLAY_CMD_MODE_BIT_SLAVE:0) |
|
||||||
|
connection->player);
|
||||||
netplay_send_raw_cmd_all(netplay, connection, NETPLAY_CMD_MODE, payload, sizeof(payload));
|
netplay_send_raw_cmd_all(netplay, connection, NETPLAY_CMD_MODE, payload, sizeof(payload));
|
||||||
|
|
||||||
/* Announce it */
|
/* Announce it */
|
||||||
|
@ -692,7 +743,10 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
|
|
||||||
/* Tell the player even if they were confused */
|
/* Tell the player even if they were confused */
|
||||||
payload[1] = htonl(NETPLAY_CMD_MODE_BIT_PLAYING |
|
payload[1] = htonl(NETPLAY_CMD_MODE_BIT_PLAYING |
|
||||||
NETPLAY_CMD_MODE_BIT_YOU | connection->player);
|
((connection->mode == NETPLAY_CONNECTION_SLAVE)?
|
||||||
|
NETPLAY_CMD_MODE_BIT_SLAVE:0) |
|
||||||
|
NETPLAY_CMD_MODE_BIT_YOU |
|
||||||
|
connection->player);
|
||||||
netplay_send_raw_cmd(netplay, connection, NETPLAY_CMD_MODE, payload, sizeof(payload));
|
netplay_send_raw_cmd(netplay, connection, NETPLAY_CMD_MODE, payload, sizeof(payload));
|
||||||
|
|
||||||
/* And expect their data */
|
/* And expect their data */
|
||||||
|
@ -764,7 +818,21 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
return netplay_cmd_nak(netplay, connection);
|
return netplay_cmd_nak(netplay, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
netplay->self_mode = NETPLAY_CONNECTION_PLAYING;
|
/* 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->self_player = player;
|
||||||
|
|
||||||
/* Fix up current frame info */
|
/* Fix up current frame info */
|
||||||
|
@ -836,6 +904,9 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
return netplay_cmd_nak(netplay, connection);
|
return netplay_cmd_nak(netplay, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Unmark ourself, in case we were in slave mode */
|
||||||
|
netplay->connected_players &= ~(1<<player);
|
||||||
|
|
||||||
/* Announce it */
|
/* Announce it */
|
||||||
strlcpy(msg, "You have left the game", sizeof(msg));
|
strlcpy(msg, "You have left the game", sizeof(msg));
|
||||||
RARCH_LOG("%s\n", msg);
|
RARCH_LOG("%s\n", msg);
|
||||||
|
@ -1049,7 +1120,8 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only players may load states */
|
/* Only players may load states */
|
||||||
if (connection->mode != NETPLAY_CONNECTION_PLAYING)
|
if (connection->mode != NETPLAY_CONNECTION_PLAYING &&
|
||||||
|
connection->mode != NETPLAY_CONNECTION_SLAVE)
|
||||||
{
|
{
|
||||||
RARCH_ERR("Netplay state load from a spectator.\n");
|
RARCH_ERR("Netplay state load from a spectator.\n");
|
||||||
return netplay_cmd_nak(netplay, connection);
|
return netplay_cmd_nak(netplay, connection);
|
||||||
|
@ -1212,7 +1284,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||||
}
|
}
|
||||||
nick[sizeof(nick)-1] = '\0';
|
nick[sizeof(nick)-1] = '\0';
|
||||||
|
|
||||||
/* We outright ignore pausing from spectators */
|
/* We outright ignore pausing from spectators and slaves */
|
||||||
if (connection->mode != NETPLAY_CONNECTION_PLAYING)
|
if (connection->mode != NETPLAY_CONNECTION_PLAYING)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1367,6 +1439,49 @@ int netplay_poll_net_input(netplay_t *netplay, bool block)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netplay_handle_slaves
|
||||||
|
*
|
||||||
|
* Handle any slave connections
|
||||||
|
*/
|
||||||
|
void netplay_handle_slaves(netplay_t *netplay)
|
||||||
|
{
|
||||||
|
struct delta_frame *frame = &netplay->buffer[netplay->self_ptr];
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < netplay->connections_size; i++)
|
||||||
|
{
|
||||||
|
struct netplay_connection *connection = &netplay->connections[i];
|
||||||
|
if (connection->active &&
|
||||||
|
connection->mode == NETPLAY_CONNECTION_SLAVE)
|
||||||
|
{
|
||||||
|
int player = connection->player;
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Alright, we have to send something. Do we need to generate it first? */
|
||||||
|
if (!frame->have_real[player])
|
||||||
|
{
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send it along */
|
||||||
|
send_input_frame(netplay, NULL, NULL, netplay->self_frame_count,
|
||||||
|
player, frame->real_input_state[player]);
|
||||||
|
|
||||||
|
/* 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_flip_port
|
* netplay_flip_port
|
||||||
*
|
*
|
||||||
|
|
|
@ -176,6 +176,8 @@ enum netplay_cmd
|
||||||
|
|
||||||
#define NETPLAY_CMD_INPUT_BIT_SERVER (1U<<31)
|
#define NETPLAY_CMD_INPUT_BIT_SERVER (1U<<31)
|
||||||
#define NETPLAY_CMD_SYNC_BIT_PAUSED (1U<<31)
|
#define NETPLAY_CMD_SYNC_BIT_PAUSED (1U<<31)
|
||||||
|
#define NETPLAY_CMD_PLAY_BIT_SLAVE (1U)
|
||||||
|
#define NETPLAY_CMD_MODE_BIT_SLAVE (1U<<18)
|
||||||
#define NETPLAY_CMD_MODE_BIT_PLAYING (1U<<17)
|
#define NETPLAY_CMD_MODE_BIT_PLAYING (1U<<17)
|
||||||
#define NETPLAY_CMD_MODE_BIT_YOU (1U<<16)
|
#define NETPLAY_CMD_MODE_BIT_YOU (1U<<16)
|
||||||
|
|
||||||
|
@ -206,6 +208,7 @@ enum rarch_netplay_connection_mode
|
||||||
/* Ready: */
|
/* Ready: */
|
||||||
NETPLAY_CONNECTION_CONNECTED, /* Modes above this are connected */
|
NETPLAY_CONNECTION_CONNECTED, /* Modes above this are connected */
|
||||||
NETPLAY_CONNECTION_SPECTATING, /* Spectator mode */
|
NETPLAY_CONNECTION_SPECTATING, /* Spectator mode */
|
||||||
|
NETPLAY_CONNECTION_SLAVE, /* Playing in slave mode */
|
||||||
NETPLAY_CONNECTION_PLAYING /* Normal ready state */
|
NETPLAY_CONNECTION_PLAYING /* Normal ready state */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -331,10 +334,13 @@ struct netplay
|
||||||
size_t connections_size;
|
size_t connections_size;
|
||||||
struct netplay_connection one_connection; /* Client only */
|
struct netplay_connection one_connection; /* Client only */
|
||||||
|
|
||||||
/* Bitmap of players with controllers (whether local or remote) (low bit is
|
/* Bitmap of players with controllers (low bit is player 1) */
|
||||||
* player 1) */
|
|
||||||
uint32_t connected_players;
|
uint32_t connected_players;
|
||||||
|
|
||||||
|
/* Bitmap of players playing in slave mode (should be a subset of
|
||||||
|
* connected_players) */
|
||||||
|
uint32_t connected_slaves;
|
||||||
|
|
||||||
/* Maximum player number */
|
/* Maximum player number */
|
||||||
uint32_t player_max;
|
uint32_t player_max;
|
||||||
|
|
||||||
|
@ -758,6 +764,13 @@ bool netplay_cmd_stall(netplay_t *netplay,
|
||||||
*/
|
*/
|
||||||
int netplay_poll_net_input(netplay_t *netplay, bool block);
|
int netplay_poll_net_input(netplay_t *netplay, bool block);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netplay_handle_slaves
|
||||||
|
*
|
||||||
|
* Handle any slave connections
|
||||||
|
*/
|
||||||
|
void netplay_handle_slaves(netplay_t *netplay);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* netplay_flip_port
|
* netplay_flip_port
|
||||||
*
|
*
|
||||||
|
|
|
@ -55,6 +55,7 @@ void netplay_update_unread_ptr(netplay_t *netplay)
|
||||||
for (player = 0; player < MAX_USERS; player++)
|
for (player = 0; player < MAX_USERS; player++)
|
||||||
{
|
{
|
||||||
if (!(netplay->connected_players & (1<<player))) continue;
|
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->read_frame_count[player] < new_unread_frame_count)
|
||||||
{
|
{
|
||||||
new_unread_ptr = netplay->read_ptr[player];
|
new_unread_ptr = netplay->read_ptr[player];
|
||||||
|
|
Loading…
Reference in New Issue