mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-25 00:49:47 +00:00
Re-fixed input simulation.
This commit is contained in:
parent
8c551f3990
commit
b897ba4e30
@ -59,9 +59,9 @@ bool netplay_delta_frame_ready(netplay_t *netplay, struct delta_frame *delta,
|
||||
delta->crc = 0;
|
||||
for (i = 0; i < MAX_INPUT_DEVICES; i++)
|
||||
{
|
||||
clear_input(delta->resolved_input[i]);
|
||||
clear_input(delta->real_input[i]);
|
||||
clear_input(delta->simulated_input[i]);
|
||||
clear_input(delta->resolved_input1[i]);
|
||||
clear_input(delta->real_input1[i]);
|
||||
clear_input(delta->simulated_input1[i]);
|
||||
}
|
||||
delta->have_local = false;
|
||||
for (i = 0; i < MAX_CLIENTS; i++)
|
||||
@ -117,9 +117,9 @@ void netplay_delta_frame_free(struct delta_frame *delta)
|
||||
|
||||
for (i = 0; i < MAX_INPUT_DEVICES; i++)
|
||||
{
|
||||
free_input_state(&delta->resolved_input[i]);
|
||||
free_input_state(&delta->real_input[i]);
|
||||
free_input_state(&delta->simulated_input[i]);
|
||||
free_input_state(&delta->resolved_input1[i]);
|
||||
free_input_state(&delta->real_input1[i]);
|
||||
free_input_state(&delta->simulated_input1[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,13 +129,13 @@ void netplay_delta_frame_free(struct delta_frame *delta)
|
||||
* Get an input state for a particular client
|
||||
*/
|
||||
netplay_input_state_t netplay_input_state_for(netplay_input_state_t *list,
|
||||
uint32_t client_num, size_t size, bool must_create)
|
||||
uint32_t client_num, size_t size, bool must_create, bool must_not_create)
|
||||
{
|
||||
netplay_input_state_t ret;
|
||||
while (*list)
|
||||
{
|
||||
ret = *list;
|
||||
if (!ret->used && ret->size == size)
|
||||
if (!ret->used && !must_not_create && ret->size == size)
|
||||
{
|
||||
ret->client_num = client_num;
|
||||
ret->used = true;
|
||||
@ -151,6 +151,9 @@ netplay_input_state_t netplay_input_state_for(netplay_input_state_t *list,
|
||||
list = &(ret->next);
|
||||
}
|
||||
|
||||
if (must_not_create)
|
||||
return NULL;
|
||||
|
||||
/* Couldn't find a slot, allocate a fresh one */
|
||||
ret = calloc(1, sizeof(struct netplay_input_state) + (size-1) * sizeof(uint32_t));
|
||||
if (!ret)
|
||||
|
@ -135,8 +135,8 @@ static bool get_self_input_state(netplay_t *netplay)
|
||||
if (!(devices & (1<<devi)))
|
||||
continue;
|
||||
|
||||
istate = netplay_input_state_for(&ptr->real_input[devi],
|
||||
netplay->self_client_num, 3 /* FIXME */, true);
|
||||
istate = netplay_input_state_for(&ptr->real_input1[devi],
|
||||
netplay->self_client_num, 3 /* FIXME */, true, false);
|
||||
if (!istate)
|
||||
continue; /* FIXME: More severe? */
|
||||
|
||||
@ -501,11 +501,9 @@ static int16_t netplay_input_state(netplay_t *netplay,
|
||||
|
||||
/* FIXME: Mixing */
|
||||
delta = &netplay->buffer[ptr];
|
||||
istate = delta->real_input[port];
|
||||
istate = delta->resolved_input1[port];
|
||||
if (istate && istate->used)
|
||||
delta->used_real[port] = true;
|
||||
else
|
||||
istate = delta->simulated_input[port];
|
||||
if (!istate)
|
||||
return 0;
|
||||
|
||||
|
@ -225,7 +225,7 @@ static bool send_input_frame(netplay_t *netplay, struct delta_frame *dframe,
|
||||
netplay_input_state_t istate;
|
||||
if (!(devices & (1<<device)))
|
||||
continue;
|
||||
istate = dframe->real_input[device];
|
||||
istate = dframe->real_input1[device];
|
||||
while (istate && istate->client_num != client_num)
|
||||
istate = istate->next;
|
||||
if (!istate)
|
||||
@ -633,8 +633,13 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
continue;
|
||||
|
||||
dsize = netplay_expected_input_size(1 << device);
|
||||
istate = netplay_input_state_for(&dframe->real_input[device],
|
||||
client_num, dsize, true);
|
||||
istate = netplay_input_state_for(&dframe->real_input1[device],
|
||||
client_num, dsize, true, false);
|
||||
if (!istate)
|
||||
{
|
||||
/* Catastrophe! */
|
||||
return netplay_cmd_nak(netplay, connection);
|
||||
}
|
||||
RECV(istate->data, dsize*sizeof(uint32_t))
|
||||
return false;
|
||||
for (di = 0; di < dsize; di++)
|
||||
@ -1002,7 +1007,9 @@ static bool netplay_get_cmd(netplay_t *netplay,
|
||||
for (device = 0; device < MAX_INPUT_DEVICES; device++)
|
||||
{
|
||||
if (!(devices & (1<<device))) continue;
|
||||
netplay_input_state_t istate = netplay_input_state_for(&dframe->real_input[device], client_num, 3 /* FIXME */, true);
|
||||
netplay_input_state_t istate = netplay_input_state_for(
|
||||
&dframe->real_input1[device], client_num,
|
||||
3 /* FIXME */, true, false);
|
||||
memset(istate->data, 0, istate->size*sizeof(uint32_t));
|
||||
}
|
||||
dframe->have_local = true;
|
||||
@ -1653,13 +1660,13 @@ void netplay_handle_slaves(netplay_t *netplay)
|
||||
netplay_input_state_t istate_out, istate_in;
|
||||
if (!(devices & (1<<device)))
|
||||
continue;
|
||||
istate_in = oframe->real_input[device];
|
||||
istate_in = oframe->real_input1[device];
|
||||
while (istate_in && istate_in->client_num != client_num)
|
||||
istate_in = istate_in->next;
|
||||
if (!istate_in)
|
||||
continue;
|
||||
istate_out = netplay_input_state_for(&frame->real_input[device],
|
||||
client_num, istate_in->size, true);
|
||||
istate_out = netplay_input_state_for(&frame->real_input1[device],
|
||||
client_num, istate_in->size, true, false);
|
||||
memcpy(istate_out->data, istate_in->data,
|
||||
istate_in->size * sizeof(uint32_t));
|
||||
}
|
||||
|
@ -278,14 +278,14 @@ struct delta_frame
|
||||
|
||||
/* The resolved input, i.e., what's actually going to the core. One input
|
||||
* per device. */
|
||||
netplay_input_state_t resolved_input[MAX_INPUT_DEVICES];
|
||||
netplay_input_state_t resolved_input1[MAX_INPUT_DEVICES];
|
||||
|
||||
/* The real input */
|
||||
netplay_input_state_t real_input[MAX_INPUT_DEVICES];
|
||||
netplay_input_state_t real_input1[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];
|
||||
netplay_input_state_t simulated_input1[MAX_INPUT_DEVICES];
|
||||
|
||||
/* Have we read local input? */
|
||||
bool have_local;
|
||||
@ -656,7 +656,7 @@ void netplay_delta_frame_free(struct delta_frame *delta);
|
||||
* Get an input state for a particular client
|
||||
*/
|
||||
netplay_input_state_t netplay_input_state_for(netplay_input_state_t *list,
|
||||
uint32_t client_num, size_t size, bool must_create);
|
||||
uint32_t client_num, size_t size, bool must_create, bool must_not_create);
|
||||
|
||||
/**
|
||||
* netplay_expected_input_size
|
||||
|
@ -98,68 +98,79 @@ bool netplay_resolve_input(netplay_t *netplay, size_t sim_ptr, bool resim)
|
||||
uint32_t client;
|
||||
size_t prev;
|
||||
struct delta_frame *simframe, *pframe;
|
||||
netplay_input_state_t simstate, pstate;
|
||||
netplay_input_state_t simstate, resstate, pstate;
|
||||
uint32_t devices, device;
|
||||
bool ret = false;
|
||||
bool ret = false, simulated;
|
||||
|
||||
simframe = &netplay->buffer[sim_ptr];
|
||||
|
||||
for (client = 0; client < MAX_CLIENTS; client++)
|
||||
{
|
||||
if (!(netplay->connected_players1 & (1<<client))) continue;
|
||||
// FIXME: Maybe this is the right time to do resolved data?
|
||||
if (simframe->have_real[client]) continue;
|
||||
|
||||
devices = netplay->client_devices[client];
|
||||
|
||||
for (device = 0; device < MAX_INPUT_DEVICES; device++)
|
||||
{
|
||||
if (!(devices & device)) continue;
|
||||
if (!(devices & (1<<device)))
|
||||
continue;
|
||||
|
||||
simstate = netplay_input_state_for(&simframe->simulated_input[device], client, 3 /* FIXME */, false);
|
||||
simulated = false;
|
||||
simstate = netplay_input_state_for(&simframe->real_input1[device], client, 3 /* FIXME */, false, true);
|
||||
if (!simstate)
|
||||
continue;
|
||||
|
||||
prev = PREV_PTR(netplay->read_ptr1[client]);
|
||||
pframe = &netplay->buffer[prev];
|
||||
pstate = netplay_input_state_for(&pframe->real_input[device], client, 3 /* FIXME */, false);
|
||||
if (!pstate)
|
||||
continue;
|
||||
|
||||
if (resim)
|
||||
{
|
||||
/* In resimulation mode, we only copy the buttons. The reason for this
|
||||
* is nonobvious:
|
||||
*
|
||||
* If we resimulated nothing, then the /duration/ with which any input
|
||||
* was pressed would be approximately correct, since the original
|
||||
* simulation came in as the input came in, but the /number of times/
|
||||
* the input was pressed would be wrong, as there would be an
|
||||
* advancing wavefront of real data overtaking the simulated data
|
||||
* (which is really just real data offset by some frames).
|
||||
*
|
||||
* That's acceptable for arrows in most situations, since the amount
|
||||
* you move is tied to the duration, but unacceptable for buttons,
|
||||
* which will seem to jerkily be pressed numerous times with those
|
||||
* wavefronts.
|
||||
*/
|
||||
const uint32_t keep = (1U<<RETRO_DEVICE_ID_JOYPAD_UP) |
|
||||
(1U<<RETRO_DEVICE_ID_JOYPAD_DOWN) |
|
||||
(1U<<RETRO_DEVICE_ID_JOYPAD_LEFT) |
|
||||
(1U<<RETRO_DEVICE_ID_JOYPAD_RIGHT);
|
||||
uint32_t prev = simstate->data[0];
|
||||
simstate->data[0] &= keep;
|
||||
simstate->data[0] |= pstate->data[0] & ~keep;
|
||||
if (prev != simstate->data[0])
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (memcmp(simstate->data, pstate->data, simstate->size * sizeof(uint32_t)))
|
||||
ret = true;
|
||||
memcpy(simstate->data, pstate->data,
|
||||
simstate->size * sizeof(uint32_t));
|
||||
/* Don't already have this input, so must simulate */
|
||||
simulated = true;
|
||||
simstate = netplay_input_state_for(&simframe->simulated_input1[device], client, 3 /* FIXME */, false, false);
|
||||
if (!simstate)
|
||||
continue;
|
||||
|
||||
prev = PREV_PTR(netplay->read_ptr1[client]);
|
||||
pframe = &netplay->buffer[prev];
|
||||
pstate = netplay_input_state_for(&pframe->real_input1[device], client, 3 /* FIXME */, false, true);
|
||||
if (!pstate)
|
||||
continue;
|
||||
|
||||
if (resim)
|
||||
{
|
||||
/* In resimulation mode, we only copy the buttons. The reason for this
|
||||
* is nonobvious:
|
||||
*
|
||||
* If we resimulated nothing, then the /duration/ with which any input
|
||||
* was pressed would be approximately correct, since the original
|
||||
* simulation came in as the input came in, but the /number of times/
|
||||
* the input was pressed would be wrong, as there would be an
|
||||
* advancing wavefront of real data overtaking the simulated data
|
||||
* (which is really just real data offset by some frames).
|
||||
*
|
||||
* That's acceptable for arrows in most situations, since the amount
|
||||
* you move is tied to the duration, but unacceptable for buttons,
|
||||
* which will seem to jerkily be pressed numerous times with those
|
||||
* wavefronts.
|
||||
*/
|
||||
const uint32_t keep = (1U<<RETRO_DEVICE_ID_JOYPAD_UP) |
|
||||
(1U<<RETRO_DEVICE_ID_JOYPAD_DOWN) |
|
||||
(1U<<RETRO_DEVICE_ID_JOYPAD_LEFT) |
|
||||
(1U<<RETRO_DEVICE_ID_JOYPAD_RIGHT);
|
||||
uint32_t prev = simstate->data[0];
|
||||
simstate->data[0] &= keep;
|
||||
simstate->data[0] |= pstate->data[0] & ~keep;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(simstate->data, pstate->data,
|
||||
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_input1[device], 0, 3 /* FIXME */, false, false);
|
||||
if (!resstate)
|
||||
continue;
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -440,7 +451,6 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
|
||||
}
|
||||
|
||||
#ifndef DEBUG_NONDETERMINISTIC_CORES
|
||||
#if 0 /* FIXME: netplay_resolve_input is broken */
|
||||
if (!netplay->force_rewind)
|
||||
{
|
||||
/* Skip ahead if we predicted correctly.
|
||||
@ -460,7 +470,6 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled)
|
||||
netplay->other_frame_count++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Now replay the real input if we've gotten ahead of it */
|
||||
|
Loading…
Reference in New Issue
Block a user