Netplay: Fix synchronization for the Wiinote netplay

The old implementation always polled the local 1st Wiimote and used that as input for the Wiimote that is mapped to the player. But the reporting mode for Wiimotes can be different, even when using the same extensions. So an input for Wiimote 1 with a data size 4 could be used for Wiimote 2, which actually requires data size 7 at that time for example.

The 2nd problem was that the code added a dummy input into the buffer, when the reporting mode changed. But when the data from the other player hasn't arrived yet, the data in the buffer is out of order. Well, i think this is the problem, i'm not 100% sure, because i don't fully understand how the buffer works. But on the other hand, i'm pretty sure this will just force sync the players on reporting mode changes, instead of allowing them to be apart.

Pros:
- No more desyncs caused by big bugs in the code.
- Can use different extensions for different players.

Cons:
- Higher latency, because instead of polling 1 controller per player at once, all controllers are polled in order, send to the other players, before the next is processed.
- Have to setup the Wiimote, which the player is going to use, instead of the 1st one.

Now, if the controller config could temporarily be overridden with the one from another slot, the 2nd problem could be fixed. But at the same time, we would lose the ability to use different extensions. (unless we hack around it somehow, or properly send the used extension to the other players)
This commit is contained in:
mimimi085181 2016-07-16 12:46:23 +02:00
parent bb87bb73f4
commit 8b7bfe6cf9
2 changed files with 12 additions and 70 deletions

View File

@ -768,7 +768,6 @@ bool NetPlayClient::StartGame(const std::string& path)
// Needed to prevent locking up at boot if (when) the wiimotes connect out of order. // Needed to prevent locking up at boot if (when) the wiimotes connect out of order.
NetWiimote nw; NetWiimote nw;
nw.resize(4, 0); nw.resize(4, 0);
m_wiimote_current_data_size.fill(4);
for (unsigned int w = 0; w < 4; ++w) for (unsigned int w = 0; w < 4; ++w)
{ {
@ -973,46 +972,24 @@ bool NetPlayClient::WiimoteUpdate(int _number, u8* data, const u8 size)
{ {
std::lock_guard<std::recursive_mutex> lkp(m_crit.players); std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
// in game mapping for this local Wiimote // Only send data, if this Wiimote is mapped to this player
unsigned int in_game_num = LocalWiimoteToInGameWiimote(_number); if (m_wiimote_map[_number] == m_local_player->pid)
// does this local Wiimote map in game?
if (in_game_num < 4)
{ {
if (m_wiimote_current_data_size[in_game_num] == size) nw.assign(data, data + size);
do
{ {
nw.assign(data, data + size); // add to buffer
do m_wiimote_buffer[_number].Push(nw);
{
// add to buffer
m_wiimote_buffer[in_game_num].Push(nw);
SendWiimoteState(in_game_num, nw); SendWiimoteState(_number, nw);
} while (m_wiimote_buffer[in_game_num].Size() <= } while (m_wiimote_buffer[_number].Size() <=
m_target_buffer_size * 200 / m_target_buffer_size * 200 /
120); // TODO: add a seperate setting for wiimote buffer? 120); // TODO: add a seperate setting for wiimote buffer?
}
else
{
while (m_wiimote_buffer[in_game_num].Size() > 0)
{
// Reporting mode changed, so previous buffer is no good.
m_wiimote_buffer[in_game_num].Pop();
}
nw.resize(size, 0);
m_wiimote_buffer[in_game_num].Push(nw);
m_wiimote_buffer[in_game_num].Push(nw);
m_wiimote_buffer[in_game_num].Push(nw);
m_wiimote_buffer[in_game_num].Push(nw);
m_wiimote_buffer[in_game_num].Push(nw);
m_wiimote_buffer[in_game_num].Push(nw);
m_wiimote_current_data_size[in_game_num] = size;
}
} }
} // unlock players } // unlock players
while (m_wiimote_current_data_size[_number] == size && !m_wiimote_buffer[_number].Pop(nw)) while (!m_wiimote_buffer[_number].Pop(nw))
{ {
// wait for receiving thread to push some data // wait for receiving thread to push some data
Common::SleepCurrentThread(1); Common::SleepCurrentThread(1);
@ -1020,23 +997,11 @@ bool NetPlayClient::WiimoteUpdate(int _number, u8* data, const u8 size)
return false; return false;
} }
// Use a blank input, since we may not have any valid input. // If the reporting mode has changed, we just need to pop through the buffer,
if (m_wiimote_current_data_size[_number] != size)
{
nw.resize(size, 0);
m_wiimote_buffer[_number].Push(nw);
m_wiimote_buffer[_number].Push(nw);
m_wiimote_buffer[_number].Push(nw);
m_wiimote_buffer[_number].Push(nw);
m_wiimote_buffer[_number].Push(nw);
}
// We should have used a blank input last time, so now we just need to pop through the old buffer,
// until we reach a good input // until we reach a good input
if (nw.size() != size) if (nw.size() != size)
{ {
u32 tries = 0; u32 tries = 0;
// Clear the buffer and wait for new input, since we probably just changed reporting mode.
while (nw.size() != size) while (nw.size() != size)
{ {
while (!m_wiimote_buffer[_number].Pop(nw)) while (!m_wiimote_buffer[_number].Pop(nw))
@ -1058,7 +1023,6 @@ bool NetPlayClient::WiimoteUpdate(int _number, u8* data, const u8 size)
} }
} }
m_wiimote_current_data_size[_number] = size;
memcpy(data, nw.data(), size); memcpy(data, nw.data(), size);
return true; return true;
} }
@ -1155,25 +1119,6 @@ u8 NetPlayClient::LocalPadToInGamePad(u8 local_pad)
return ingame_pad; return ingame_pad;
} }
u8 NetPlayClient::LocalWiimoteToInGameWiimote(u8 local_pad)
{
// Figure out which in-game pad maps to which local pad.
// The logic we have here is that the local slots always
// go in order.
int local_pad_count = -1;
int ingame_pad = 0;
for (; ingame_pad < 4; ingame_pad++)
{
if (m_wiimote_map[ingame_pad] == m_local_player->pid)
local_pad_count++;
if (local_pad_count == local_pad)
break;
}
return ingame_pad;
}
void NetPlayClient::SendTimeBase() void NetPlayClient::SendTimeBase()
{ {
std::lock_guard<std::mutex> lk(crit_netplay_client); std::lock_guard<std::mutex> lk(crit_netplay_client);

View File

@ -89,8 +89,6 @@ public:
u8 InGamePadToLocalPad(u8 ingame_pad); u8 InGamePadToLocalPad(u8 ingame_pad);
u8 LocalPadToInGamePad(u8 localPad); u8 LocalPadToInGamePad(u8 localPad);
u8 LocalWiimoteToInGameWiimote(u8 local_pad);
static void SendTimeBase(); static void SendTimeBase();
bool DoAllPlayersHaveGame(); bool DoAllPlayersHaveGame();
@ -109,7 +107,6 @@ protected:
std::array<Common::FifoQueue<GCPadStatus>, 4> m_pad_buffer; std::array<Common::FifoQueue<GCPadStatus>, 4> m_pad_buffer;
std::array<Common::FifoQueue<NetWiimote>, 4> m_wiimote_buffer; std::array<Common::FifoQueue<NetWiimote>, 4> m_wiimote_buffer;
std::array<u32, 4> m_wiimote_current_data_size;
NetPlayUI* m_dialog = nullptr; NetPlayUI* m_dialog = nullptr;