mirror of
https://github.com/libretro/RetroArch
synced 2025-03-29 22:20:21 +00:00
Added real pad sharing modes.
This commit is contained in:
parent
e4029b72c1
commit
fe80c4ce2c
@ -160,15 +160,15 @@ Payload:
|
||||
{
|
||||
frame number: uint32
|
||||
client number: 32 bits
|
||||
joypad input: uint32
|
||||
analog 1 input: uint32
|
||||
analog 2 input: uint32
|
||||
input data: variable
|
||||
}
|
||||
Description:
|
||||
Input state for each frame. Netplay must send an INPUT command for every
|
||||
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.
|
||||
frame may arrive after the server's input for the frame. The actual size of
|
||||
the input data is variable, but must match the expected size for each of
|
||||
the devices the given client controls.
|
||||
|
||||
Command: NOINPUT
|
||||
Payload:
|
||||
@ -217,6 +217,7 @@ Payload:
|
||||
paused?: 1 bit
|
||||
client number: 31 bits
|
||||
controller devices: uint32[16]
|
||||
share modes: uint8[16]
|
||||
controller-client mapping: uint32[16]
|
||||
client nick: char[32]
|
||||
sram: variable
|
||||
@ -239,7 +240,8 @@ Command: PLAY
|
||||
Payload:
|
||||
{
|
||||
as slave?: 1 bit
|
||||
reserved: 15 bits
|
||||
reserved: 7 bits
|
||||
preferred share mode: 8 bits
|
||||
requested device(s): 16 bits
|
||||
}
|
||||
Description:
|
||||
@ -247,18 +249,20 @@ Description:
|
||||
before sending input. Server may refuse or force slave connections, so the
|
||||
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.
|
||||
unassigned device, and share the first device if all devices are assigned
|
||||
and the first device is shareable.
|
||||
|
||||
Command: MODE
|
||||
Payload:
|
||||
{
|
||||
frame number: uint32
|
||||
reserved: 13 bits
|
||||
slave: 1 bit
|
||||
playing: 1 bit
|
||||
you: 1 bit
|
||||
playing: 1 bit
|
||||
slave: 1 bit
|
||||
reserved: 13 bits
|
||||
client number: uint16
|
||||
device bitmap: uint32
|
||||
share modes: uint8[16]
|
||||
}
|
||||
Description:
|
||||
Inform of a connection mode change (possibly of the receiving client). Only
|
||||
|
@ -496,9 +496,6 @@ static int16_t netplay_input_state(netplay_t *netplay,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (port > netplay->input_device_max)
|
||||
netplay->input_device_max = port;
|
||||
|
||||
/* FIXME: Mixing */
|
||||
delta = &netplay->buffer[ptr];
|
||||
istate = delta->resolved_input[port];
|
||||
@ -1161,12 +1158,32 @@ static void netplay_toggle_play_spectate(netplay_t *netplay)
|
||||
else if (netplay->self_mode == NETPLAY_CONNECTION_SPECTATING)
|
||||
{
|
||||
uint32_t device;
|
||||
uint8_t share_mode = NETPLAY_SHARE_DIGITAL_OR|NETPLAY_SHARE_ANALOG_MAX;
|
||||
|
||||
/* Take an input device */
|
||||
for (device = 0; device < MAX_INPUT_DEVICES; device++)
|
||||
if (!(netplay->device_clients[device]))
|
||||
{
|
||||
if (input_config_get_device(device) == RETRO_DEVICE_NONE)
|
||||
{
|
||||
device = MAX_INPUT_DEVICES;
|
||||
break;
|
||||
if (device == MAX_INPUT_DEVICES)
|
||||
}
|
||||
if (!netplay->device_clients[device])
|
||||
break;
|
||||
}
|
||||
if (device >= MAX_INPUT_DEVICES)
|
||||
{
|
||||
/* Share one */
|
||||
for (device = 0; device < MAX_INPUT_DEVICES; device++)
|
||||
{
|
||||
if (netplay->device_clients[device] && netplay->device_share_modes[device])
|
||||
{
|
||||
share_mode = netplay->device_share_modes[device];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (device >= MAX_INPUT_DEVICES)
|
||||
return; /* Failure! */
|
||||
|
||||
payload[1] = htonl(NETPLAY_CMD_MODE_BIT_PLAYING | device);
|
||||
@ -1175,6 +1192,7 @@ static void netplay_toggle_play_spectate(netplay_t *netplay)
|
||||
netplay->connected_players |= 1;
|
||||
netplay->client_devices[0] = netplay->self_devices = (1<<device);
|
||||
netplay->device_clients[device] = 1;
|
||||
netplay->device_share_modes[device] = share_mode;
|
||||
netplay->read_ptr1[0] = netplay->self_ptr;
|
||||
netplay->read_frame_count1[0] = netplay->self_frame_count;
|
||||
|
||||
@ -1320,13 +1338,7 @@ 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_players = 1;
|
||||
}
|
||||
netplay_toggle_play_spectate(netplay_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -547,6 +547,9 @@ bool netplay_handshake_sync(netplay_t *netplay,
|
||||
/* Controller devices */
|
||||
+ MAX_INPUT_DEVICES*sizeof(uint32_t)
|
||||
|
||||
/* Share modes */
|
||||
+ MAX_INPUT_DEVICES*sizeof(uint8_t)
|
||||
|
||||
/* Device-client mapping */
|
||||
+ MAX_INPUT_DEVICES*sizeof(uint32_t)
|
||||
|
||||
@ -574,6 +577,11 @@ bool netplay_handshake_sync(netplay_t *netplay,
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Then the share mode */
|
||||
if (!netplay_send(&connection->send_packet_buffer, connection->fd,
|
||||
netplay->device_share_modes, sizeof(netplay->device_share_modes)))
|
||||
return false;
|
||||
|
||||
/* Then the device-client mapping */
|
||||
for (i = 0; i < MAX_INPUT_DEVICES; i++)
|
||||
{
|
||||
@ -933,8 +941,8 @@ bool netplay_handshake_pre_sync(netplay_t *netplay,
|
||||
}
|
||||
|
||||
/* Only expecting a sync command */
|
||||
if (ntohl(cmd[0]) != NETPLAY_CMD_SYNC||
|
||||
ntohl(cmd[1]) < (2+2*MAX_INPUT_DEVICES)*sizeof(uint32_t) +
|
||||
if (ntohl(cmd[0]) != NETPLAY_CMD_SYNC ||
|
||||
ntohl(cmd[1]) < (2+2*MAX_INPUT_DEVICES)*sizeof(uint32_t) + (MAX_INPUT_DEVICES)*sizeof(uint8_t) +
|
||||
NETPLAY_NICK_LEN)
|
||||
{
|
||||
RARCH_ERR("%s\n",
|
||||
@ -1001,6 +1009,10 @@ bool netplay_handshake_pre_sync(netplay_t *netplay,
|
||||
core_set_controller_port_device(&pad);
|
||||
}
|
||||
|
||||
/* Get the share modes */
|
||||
RECV(netplay->device_share_modes, sizeof(netplay->device_share_modes))
|
||||
return false;
|
||||
|
||||
/* Get the client-controller mapping */
|
||||
netplay->connected_players =
|
||||
netplay->connected_slaves =
|
||||
@ -1012,7 +1024,6 @@ 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_players |= device;
|
||||
@ -1044,7 +1055,7 @@ bool netplay_handshake_pre_sync(netplay_t *netplay,
|
||||
|
||||
local_sram_size = (unsigned)mem_info.size;
|
||||
remote_sram_size = ntohl(cmd[1]) -
|
||||
(2+2*MAX_INPUT_DEVICES)*sizeof(uint32_t) - NETPLAY_NICK_LEN;
|
||||
(2+2*MAX_INPUT_DEVICES)*sizeof(uint32_t) - (MAX_INPUT_DEVICES)*sizeof(uint8_t) - NETPLAY_NICK_LEN;
|
||||
|
||||
if (local_sram_size != 0 && local_sram_size == remote_sram_size)
|
||||
{
|
||||
|
@ -426,7 +426,6 @@ 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->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;
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "../../retroarch.h"
|
||||
#include "../../tasks/tasks_internal.h"
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
#define DEBUG_NETPLAY_STEPS 1
|
||||
|
||||
static void print_state(netplay_t *netplay)
|
||||
@ -185,10 +185,11 @@ void netplay_delayed_state_change(netplay_t *netplay)
|
||||
connection->delay_frame <= netplay->self_frame_count)
|
||||
{
|
||||
/* Something was delayed! Prepare the MODE command */
|
||||
uint32_t payload[3];
|
||||
uint32_t payload[7];
|
||||
payload[0] = htonl(connection->delay_frame);
|
||||
payload[1] = htonl(client_num);
|
||||
payload[2] = htonl(0);
|
||||
memcpy(payload + 3, netplay->device_share_modes, sizeof(netplay->device_share_modes));
|
||||
|
||||
/* Remove the connection entirely if relevant */
|
||||
if (connection->mode == NETPLAY_CONNECTION_DELAYED_DISCONNECT)
|
||||
@ -468,7 +469,7 @@ bool netplay_cmd_mode(netplay_t *netplay,
|
||||
enum rarch_netplay_connection_mode mode)
|
||||
{
|
||||
uint32_t cmd;
|
||||
uint32_t payloadBuf, *payload = NULL;
|
||||
uint32_t payloadBuf = 0, *payload = NULL;
|
||||
switch (mode)
|
||||
{
|
||||
case NETPLAY_CONNECTION_SPECTATING:
|
||||
@ -476,11 +477,13 @@ bool netplay_cmd_mode(netplay_t *netplay,
|
||||
break;
|
||||
|
||||
case NETPLAY_CONNECTION_SLAVE:
|
||||
payload = &payloadBuf;
|
||||
payloadBuf = htonl(NETPLAY_CMD_PLAY_BIT_SLAVE);
|
||||
payloadBuf = NETPLAY_CMD_PLAY_BIT_SLAVE;
|
||||
/* no break */
|
||||
|
||||
case NETPLAY_CONNECTION_PLAYING:
|
||||
payload = &payloadBuf;
|
||||
payloadBuf |= NETPLAY_SHARE_NO_PREFERENCE<<16;
|
||||
payloadBuf = htonl(payloadBuf);
|
||||
cmd = NETPLAY_CMD_PLAY;
|
||||
break;
|
||||
|
||||
@ -534,6 +537,10 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
|
||||
cmd_size = ntohl(cmd_size);
|
||||
|
||||
#ifdef DEBUG_NETPLAY_STEPS
|
||||
RARCH_LOG("Received netplay command %X (%X)\n", cmd, cmd_size);
|
||||
#endif
|
||||
|
||||
netplay->timeout_cnt = 0;
|
||||
|
||||
switch (cmd)
|
||||
@ -760,7 +767,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
|
||||
case NETPLAY_CMD_SPECTATE:
|
||||
{
|
||||
uint32_t payload[3];
|
||||
uint32_t payload[7];
|
||||
uint32_t client_num;
|
||||
size_t i;
|
||||
|
||||
@ -772,64 +779,65 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
|
||||
client_num = connection - netplay->connections + 1;
|
||||
|
||||
if (connection->mode == NETPLAY_CONNECTION_PLAYING ||
|
||||
connection->mode == NETPLAY_CONNECTION_SLAVE)
|
||||
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_count1[client_num];
|
||||
|
||||
/* Mark them as not playing anymore */
|
||||
connection->mode = NETPLAY_CONNECTION_SPECTATING;
|
||||
netplay->connected_players &= ~(1<<client_num);
|
||||
netplay->connected_slaves &= ~(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", client_num+1);
|
||||
RARCH_LOG("%s\n", msg);
|
||||
runloop_msg_queue_push(msg, 1, 180, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
payload[0] = htonl(0);
|
||||
/* They were confused */
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
}
|
||||
|
||||
/* Tell the player even if they were confused */
|
||||
/* The frame we haven't received is their end frame */
|
||||
connection->delay_frame = netplay->read_frame_count1[client_num];
|
||||
|
||||
/* Mark them as not playing anymore */
|
||||
connection->mode = NETPLAY_CONNECTION_SPECTATING;
|
||||
netplay->connected_players &= ~(1 << client_num);
|
||||
netplay->connected_slaves &= ~(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);
|
||||
|
||||
/* Tell the player */
|
||||
payload[0] = htonl(connection->delay_frame);
|
||||
payload[1] = htonl(NETPLAY_CMD_MODE_BIT_YOU | client_num);
|
||||
payload[2] = htonl(0);
|
||||
memcpy(payload + 3, netplay->device_share_modes, sizeof(netplay->device_share_modes));
|
||||
netplay_send_raw_cmd(netplay, connection, NETPLAY_CMD_MODE, payload, sizeof(payload));
|
||||
|
||||
/* Announce it */
|
||||
msg[sizeof(msg) - 1] = '\0';
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
case NETPLAY_CMD_PLAY:
|
||||
{
|
||||
uint32_t devices = 0, device, client_num;
|
||||
uint32_t payload[3];
|
||||
uint32_t mode, devices = 0, device, client_num;
|
||||
uint8_t share_mode;
|
||||
uint32_t payload[7];
|
||||
bool slave = false;
|
||||
settings_t *settings = config_get_ptr();
|
||||
|
||||
/* Check if they requested slave mode */
|
||||
if (cmd_size == sizeof(uint32_t))
|
||||
if (cmd_size != sizeof(uint32_t))
|
||||
{
|
||||
RECV(&devices, sizeof(devices))
|
||||
{
|
||||
RARCH_ERR("Failed to receive NETPLAY_CMD_PLAY payload.\n");
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
}
|
||||
|
||||
devices = ntohl(devices);
|
||||
if (devices & NETPLAY_CMD_PLAY_BIT_SLAVE)
|
||||
slave = true;
|
||||
devices &= ~(NETPLAY_CMD_PLAY_BIT_SLAVE);
|
||||
}
|
||||
else if (cmd_size != 0)
|
||||
{
|
||||
RARCH_ERR("Invalid payload size for NETPLAY_CMD_PLAY.\n");
|
||||
RARCH_ERR("Incorrect NETPLAY_CMD_PLAY payload size.\n");
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
}
|
||||
RECV(&mode, sizeof(uint32_t))
|
||||
{
|
||||
RARCH_ERR("Failed to receive NETPLAY_CMD_PLAY payload.\n");
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
}
|
||||
mode = ntohl(mode);
|
||||
|
||||
/* Check the requested mode */
|
||||
slave = (mode&NETPLAY_CMD_PLAY_BIT_SLAVE)?true:false;
|
||||
share_mode = (mode>>16)&0xFF;
|
||||
|
||||
/* And the requested devices */
|
||||
devices = mode&0xFFFF;
|
||||
|
||||
/* Check if their slave mode request corresponds with what we allow */
|
||||
if (settings->bools.netplay_require_slaves)
|
||||
@ -837,6 +845,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
else if (!settings->bools.netplay_allow_slaves)
|
||||
slave = false;
|
||||
|
||||
/* Start forming our response */
|
||||
payload[0] = htonl(netplay->self_frame_count + 1);
|
||||
|
||||
if (!netplay->is_server)
|
||||
@ -862,13 +871,38 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
break;
|
||||
}
|
||||
|
||||
/* Find an available device (FIXME: Honor device request) */
|
||||
for (device = 0; device <= netplay->input_device_max; device++)
|
||||
if (connection->mode == NETPLAY_CONNECTION_PLAYING
|
||||
|| connection->mode == NETPLAY_CONNECTION_SLAVE)
|
||||
{
|
||||
/* They were obviously confused */
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
}
|
||||
|
||||
/* Find an available device (FIXME: Honor device request) */
|
||||
(void) devices;
|
||||
for (device = 0; device < MAX_INPUT_DEVICES; device++)
|
||||
{
|
||||
if (input_config_get_device(device) == RETRO_DEVICE_NONE)
|
||||
{
|
||||
device = MAX_INPUT_DEVICES;
|
||||
break;
|
||||
}
|
||||
if (!netplay->device_clients[device])
|
||||
break;
|
||||
}
|
||||
if (device > netplay->input_device_max)
|
||||
if (device >= MAX_INPUT_DEVICES && share_mode)
|
||||
{
|
||||
/* No device was totally free, maybe one is shareable? */
|
||||
for (device = 0; device < MAX_INPUT_DEVICES; device++)
|
||||
{
|
||||
if (netplay->device_clients[device] && netplay->device_share_modes[device])
|
||||
{
|
||||
share_mode = netplay->device_share_modes[device];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (device >= MAX_INPUT_DEVICES)
|
||||
{
|
||||
/* No slots free! */
|
||||
payload[0] = htonl(NETPLAY_CMD_MODE_REFUSED_REASON_NO_SLOTS);
|
||||
@ -877,40 +911,48 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
}
|
||||
payload[2] = htonl(1<<device);
|
||||
|
||||
if (connection->mode != NETPLAY_CONNECTION_PLAYING &&
|
||||
connection->mode != NETPLAY_CONNECTION_SLAVE)
|
||||
/* Fix our share mode */
|
||||
if (share_mode)
|
||||
{
|
||||
/* Mark them as playing */
|
||||
connection->mode = slave ? NETPLAY_CONNECTION_SLAVE :
|
||||
NETPLAY_CONNECTION_PLAYING;
|
||||
|
||||
netplay->connected_players |= 1<<client_num;
|
||||
if (slave)
|
||||
netplay->connected_slaves |= 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) |
|
||||
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", client_num+1);
|
||||
RARCH_LOG("%s\n", msg);
|
||||
runloop_msg_queue_push(msg, 1, 180, false);
|
||||
|
||||
if ((share_mode & NETPLAY_SHARE_DIGITAL_BITS) == 0)
|
||||
share_mode |= NETPLAY_SHARE_DIGITAL_OR;
|
||||
if ((share_mode & NETPLAY_SHARE_ANALOG_BITS) == 0)
|
||||
share_mode |= NETPLAY_SHARE_ANALOG_MAX;
|
||||
share_mode &= ~NETPLAY_SHARE_NO_PREFERENCE;
|
||||
}
|
||||
|
||||
/* Tell the player even if they were confused */
|
||||
|
||||
/* Mark them as playing */
|
||||
connection->mode =
|
||||
slave ? NETPLAY_CONNECTION_SLAVE : NETPLAY_CONNECTION_PLAYING;
|
||||
|
||||
netplay->connected_players |= 1 << client_num;
|
||||
if (slave)
|
||||
netplay->connected_slaves |= 1 << client_num;
|
||||
netplay->client_devices[client_num] |= 1 << device;
|
||||
netplay->device_clients[device] |= 1 << client_num;
|
||||
netplay->device_share_modes[device] = share_mode;
|
||||
|
||||
/* Tell everyone */
|
||||
payload[1] = htonl(
|
||||
NETPLAY_CMD_MODE_BIT_PLAYING
|
||||
| (slave ? NETPLAY_CMD_MODE_BIT_SLAVE : 0) | client_num);
|
||||
memcpy(payload + 3, netplay->device_share_modes, sizeof(netplay->device_share_modes));
|
||||
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", client_num + 1);
|
||||
RARCH_LOG("%s\n", msg);
|
||||
runloop_msg_queue_push(msg, 1, 180, false);
|
||||
|
||||
/* Tell the player */
|
||||
payload[1] = htonl(NETPLAY_CMD_MODE_BIT_PLAYING |
|
||||
((connection->mode == NETPLAY_CONNECTION_SLAVE)?
|
||||
NETPLAY_CMD_MODE_BIT_SLAVE:0) |
|
||||
NETPLAY_CMD_MODE_BIT_YOU |
|
||||
client_num);
|
||||
payload[2] = htonl(1<<device);
|
||||
netplay_send_raw_cmd(netplay, connection, NETPLAY_CMD_MODE, payload, sizeof(payload));
|
||||
|
||||
/* And expect their data */
|
||||
@ -921,7 +963,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
|
||||
case NETPLAY_CMD_MODE:
|
||||
{
|
||||
uint32_t payload[3];
|
||||
uint32_t payload[7];
|
||||
uint32_t frame, mode, client_num, devices, device;
|
||||
size_t ptr;
|
||||
struct delta_frame *dframe;
|
||||
@ -937,8 +979,13 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
dframe = &netplay->buffer[ptr]; \
|
||||
} while(0)
|
||||
|
||||
if (cmd_size != sizeof(payload) ||
|
||||
netplay->is_server)
|
||||
if (netplay->is_server)
|
||||
{
|
||||
RARCH_ERR("NETPLAY_CMD_MODE from client.\n");
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
}
|
||||
|
||||
if (cmd_size != sizeof(payload))
|
||||
{
|
||||
RARCH_ERR("Invalid payload size for NETPLAY_CMD_MODE.\n");
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
@ -965,6 +1012,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
}
|
||||
|
||||
devices = ntohl(payload[2]);
|
||||
memcpy(netplay->device_share_modes, payload + 3, sizeof(netplay->device_share_modes));
|
||||
|
||||
if (mode & NETPLAY_CMD_MODE_BIT_YOU)
|
||||
{
|
||||
|
@ -184,9 +184,9 @@ enum netplay_cmd
|
||||
|
||||
#define NETPLAY_CMD_SYNC_BIT_PAUSED (1U<<31)
|
||||
#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)
|
||||
#define NETPLAY_CMD_MODE_BIT_YOU (1U<<31)
|
||||
#define NETPLAY_CMD_MODE_BIT_PLAYING (1U<<30)
|
||||
#define NETPLAY_CMD_MODE_BIT_SLAVE (1U<<29)
|
||||
|
||||
/* These are the reasons given for mode changes to be rejected */
|
||||
enum netplay_cmd_mode_reasons
|
||||
@ -201,9 +201,35 @@ enum netplay_cmd_mode_reasons
|
||||
NETPLAY_CMD_MODE_REFUSED_REASON_NO_SLOTS,
|
||||
|
||||
/* You're changing modes too fast */
|
||||
NETPLAY_CMD_MODE_REFUSED_REASON_TOO_FAST
|
||||
NETPLAY_CMD_MODE_REFUSED_REASON_TOO_FAST,
|
||||
|
||||
/* You requested a particular port but it's not available */
|
||||
NETPLAY_CMD_MODE_REFUSED_REASON_NOT_AVAILABLE
|
||||
};
|
||||
|
||||
/* Preferences for sharing devices */
|
||||
enum rarch_netplay_share_preference
|
||||
{
|
||||
/* Prefer not to share, shouldn't be set as a sharing mode for an shared device */
|
||||
NETPLAY_SHARE_NO_SHARING = 0x0,
|
||||
|
||||
/* No preference. Only for requests. Set if sharing is requested but either
|
||||
* digital or analog doesn't have a preference. */
|
||||
NETPLAY_SHARE_NO_PREFERENCE = 0x1,
|
||||
|
||||
/* For digital devices */
|
||||
NETPLAY_SHARE_DIGITAL_BITS = 0x1C,
|
||||
NETPLAY_SHARE_DIGITAL_OR = 0x4,
|
||||
NETPLAY_SHARE_DIGITAL_XOR = 0x8,
|
||||
NETPLAY_SHARE_DIGITAL_VOTE = 0xC,
|
||||
|
||||
/* For analog devices */
|
||||
NETPLAY_SHARE_ANALOG_BITS = 0xE0,
|
||||
NETPLAY_SHARE_ANALOG_MAX = 0x20,
|
||||
NETPLAY_SHARE_ANALOG_AVERAGE = 0x40
|
||||
};
|
||||
|
||||
/* The current status of a connection */
|
||||
enum rarch_netplay_connection_mode
|
||||
{
|
||||
NETPLAY_CONNECTION_NONE = 0,
|
||||
@ -399,6 +425,9 @@ struct netplay
|
||||
/* For each device, the bitmap of clients connected */
|
||||
client_bitmap_t device_clients[MAX_INPUT_DEVICES];
|
||||
|
||||
/* The sharing mode for each device */
|
||||
uint8_t device_share_modes[MAX_INPUT_DEVICES];
|
||||
|
||||
/* Our own device bitmap */
|
||||
uint32_t self_devices;
|
||||
|
||||
@ -406,9 +435,6 @@ struct netplay
|
||||
* attempt to stay in sync. */
|
||||
uint32_t desync;
|
||||
|
||||
/* Maximum input device number */
|
||||
uint32_t input_device_max;
|
||||
|
||||
struct retro_callbacks cbs;
|
||||
|
||||
/* TCP port (only set if serving) */
|
||||
|
@ -82,6 +82,188 @@ void netplay_update_unread_ptr(netplay_t *netplay)
|
||||
}
|
||||
}
|
||||
|
||||
struct vote_count {
|
||||
uint16_t votes[32];
|
||||
};
|
||||
|
||||
/**
|
||||
* netplay_device_client_state
|
||||
* @resstate : state being resolved
|
||||
* @simframe : frame in which merging is being performed
|
||||
* @device : device being merged
|
||||
* @client : client to find state for
|
||||
*/
|
||||
netplay_input_state_t netplay_device_client_state(
|
||||
netplay_input_state_t resstate, struct delta_frame *simframe,
|
||||
uint32_t device, uint32_t client)
|
||||
{
|
||||
netplay_input_state_t simstate =
|
||||
netplay_input_state_for(
|
||||
&simframe->real_input[device], client, 3 /* FIXME */, false, true);
|
||||
if (!simstate)
|
||||
{
|
||||
resstate->used = false;
|
||||
simstate = netplay_input_state_for(&simframe->simlated_input[device],
|
||||
client, 3 /* FIXME */, false, true);
|
||||
}
|
||||
return simstate;
|
||||
}
|
||||
|
||||
/**
|
||||
* netplay_merge_digital
|
||||
* @netplay : pointer to netplay object
|
||||
* @resstate : state being resolved
|
||||
* @simframe : frame in which merging is being performed
|
||||
* @device : device being merged
|
||||
* @clients : bitmap of clients being merged
|
||||
* @digital : bitmap of digital bits
|
||||
*/
|
||||
static void netplay_merge_digital(netplay_t *netplay,
|
||||
netplay_input_state_t resstate, struct delta_frame *simframe,
|
||||
uint32_t device, uint32_t clients, const uint32_t *digital)
|
||||
{
|
||||
netplay_input_state_t simstate;
|
||||
uint32_t word, bit, client;
|
||||
uint8_t share_mode = netplay->device_share_modes[device] & NETPLAY_SHARE_DIGITAL_BITS;
|
||||
if (share_mode == NETPLAY_SHARE_DIGITAL_VOTE)
|
||||
{
|
||||
/* Vote mode requires counting all the bits */
|
||||
uint32_t client_count = 0;
|
||||
struct vote_count votes[3] = {0};
|
||||
for (client = 0; client < MAX_CLIENTS; client++)
|
||||
{
|
||||
if (!(clients & (1<<client))) continue;
|
||||
client_count++;
|
||||
simstate = netplay_device_client_state(resstate, simframe, device, client);
|
||||
if (!simstate) continue;
|
||||
|
||||
for (word = 0; word < 3 /* FIXME */; word++)
|
||||
{
|
||||
if (!digital[word]) continue;
|
||||
for (bit = 0; bit < 32; bit++)
|
||||
{
|
||||
if (!(digital[word] & (1<<bit))) continue;
|
||||
if (simstate->data[word] & (1<<bit))
|
||||
votes[word].votes[bit]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now count all the bits */
|
||||
client_count /= 2;
|
||||
for (word = 0; word < 3 /* FIXME */; word++)
|
||||
{
|
||||
for (bit = 0; bit < 32; bit++)
|
||||
{
|
||||
if (votes[word].votes[bit] > client_count)
|
||||
resstate->data[word] |= (1<<bit);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else /* !VOTE */
|
||||
{
|
||||
for (client = 0; client < MAX_CLIENTS; client++)
|
||||
{
|
||||
if (!(clients & (1<<client))) continue;
|
||||
simstate = netplay_device_client_state(resstate, simframe, device, client);
|
||||
if (!simstate) continue;
|
||||
for (word = 0; word < 3 /* FIXME */; word++)
|
||||
{
|
||||
uint32_t part;
|
||||
if (!digital[word]) continue;
|
||||
part = simstate->data[word];
|
||||
if (digital[word] == (uint32_t) -1)
|
||||
{
|
||||
/* Combine the whole word */
|
||||
switch (share_mode)
|
||||
{
|
||||
case NETPLAY_SHARE_DIGITAL_XOR: resstate->data[word] ^= part; break;
|
||||
default: resstate->data[word] |= part;
|
||||
}
|
||||
|
||||
}
|
||||
else /* !whole word */
|
||||
{
|
||||
for (bit = 0; bit < 32; bit++)
|
||||
{
|
||||
if (!(digital[word] & (1<<bit))) continue;
|
||||
switch (share_mode)
|
||||
{
|
||||
case NETPLAY_SHARE_DIGITAL_XOR: resstate->data[word] ^= part & (1<<bit); break;
|
||||
default: resstate->data[word] |= part & (1<<bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* merge_analog_part
|
||||
* @netplay : pointer to netplay object
|
||||
* @resstate : state being resolved
|
||||
* @simframe : frame in which merging is being performed
|
||||
* @device : device being merged
|
||||
* @clients : bitmap of clients being merged
|
||||
* @word : word to merge
|
||||
* @bit : first bit to merge
|
||||
*/
|
||||
static void merge_analog_part(netplay_t *netplay,
|
||||
netplay_input_state_t resstate, struct delta_frame *simframe,
|
||||
uint32_t device, uint32_t clients, uint32_t word, uint8_t bit)
|
||||
{
|
||||
netplay_input_state_t simstate;
|
||||
uint32_t client, client_count = 0;;
|
||||
uint8_t share_mode = netplay->device_share_modes[device] & NETPLAY_SHARE_ANALOG_BITS;
|
||||
int32_t value = 0, new_value;
|
||||
|
||||
for (client = 0; client < MAX_CLIENTS; client++)
|
||||
{
|
||||
if (!(clients & (1<<client))) continue;
|
||||
client_count++;
|
||||
simstate = netplay_device_client_state(resstate, simframe, device, client);
|
||||
if (!simstate) continue;
|
||||
new_value = (int16_t) ((simstate->data[word]>>bit) & 0xFFFF);
|
||||
switch (share_mode)
|
||||
{
|
||||
case NETPLAY_SHARE_ANALOG_AVERAGE:
|
||||
value += (int32_t) new_value;
|
||||
break;
|
||||
default:
|
||||
if (abs(new_value) > abs(value) ||
|
||||
(abs(new_value) == abs(value) && new_value > value))
|
||||
value = new_value;
|
||||
}
|
||||
}
|
||||
|
||||
if (share_mode == NETPLAY_SHARE_ANALOG_AVERAGE)
|
||||
value /= client_count;
|
||||
|
||||
resstate->data[word] |= ((uint32_t) (uint16_t) value) << bit;
|
||||
}
|
||||
|
||||
/**
|
||||
* netplay_merge_analog
|
||||
* @netplay : pointer to netplay object
|
||||
* @resstate : state being resolved
|
||||
* @simframe : frame in which merging is being performed
|
||||
* @device : device being merged
|
||||
* @clients : bitmap of clients being merged
|
||||
*/
|
||||
static void netplay_merge_analog(netplay_t *netplay,
|
||||
netplay_input_state_t resstate, struct delta_frame *simframe,
|
||||
uint32_t device, uint32_t clients)
|
||||
{
|
||||
/* FIXME: Assumes 3-byte gamepad */
|
||||
merge_analog_part(netplay, resstate, simframe, device, clients, 1, 0);
|
||||
merge_analog_part(netplay, resstate, simframe, device, clients, 1, 16);
|
||||
merge_analog_part(netplay, resstate, simframe, device, clients, 2, 0);
|
||||
merge_analog_part(netplay, resstate, simframe, device, clients, 2, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* netplay_resolve_input
|
||||
* @netplay : pointer to netplay object
|
||||
@ -95,26 +277,27 @@ void netplay_update_unread_ptr(netplay_t *netplay)
|
||||
*/
|
||||
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, resstate, pstate;
|
||||
uint32_t devices, device;
|
||||
netplay_input_state_t simstate, resstate, oldresstate, pstate;
|
||||
uint32_t clients, client, client_count;
|
||||
uint32_t device;
|
||||
bool ret = false, simulated;
|
||||
|
||||
simframe = &netplay->buffer[sim_ptr];
|
||||
|
||||
for (client = 0; client < MAX_CLIENTS; client++)
|
||||
for (device = 0; device < MAX_INPUT_DEVICES; device++)
|
||||
{
|
||||
if (!(netplay->connected_players & (1<<client))) continue;
|
||||
clients = netplay->device_clients[device];
|
||||
if (!clients) continue;
|
||||
client_count = 0;
|
||||
|
||||
devices = netplay->client_devices[client];
|
||||
|
||||
for (device = 0; device < MAX_INPUT_DEVICES; device++)
|
||||
for (client = 0; client < MAX_CLIENTS; client++)
|
||||
{
|
||||
if (!(devices & (1<<device)))
|
||||
continue;
|
||||
if (!(clients & (1<<client))) continue;
|
||||
client_count++;
|
||||
|
||||
/* Resolve this client-device */
|
||||
simulated = false;
|
||||
simstate = netplay_input_state_for(&simframe->real_input[device], client, 3 /* FIXME */, false, true);
|
||||
if (!simstate)
|
||||
@ -162,15 +345,36 @@ bool netplay_resolve_input(netplay_t *netplay, size_t sim_ptr, bool resim)
|
||||
simstate->size * sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we copy the state, whether real or simulated, out into the resolved state (FIXME: Merging) */
|
||||
resstate = netplay_input_state_for(&simframe->resolved_input[device], 0, 3 /* FIXME */, false, false);
|
||||
if (!resstate)
|
||||
continue;
|
||||
/* Now we copy the state, whether real or simulated, out into the resolved state */
|
||||
resstate = netplay_input_state_for(&simframe->resolved_input[device], 0, 3 /* FIXME */, false, false);
|
||||
if (!resstate)
|
||||
continue;
|
||||
|
||||
if (client_count == 1)
|
||||
{
|
||||
/* Trivial in the common 1-client case */
|
||||
resstate->used = !simulated; /* We reuse "used" to mean "real" */
|
||||
if (memcmp(resstate->data, simstate->data, resstate->size * sizeof(uint32_t)))
|
||||
ret = true;
|
||||
memcpy(resstate->data, simstate->data, resstate->size * sizeof(uint32_t));
|
||||
|
||||
} else {
|
||||
/* Merge them */
|
||||
static const uint32_t digital[3] = {-1, 0, 0};
|
||||
oldresstate = netplay_input_state_for(&simframe->resolved_input[device], 1, 3 /* FIXME */, false, false);
|
||||
if (!oldresstate)
|
||||
continue;
|
||||
memcpy(oldresstate->data, resstate->data, oldresstate->size * sizeof(uint32_t));
|
||||
memset(resstate->data, 0, resstate->size * sizeof(uint32_t));
|
||||
|
||||
netplay_merge_digital(netplay, resstate, simframe, device, clients, digital);
|
||||
netplay_merge_analog(netplay, resstate, simframe, device, clients);
|
||||
|
||||
if (memcmp(resstate->data, oldresstate->data, resstate->size * sizeof(uint32_t)))
|
||||
ret = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user