mirror of
https://github.com/libretro/RetroArch
synced 2025-03-29 22:20:21 +00:00
Netplay input device abstraction, support for mice
This abstracts away the details of particular input devices for netplay, and adds support for mice and (similar) lightguns. Unfortunately, in practice, no core handles mice or lightguns in a savestate-safe way, so they need to be used in stateless mode to be reliable, but they do work.
This commit is contained in:
parent
ab669a2db8
commit
c01a199493
@ -357,3 +357,40 @@ Unused
|
||||
|
||||
Command: CFG_ACK
|
||||
Unused
|
||||
|
||||
|
||||
Input types
|
||||
|
||||
Each input device uses a number of words fixed by the type of device. When
|
||||
buttons are listed, they are listed from lowest bit to highest bit, i.e.,
|
||||
reverse order. When insufficient buttons are present to represent to represent
|
||||
a full 32-bit word, the remainder are reserved and unused.
|
||||
|
||||
JOYPAD
|
||||
{
|
||||
B, Y, Select, Start, Up, Down, Left, Right, A, X, L, R, L2, R2, L3, R3
|
||||
}
|
||||
|
||||
MOUSE
|
||||
{
|
||||
unused, unused, Left, Right, Wheel up, Wheel down, Middle, Horizontal
|
||||
wheel up, Horizontal wheel down
|
||||
Y: int16
|
||||
X: int16
|
||||
}
|
||||
|
||||
LIGHTGUN
|
||||
{
|
||||
unused, unused, Trigger, Cursor, Turbo, Pause, Start
|
||||
Y: int16
|
||||
X: int16
|
||||
}
|
||||
|
||||
ANALOG
|
||||
{
|
||||
buttons: uint32, as JOYPAD
|
||||
Left analog Y: int16
|
||||
Left analog X: int16
|
||||
Right analog Y: int16
|
||||
Right analog X: int16
|
||||
}
|
||||
|
@ -167,14 +167,22 @@ netplay_input_state_t netplay_input_state_for(netplay_input_state_t *list,
|
||||
*
|
||||
* Size in words for a given set of devices.
|
||||
*/
|
||||
uint32_t netplay_expected_input_size(uint32_t devices)
|
||||
uint32_t netplay_expected_input_size(netplay_t *netplay, uint32_t devices)
|
||||
{
|
||||
/* FIXME: For now, we assume all devices are three words, because in the implementation, they are. */
|
||||
uint32_t ret = 0;
|
||||
while (devices)
|
||||
uint32_t ret = 0, device;
|
||||
for (device = 0; device < MAX_INPUT_DEVICES; device++)
|
||||
{
|
||||
if (devices & 1) ret += 3;
|
||||
devices >>= 1;
|
||||
if (!(devices & (1<<device))) continue;
|
||||
switch (netplay->config_devices[device]&RETRO_DEVICE_MASK)
|
||||
{
|
||||
/* These are all essentially magic numbers, but each device has a
|
||||
* fixed size, documented in network/netplay/README */
|
||||
case RETRO_DEVICE_JOYPAD: ret += 1; break;
|
||||
case RETRO_DEVICE_MOUSE: ret += 2; break;
|
||||
case RETRO_DEVICE_LIGHTGUN: ret += 2; break;
|
||||
case RETRO_DEVICE_ANALOG: ret += 3; break;
|
||||
default: break; /* Unsupported */
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -137,41 +137,70 @@ static bool get_self_input_state(netplay_t *netplay)
|
||||
continue;
|
||||
|
||||
/* Find an appropriate local device */
|
||||
dev_type = input_config_get_device(devi)&RETRO_DEVICE_MASK;
|
||||
dev_type = netplay->config_devices[devi]&RETRO_DEVICE_MASK;
|
||||
for (local_device = 0; local_device < MAX_INPUT_DEVICES; local_device++)
|
||||
{
|
||||
if (used_devices & (1<<local_device)) continue;
|
||||
if ((input_config_get_device(local_device)&RETRO_DEVICE_MASK) == dev_type) break;
|
||||
if ((netplay->config_devices[local_device]&RETRO_DEVICE_MASK) == dev_type) break;
|
||||
}
|
||||
if (local_device == MAX_INPUT_DEVICES)
|
||||
local_device = 0;
|
||||
used_devices |= (1<<local_device);
|
||||
|
||||
istate = netplay_input_state_for(&ptr->real_input[devi],
|
||||
netplay->self_client_num, 3 /* FIXME */, true, false);
|
||||
netplay->self_client_num, netplay_expected_input_size(netplay, 1 << devi),
|
||||
true, false);
|
||||
if (!istate)
|
||||
continue; /* FIXME: More severe? */
|
||||
|
||||
/* First frame we always give zero input since relying on
|
||||
* input from first frame screws up when we use -F 0. */
|
||||
if (!input_driver_is_libretro_input_blocked() && netplay->self_frame_count > 0)
|
||||
{
|
||||
/* 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(local_device,
|
||||
RETRO_DEVICE_JOYPAD, 0, (unsigned)i);
|
||||
state[0] |= tmp ? 1 << i : 0;
|
||||
}
|
||||
unsigned dtype = netplay->config_devices[devi]&RETRO_DEVICE_MASK;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
switch (dtype)
|
||||
{
|
||||
int16_t tmp_x = cb(local_device,
|
||||
RETRO_DEVICE_ANALOG, (unsigned)i, 0);
|
||||
int16_t tmp_y = cb(local_device,
|
||||
RETRO_DEVICE_ANALOG, (unsigned)i, 1);
|
||||
state[1 + i] = (uint16_t)tmp_x | (((uint16_t)tmp_y) << 16);
|
||||
case RETRO_DEVICE_ANALOG:
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
int16_t tmp_x = cb(local_device,
|
||||
RETRO_DEVICE_ANALOG, (unsigned)i, 0);
|
||||
int16_t tmp_y = cb(local_device,
|
||||
RETRO_DEVICE_ANALOG, (unsigned)i, 1);
|
||||
state[1 + i] = (uint16_t)tmp_x | (((uint16_t)tmp_y) << 16);
|
||||
}
|
||||
/* no break */
|
||||
|
||||
case RETRO_DEVICE_JOYPAD:
|
||||
for (i = 0; i <= RETRO_DEVICE_ID_JOYPAD_R3; i++)
|
||||
{
|
||||
int16_t tmp = cb(local_device,
|
||||
RETRO_DEVICE_JOYPAD, 0, (unsigned)i);
|
||||
state[0] |= tmp ? 1 << i : 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case RETRO_DEVICE_MOUSE:
|
||||
case RETRO_DEVICE_LIGHTGUN:
|
||||
{
|
||||
int16_t tmp_x = cb(local_device, dtype, 0, 0);
|
||||
int16_t tmp_y = cb(local_device, dtype, 0, 1);
|
||||
state[1] = (uint16_t)tmp_x | (((uint16_t)tmp_y) << 16);
|
||||
for (i = 2;
|
||||
i <= ((dtype == RETRO_DEVICE_MOUSE) ?
|
||||
RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN :
|
||||
RETRO_DEVICE_ID_LIGHTGUN_START);
|
||||
i++)
|
||||
{
|
||||
int16_t tmp = cb(local_device, dtype, 0,
|
||||
(unsigned) i);
|
||||
state[0] |= tmp ? 1 << i : 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -504,8 +533,20 @@ static int16_t netplay_input_state(netplay_t *netplay,
|
||||
const uint32_t *curr_input_state = NULL;
|
||||
|
||||
if (port >= MAX_INPUT_DEVICES)
|
||||
{
|
||||
return 0;
|
||||
|
||||
/* If the port doesn't seem to correspond to the device, "correct" it. This
|
||||
* is common with e.g. zappers. */
|
||||
if (device != RETRO_DEVICE_JOYPAD &&
|
||||
(netplay->config_devices[port]&RETRO_DEVICE_MASK) != device)
|
||||
{
|
||||
for (port = 0; port < MAX_INPUT_DEVICES; port++)
|
||||
{
|
||||
if ((netplay->config_devices[port]&RETRO_DEVICE_MASK) == device)
|
||||
break;
|
||||
}
|
||||
if (port == MAX_INPUT_DEVICES)
|
||||
return 0;
|
||||
}
|
||||
|
||||
delta = &netplay->buffer[ptr];
|
||||
@ -513,6 +554,8 @@ static int16_t netplay_input_state(netplay_t *netplay,
|
||||
if (!istate || !istate->used)
|
||||
return 0;
|
||||
|
||||
if (istate->size == 0)
|
||||
return 0;
|
||||
curr_input_state = istate->data;
|
||||
|
||||
switch (device)
|
||||
@ -522,10 +565,23 @@ static int16_t netplay_input_state(netplay_t *netplay,
|
||||
|
||||
case RETRO_DEVICE_ANALOG:
|
||||
{
|
||||
uint32_t state = curr_input_state[1 + idx];
|
||||
uint32_t state;
|
||||
if (istate->size != 3)
|
||||
return 0;
|
||||
state = curr_input_state[1 + idx];
|
||||
return (int16_t)(uint16_t)(state >> (id * 16));
|
||||
}
|
||||
|
||||
case RETRO_DEVICE_MOUSE:
|
||||
case RETRO_DEVICE_LIGHTGUN:
|
||||
{
|
||||
if (istate->size != 2)
|
||||
return 0;
|
||||
if (id <= RETRO_DEVICE_ID_MOUSE_Y)
|
||||
return (int16_t)(uint16_t)(curr_input_state[1] >> (id * 16));
|
||||
return ((1 << id) & curr_input_state[0]) ? 1 : 0;
|
||||
}
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -35,7 +35,6 @@
|
||||
#include "../../content.h"
|
||||
#include "../../retroarch.h"
|
||||
#include "../../version.h"
|
||||
#include "../../input/input_driver.h"
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
#include "../../menu/widgets/menu_input_dialog.h"
|
||||
@ -594,7 +593,7 @@ bool netplay_handshake_sync(netplay_t *netplay,
|
||||
/* Now send the device info */
|
||||
for (i = 0; i < MAX_INPUT_DEVICES; i++)
|
||||
{
|
||||
device = htonl(input_config_get_device((unsigned)i));
|
||||
device = htonl(netplay->config_devices[i]);
|
||||
if (!netplay_send(&connection->send_packet_buffer, connection->fd,
|
||||
&device, sizeof(device)))
|
||||
return false;
|
||||
@ -1022,6 +1021,7 @@ bool netplay_handshake_pre_sync(netplay_t *netplay,
|
||||
|
||||
pad.port = (unsigned)i;
|
||||
pad.device = ntohl(device);
|
||||
netplay->config_devices[i] = pad.device;
|
||||
|
||||
core_set_controller_port_device(&pad);
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
|
||||
#include "../../autosave.h"
|
||||
#include "../../retroarch.h"
|
||||
#include "../../input/input_driver.h"
|
||||
|
||||
#if defined(AF_INET6) && !defined(HAVE_SOCKET_LEGACY)
|
||||
#define HAVE_INET6 1
|
||||
@ -466,8 +467,21 @@ netplay_t *netplay_new(void *direct_host, const char *server, uint16_t port,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!netplay->is_server)
|
||||
if (netplay->is_server)
|
||||
{
|
||||
/* Clients get device info from the server */
|
||||
unsigned i;
|
||||
for (i = 0; i < MAX_INPUT_DEVICES; i++)
|
||||
{
|
||||
uint32_t dtype = input_config_get_device(i);
|
||||
netplay->config_devices[i] = dtype;
|
||||
if (dtype != RETRO_DEVICE_NONE && !netplay_expected_input_size(netplay, 1<<i))
|
||||
RARCH_WARN("Netplay does not support input device %u\n", i+1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Start our handshake */
|
||||
netplay_handshake_init_send(netplay, &netplay->connections[0]);
|
||||
|
||||
netplay->connections[0].mode = NETPLAY_CONNECTION_INIT;
|
||||
|
@ -232,7 +232,7 @@ static bool send_input_frame(netplay_t *netplay, struct delta_frame *dframe,
|
||||
if (!(devices & (1<<device)))
|
||||
continue;
|
||||
istate = dframe->real_input[device];
|
||||
while (istate && istate->client_num != client_num)
|
||||
while (istate && (!istate->used || istate->client_num != client_num))
|
||||
istate = istate->next;
|
||||
if (!istate)
|
||||
continue;
|
||||
@ -810,7 +810,7 @@ static void handle_play_spectate(netplay_t *netplay, uint32_t client_num,
|
||||
/* Find an available device */
|
||||
for (device = 0; device < MAX_INPUT_DEVICES; device++)
|
||||
{
|
||||
if (input_config_get_device(device) == RETRO_DEVICE_NONE)
|
||||
if (netplay->config_devices[device] == RETRO_DEVICE_NONE)
|
||||
{
|
||||
device = MAX_INPUT_DEVICES;
|
||||
break;
|
||||
@ -985,7 +985,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
|
||||
/* Figure out how much input is expected */
|
||||
devices = netplay->client_devices[client_num];
|
||||
input_size = netplay_expected_input_size(devices);
|
||||
input_size = netplay_expected_input_size(netplay, devices);
|
||||
|
||||
if (cmd_size != (2+input_size) * sizeof(uint32_t))
|
||||
{
|
||||
@ -1037,7 +1037,7 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
if (!(devices & (1<<device)))
|
||||
continue;
|
||||
|
||||
dsize = netplay_expected_input_size(1 << device);
|
||||
dsize = netplay_expected_input_size(netplay, 1 << device);
|
||||
istate = netplay_input_state_for(&dframe->real_input[device],
|
||||
client_num, dsize, true, false);
|
||||
if (!istate)
|
||||
@ -1297,12 +1297,15 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
{
|
||||
for (device = 0; device < MAX_INPUT_DEVICES; device++)
|
||||
{
|
||||
uint32_t dsize;
|
||||
netplay_input_state_t istate;
|
||||
if (!(devices & (1<<device))) continue;
|
||||
netplay_input_state_t istate = netplay_input_state_for(
|
||||
&dframe->real_input[device], client_num,
|
||||
3 /* FIXME */, false, false);
|
||||
dsize = netplay_expected_input_size(netplay, 1 << device);
|
||||
istate = netplay_input_state_for(
|
||||
&dframe->real_input[device], client_num, dsize,
|
||||
false, false);
|
||||
if (!istate) continue;
|
||||
memset(istate->data, 0, istate->size*sizeof(uint32_t));
|
||||
memset(istate->data, 0, dsize*sizeof(uint32_t));
|
||||
}
|
||||
dframe->have_local = true;
|
||||
dframe->have_real[client_num] = true;
|
||||
|
@ -436,6 +436,10 @@ struct netplay
|
||||
* attempt to stay in sync. */
|
||||
uint32_t desync;
|
||||
|
||||
/* The device types for every connected device. We store them and ignore any
|
||||
* menu changes, as netplay needs fixed devices. */
|
||||
uint32_t config_devices[MAX_INPUT_DEVICES];
|
||||
|
||||
struct retro_callbacks cbs;
|
||||
|
||||
/* TCP port (only set if serving) */
|
||||
@ -680,7 +684,7 @@ netplay_input_state_t netplay_input_state_for(netplay_input_state_t *list,
|
||||
*
|
||||
* Size in words for a given set of devices.
|
||||
*/
|
||||
uint32_t netplay_expected_input_size(uint32_t devices);
|
||||
uint32_t netplay_expected_input_size(netplay_t *netplay, uint32_t devices);
|
||||
|
||||
|
||||
/***************************************************************
|
||||
|
@ -96,15 +96,17 @@ struct vote_count {
|
||||
netplay_input_state_t netplay_device_client_state(netplay_t *netplay,
|
||||
struct delta_frame *simframe, uint32_t device, uint32_t client)
|
||||
{
|
||||
uint32_t dsize = netplay_expected_input_size(netplay, 1 << device);
|
||||
netplay_input_state_t simstate =
|
||||
netplay_input_state_for(
|
||||
&simframe->real_input[device], client, 3 /* FIXME */, false, true);
|
||||
&simframe->real_input[device], client,
|
||||
dsize, false, true);
|
||||
if (!simstate)
|
||||
{
|
||||
if (netplay->read_frame_count[client] > simframe->frame)
|
||||
return NULL;
|
||||
simstate = netplay_input_state_for(&simframe->simlated_input[device],
|
||||
client, 3 /* FIXME */, false, true);
|
||||
client, dsize, false, true);
|
||||
}
|
||||
return simstate;
|
||||
}
|
||||
@ -129,7 +131,7 @@ static void netplay_merge_digital(netplay_t *netplay,
|
||||
/* Make sure all real clients are accounted for */
|
||||
for (simstate = simframe->real_input[device]; simstate; simstate = simstate->next)
|
||||
{
|
||||
if (!simstate->used || simstate->size != 3 /* FIXME */) continue;
|
||||
if (!simstate->used || simstate->size != resstate->size) continue;
|
||||
clients |= 1<<simstate->client_num;
|
||||
}
|
||||
|
||||
@ -137,6 +139,8 @@ static void netplay_merge_digital(netplay_t *netplay,
|
||||
{
|
||||
/* Vote mode requires counting all the bits */
|
||||
uint32_t client_count = 0;
|
||||
|
||||
/* This just assumes we have no more than three words, will need to be adjusted for new devices */
|
||||
struct vote_count votes[3] = {0};
|
||||
for (client = 0; client < MAX_CLIENTS; client++)
|
||||
{
|
||||
@ -145,7 +149,7 @@ static void netplay_merge_digital(netplay_t *netplay,
|
||||
if (!simstate) continue;
|
||||
client_count++;
|
||||
|
||||
for (word = 0; word < 3 /* FIXME */; word++)
|
||||
for (word = 0; word < resstate->size; word++)
|
||||
{
|
||||
if (!digital[word]) continue;
|
||||
for (bit = 0; bit < 32; bit++)
|
||||
@ -159,7 +163,7 @@ static void netplay_merge_digital(netplay_t *netplay,
|
||||
|
||||
/* Now count all the bits */
|
||||
client_count /= 2;
|
||||
for (word = 0; word < 3 /* FIXME */; word++)
|
||||
for (word = 0; word < resstate->size; word++)
|
||||
{
|
||||
for (bit = 0; bit < 32; bit++)
|
||||
{
|
||||
@ -176,7 +180,7 @@ static void netplay_merge_digital(netplay_t *netplay,
|
||||
if (!(clients & (1<<client))) continue;
|
||||
simstate = netplay_device_client_state(netplay, simframe, device, client);
|
||||
if (!simstate) continue;
|
||||
for (word = 0; word < 3 /* FIXME */; word++)
|
||||
for (word = 0; word < resstate->size; word++)
|
||||
{
|
||||
uint32_t part;
|
||||
if (!digital[word]) continue;
|
||||
@ -231,7 +235,7 @@ static void merge_analog_part(netplay_t *netplay,
|
||||
/* Make sure all real clients are accounted for */
|
||||
for (simstate = simframe->real_input[device]; simstate; simstate = simstate->next)
|
||||
{
|
||||
if (!simstate->used || simstate->size != 3 /* FIXME */) continue;
|
||||
if (!simstate->used || simstate->size != resstate->size) continue;
|
||||
clients |= 1<<simstate->client_num;
|
||||
}
|
||||
|
||||
@ -267,16 +271,23 @@ static void merge_analog_part(netplay_t *netplay,
|
||||
* @simframe : frame in which merging is being performed
|
||||
* @device : device being merged
|
||||
* @clients : bitmap of clients being merged
|
||||
* @dtype : device type
|
||||
*/
|
||||
static void netplay_merge_analog(netplay_t *netplay,
|
||||
netplay_input_state_t resstate, struct delta_frame *simframe,
|
||||
uint32_t device, uint32_t clients)
|
||||
uint32_t device, uint32_t clients, unsigned dtype)
|
||||
{
|
||||
/* FIXME: Assumes 3-byte gamepad */
|
||||
if (dtype == RETRO_DEVICE_JOYPAD)
|
||||
return;
|
||||
/* All other devices have analog */
|
||||
|
||||
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);
|
||||
if (dtype == RETRO_DEVICE_ANALOG)
|
||||
{
|
||||
merge_analog_part(netplay, resstate, simframe, device, clients, 2, 0);
|
||||
merge_analog_part(netplay, resstate, simframe, device, clients, 2, 16);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -303,13 +314,15 @@ bool netplay_resolve_input(netplay_t *netplay, size_t sim_ptr, bool resim)
|
||||
|
||||
for (device = 0; device < MAX_INPUT_DEVICES; device++)
|
||||
{
|
||||
unsigned dtype = netplay->config_devices[device]&RETRO_DEVICE_MASK;
|
||||
uint32_t dsize = netplay_expected_input_size(netplay, 1 << device);
|
||||
clients = netplay->device_clients[device];
|
||||
client_count = 0;
|
||||
|
||||
/* Make sure all real clients are accounted for */
|
||||
for (simstate = simframe->real_input[device]; simstate; simstate = simstate->next)
|
||||
{
|
||||
if (!simstate->used || simstate->size != 3 /* FIXME */) continue;
|
||||
if (!simstate->used || simstate->size != dsize) continue;
|
||||
clients |= 1<<simstate->client_num;
|
||||
}
|
||||
|
||||
@ -318,19 +331,19 @@ bool netplay_resolve_input(netplay_t *netplay, size_t sim_ptr, bool resim)
|
||||
if (!(clients & (1<<client))) continue;
|
||||
|
||||
/* Resolve this client-device */
|
||||
simstate = netplay_input_state_for(&simframe->real_input[device], client, 3 /* FIXME */, false, true);
|
||||
simstate = netplay_input_state_for(&simframe->real_input[device], client, dsize, false, true);
|
||||
if (!simstate)
|
||||
{
|
||||
/* Don't already have this input, so must simulate if we're supposed to have it at all */
|
||||
if (netplay->read_frame_count[client] > simframe->frame)
|
||||
continue;
|
||||
simstate = netplay_input_state_for(&simframe->simlated_input[device], client, 3 /* FIXME */, false, false);
|
||||
simstate = netplay_input_state_for(&simframe->simlated_input[device], client, dsize, false, false);
|
||||
if (!simstate)
|
||||
continue;
|
||||
|
||||
prev = PREV_PTR(netplay->read_ptr[client]);
|
||||
pframe = &netplay->buffer[prev];
|
||||
pstate = netplay_input_state_for(&pframe->real_input[device], client, 3 /* FIXME */, false, true);
|
||||
pstate = netplay_input_state_for(&pframe->real_input[device], client, dsize, false, true);
|
||||
if (!pstate)
|
||||
continue;
|
||||
|
||||
@ -351,17 +364,28 @@ bool netplay_resolve_input(netplay_t *netplay, size_t sim_ptr, bool resim)
|
||||
* which will seem to jerkily be pressed numerous times with those
|
||||
* wavefronts.
|
||||
*/
|
||||
const uint32_t keep = (1U<<RETRO_DEVICE_ID_JOYPAD_UP) |
|
||||
(1U<<RETRO_DEVICE_ID_JOYPAD_DOWN) |
|
||||
(1U<<RETRO_DEVICE_ID_JOYPAD_LEFT) |
|
||||
(1U<<RETRO_DEVICE_ID_JOYPAD_RIGHT);
|
||||
const uint32_t keep_joypad =
|
||||
(1U<<RETRO_DEVICE_ID_JOYPAD_UP) |
|
||||
(1U<<RETRO_DEVICE_ID_JOYPAD_DOWN) |
|
||||
(1U<<RETRO_DEVICE_ID_JOYPAD_LEFT) |
|
||||
(1U<<RETRO_DEVICE_ID_JOYPAD_RIGHT);
|
||||
uint32_t keep;
|
||||
switch (dtype)
|
||||
{
|
||||
case RETRO_DEVICE_JOYPAD:
|
||||
case RETRO_DEVICE_ANALOG:
|
||||
keep = keep_joypad;
|
||||
break;
|
||||
default:
|
||||
keep = 0;
|
||||
}
|
||||
simstate->data[0] &= keep;
|
||||
simstate->data[0] |= pstate->data[0] & ~keep;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(simstate->data, pstate->data,
|
||||
simstate->size * sizeof(uint32_t));
|
||||
dsize * sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
|
||||
@ -369,23 +393,35 @@ bool netplay_resolve_input(netplay_t *netplay, size_t sim_ptr, bool resim)
|
||||
client_count++;
|
||||
}
|
||||
|
||||
/* The frontend always uses the first resolved input, so make sure it's right */
|
||||
while (simframe->resolved_input[device]
|
||||
&& (simframe->resolved_input[device]->size != dsize
|
||||
|| simframe->resolved_input[device]->client_num != 0))
|
||||
{
|
||||
/* The default resolved input is of the wrong size! */
|
||||
netplay_input_state_t nextistate = simframe->resolved_input[device]->next;
|
||||
free(simframe->resolved_input[device]);
|
||||
simframe->resolved_input[device] = nextistate;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
resstate = netplay_input_state_for(&simframe->resolved_input[device], 0,
|
||||
dsize, false, false);
|
||||
if (!resstate)
|
||||
continue;
|
||||
|
||||
if (client_count == 1)
|
||||
{
|
||||
/* Trivial in the common 1-client case */
|
||||
if (memcmp(resstate->data, client_state->data, resstate->size * sizeof(uint32_t)))
|
||||
if (memcmp(resstate->data, client_state->data, dsize * sizeof(uint32_t)))
|
||||
ret = true;
|
||||
memcpy(resstate->data, client_state->data, resstate->size * sizeof(uint32_t));
|
||||
memcpy(resstate->data, client_state->data, dsize * sizeof(uint32_t));
|
||||
|
||||
}
|
||||
else if (client_count == 0)
|
||||
{
|
||||
uint32_t word;
|
||||
for (word = 0; word < resstate->size; word++)
|
||||
for (word = 0; word < dsize; word++)
|
||||
{
|
||||
if (resstate->data[word])
|
||||
ret = true;
|
||||
@ -396,17 +432,20 @@ bool netplay_resolve_input(netplay_t *netplay, size_t sim_ptr, bool resim)
|
||||
else
|
||||
{
|
||||
/* Merge them */
|
||||
/* NOTE: As it happens, all of our devices keep the digital data in
|
||||
* the first word, so this is fine, but it'll have to change when
|
||||
* other devices are supported. */
|
||||
static const uint32_t digital[3] = {-1, 0, 0};
|
||||
oldresstate = netplay_input_state_for(&simframe->resolved_input[device], 1, 3 /* FIXME */, false, false);
|
||||
oldresstate = netplay_input_state_for(&simframe->resolved_input[device], 1, dsize, false, false);
|
||||
if (!oldresstate)
|
||||
continue;
|
||||
memcpy(oldresstate->data, resstate->data, oldresstate->size * sizeof(uint32_t));
|
||||
memset(resstate->data, 0, resstate->size * sizeof(uint32_t));
|
||||
memcpy(oldresstate->data, resstate->data, dsize * sizeof(uint32_t));
|
||||
memset(resstate->data, 0, dsize * sizeof(uint32_t));
|
||||
|
||||
netplay_merge_digital(netplay, resstate, simframe, device, clients, digital);
|
||||
netplay_merge_analog(netplay, resstate, simframe, device, clients);
|
||||
netplay_merge_analog(netplay, resstate, simframe, device, clients, dtype);
|
||||
|
||||
if (memcmp(resstate->data, oldresstate->data, resstate->size * sizeof(uint32_t)))
|
||||
if (memcmp(resstate->data, oldresstate->data, dsize * sizeof(uint32_t)))
|
||||
ret = true;
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user