Re-fixed input simulation.

This commit is contained in:
Gregor Richards 2017-09-10 09:12:32 -04:00
parent 8c551f3990
commit b897ba4e30
5 changed files with 89 additions and 72 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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));
}

View File

@ -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

View File

@ -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 */