Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
NetPlay: Rework pad mapping
Pad mapping and the UI behind it is significantly confusing,
and has been confusing users since NetPlay was introduced.

As part of a large code cleanup to help NetPlay more stable,
introduce a better pad mapping system where local pad mapping
is handled by the client. Now, all the server and other
clients know is which player have which controllers, and the
clients only know this so they can show the pad mapping in the
UI; they don't do anything else with it.

A future cleanup will use this pad mapping data to completely
ignore the pads configured in the settings pane on the host.
  • Loading branch information
magcius committed Aug 23, 2013
1 parent 7a53742 commit 23ff314
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 313 deletions.
213 changes: 84 additions & 129 deletions Source/Core/Core/Src/NetPlayClient.cpp
Expand Up @@ -23,22 +23,6 @@ NetSettings g_NetPlaySettings;

#define RPT_SIZE_HACK (1 << 16)

NetPlayClient::Player::Player()
{
memset(pad_map, -1, sizeof(pad_map));
}

// called from ---GUI--- thread
std::string NetPlayClient::Player::ToString() const
{
std::ostringstream ss;
ss << name << '[' << (char)(pid+'0') << "] : " << revision << " |";
for (unsigned int i=0; i<4; ++i)
ss << (pad_map[i]>=0 ? (char)(pad_map[i]+'1') : '-');
ss << " | " << ping << "ms";
return ss.str();
}

NetPad::NetPad()
{
nHi = 0x00808080;
Expand Down Expand Up @@ -200,16 +184,8 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)

case NP_MSG_PAD_MAPPING :
{
PlayerId pid;
packet >> pid;

{
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
Player& player = m_players[pid];

for (unsigned int i=0; i<4; ++i)
packet >> player.pad_map[i];
}
for (PadMapping i = 0; i < 4; i++)
packet >> m_pad_map[i];

m_dialog->Update();
}
Expand All @@ -223,7 +199,7 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)

// trusting server for good map value (>=0 && <4)
// add to pad buffer
m_pad_buffer[(unsigned)map].Push(np);
m_pad_buffer[map].Push(np);
}
break;

Expand Down Expand Up @@ -361,13 +337,36 @@ void NetPlayClient::GetPlayerList(std::string& list, std::vector<int>& pid_list)
e = m_players.end();
for ( ; i!=e; ++i)
{
ss << i->second.ToString() << '\n';
pid_list.push_back(i->second.pid);
const Player *player = &(i->second);
ss << player->name << "[" << (int)player->pid << "] : " << player->revision << " | ";
for (unsigned int j = 0; j < 4; j++)
{
if (m_pad_map[j] == player->pid)
ss << j + 1;
else
ss << '-';
}
ss << " | " << player->ping << "ms\n";
pid_list.push_back(player->pid);
}

list = ss.str();
}

// called from ---GUI--- thread
void NetPlayClient::GetPlayers(std::vector<const Player *> &player_list)
{
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
std::map<PlayerId, Player>::const_iterator
i = m_players.begin(),
e = m_players.end();
for ( ; i!=e; ++i)
{
const Player *player = &(i->second);
player_list.push_back(player);
}
}


// called from ---GUI--- thread
void NetPlayClient::SendChatMessage(const std::string& msg)
Expand All @@ -381,12 +380,12 @@ void NetPlayClient::SendChatMessage(const std::string& msg)
}

// called from ---CPU--- thread
void NetPlayClient::SendPadState(const PadMapping local_nb, const NetPad& np)
void NetPlayClient::SendPadState(const PadMapping in_game_pad, const NetPad& np)
{
// send to server
sf::Packet spac;
spac << (MessageId)NP_MSG_PAD_DATA;
spac << local_nb; // local pad num
spac << in_game_pad;
spac << np.nHi << np.nLo;

std::lock_guard<std::recursive_mutex> lks(m_crit.send);
Expand Down Expand Up @@ -457,13 +456,35 @@ void NetPlayClient::ClearBuffers()
// called from ---CPU--- thread
bool NetPlayClient::GetNetPads(const u8 pad_nb, const SPADStatus* const pad_status, NetPad* const netvalues)
{
{
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);

// in game mapping for this local pad
unsigned int in_game_num = m_local_player->pad_map[pad_nb];

// does this local pad map in game?
// The interface for this is extremely silly.
//
// Imagine a physical device that links three Gamecubes together
// and emulates NetPlay that way. Which Gamecube controls which
// in-game controllers can be configured on the device (m_pad_map)
// but which sockets on each individual Gamecube should be used
// to control which players? The solution that Dolphin uses is
// that we hardcode the knowledge that they go in order, so if
// you have a 3P game with three gamecubes, then every single
// controller should be plugged into slot 1.
//
// If you have a 4P game, then one of the Gamecubes will have
// a controller plugged into slot 1, and another in slot 2.
//
// The slot number is the "local" pad number, and what player
// it actually means is the "in-game" pad number.
//
// The interface here gives us the status of local pads, and
// expects to get back "in-game" pad numbers back in response.
// e.g. it asks "here's the input that slot 1 has, and by the
// way, what's the state of P1?"
//
// We should add this split between "in-game" pads and "local"
// pads higher up.

int in_game_num = GetPadNum(pad_nb);

// If this in-game pad is one of ours, then update from the
// information given.
if (in_game_num < 4)
{
NetPad np(pad_status);
Expand All @@ -476,89 +497,36 @@ bool NetPlayClient::GetNetPads(const u8 pad_nb, const SPADStatus* const pad_stat
m_pad_buffer[in_game_num].Push(np);

// send
SendPadState(pad_nb, np);
SendPadState(in_game_num, np);
}
}

} // unlock players

//Common::Timer bufftimer;
//bufftimer.Start();

// get padstate from buffer and send to game
// Now, we need to swap out the local value with the values
// retrieved from NetPlay. This could be the value we pushed
// above if we're configured as P1 and the code is trying
// to retrieve data for slot 1.
while (!m_pad_buffer[pad_nb].Pop(*netvalues))
{
// wait for receiving thread to push some data
Common::SleepCurrentThread(1);

if (false == m_is_running)
if (!m_is_running)
return false;

// TODO: check the time of bufftimer here,
// if it gets pretty high, ask the user if they want to disconnect

// TODO: use a condition instead of sleeping
Common::SleepCurrentThread(1);
}

//u64 hangtime = bufftimer.GetTimeElapsed();
//if (hangtime > 10)
//{
// std::ostringstream ss;
// ss << "Pad " << (int)pad_nb << ": Had to wait " << hangtime << "ms for pad data. (increase pad Buffer maybe)";
// Core::DisplayMessage(ss.str(), 1000);
//}

return true;
}

// called from ---CPU--- thread
void NetPlayClient::WiimoteInput(int _number, u16 _channelID, const void* _pData, u32 _Size)
{
//// in game mapping for this local wiimote
unsigned int in_game_num = m_local_player->pad_map[_number]; // just using gc pad_map for now

// does this local pad map in game?
if (in_game_num < 4)
{
m_wiimote_input[_number].resize(m_wiimote_input[_number].size() + 1);
m_wiimote_input[_number].back().assign((char*)_pData, (char*)_pData + _Size);
m_wiimote_input[_number].back().channel = _channelID;
}
// XXX
}

// called from ---CPU--- thread
void NetPlayClient::WiimoteUpdate(int _number)
{
{
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);

// in game mapping for this local wiimote
unsigned int in_game_num = m_local_player->pad_map[_number]; // just using gc pad_map for now

// does this local pad map in game?
if (in_game_num < 4)
{
m_wiimote_buffer[in_game_num].Push(m_wiimote_input[_number]);

// TODO: send it

m_wiimote_input[_number].clear();
}

} // unlock players

if (0 == m_wiimote_buffer[_number].Size())
{
//PanicAlert("PANIC");
return;
}

NetWiimote nw;
m_wiimote_buffer[_number].Pop(nw);

NetWiimote::const_iterator
i = nw.begin(), e = nw.end();
for ( ; i!=e; ++i)
Core::Callback_WiimoteInterruptChannel(_number, i->channel, &(*i)[0], (u32)i->size() + RPT_SIZE_HACK);
// XXX
}

// called from ---GUI--- thread and ---NETPLAY--- thread (client side)
Expand Down Expand Up @@ -586,13 +554,21 @@ bool NetPlayClient::StopGame()
// called from ---CPU--- thread
u8 NetPlayClient::GetPadNum(u8 numPAD)
{
// TODO: i don't like that this loop is running everytime there is rumble
unsigned int i = 0;
for (; i<4; ++i)
if (numPAD == m_local_player->pad_map[i])
// 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_pad_map[ingame_pad] == m_local_player->pid)
local_pad_count++;

if (local_pad_count == numPAD)
break;
}

return i;
return ingame_pad;
}

// stuff hacked into dolphin
Expand Down Expand Up @@ -658,22 +634,13 @@ u8 CSIDevice_DanceMat::NetPlay_GetPadNum(u8 numPAD)
//void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int _number)
void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int)
{
//CritLocker crit(crit_netplay_client);

//if (netplay_client)
// netplay_client->WiimoteUpdate(_number);
}

// called from ---CPU--- thread
//
int CWII_IPC_HLE_WiiMote::NetPlay_GetWiimoteNum(int _number)
{
//CritLocker crit(crit_netplay_client);

//if (netplay_client)
// return netplay_client->GetPadNum(_number); // just using gcpad mapping for now
//else
return _number;
return _number;
}

// called from ---CPU--- thread
Expand All @@ -684,19 +651,7 @@ bool CWII_IPC_HLE_WiiMote::NetPlay_WiimoteInput(int, u16, const void*, u32&)
std::lock_guard<std::mutex> lk(crit_netplay_client);

if (netplay_client)
//{
// if (_Size >= RPT_SIZE_HACK)
// {
// _Size -= RPT_SIZE_HACK;
// return false;
// }
// else
// {
// netplay_client->WiimoteInput(_number, _channelID, _pData, _Size);
// // don't use this packet
return true;
// }
//}
return true;
else
return false;
}
Expand Down
27 changes: 13 additions & 14 deletions Source/Core/Core/Src/NetPlayClient.h
Expand Up @@ -50,6 +50,15 @@ class NetPlayUI

extern NetSettings g_NetPlaySettings;

class Player
{
public:
PlayerId pid;
std::string name;
std::string revision;
u32 ping;
};

class NetPlayClient
{
public:
Expand All @@ -59,6 +68,7 @@ class NetPlayClient
~NetPlayClient();

void GetPlayerList(std::string& list, std::vector<int>& pid_list);
void GetPlayers(std::vector<const Player *>& player_list);

bool is_connected;

Expand All @@ -84,19 +94,6 @@ class NetPlayClient
std::recursive_mutex players, send;
} m_crit;

class Player
{
public:
Player();
std::string ToString() const;

PlayerId pid;
std::string name;
PadMapping pad_map[4];
std::string revision;
u32 ping;
};

Common::FifoQueue<NetPad> m_pad_buffer[4];
Common::FifoQueue<NetWiimote> m_wiimote_buffer[4];

Expand All @@ -117,8 +114,10 @@ class NetPlayClient

u32 m_current_game;

PadMapping m_pad_map[4];

private:
void SendPadState(const PadMapping local_nb, const NetPad& np);
void SendPadState(const PadMapping in_game_pad, const NetPad& np);
unsigned int OnData(sf::Packet& packet);

PlayerId m_pid;
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/Src/NetPlayProto.h
Expand Up @@ -24,7 +24,7 @@ struct Rpt : public std::vector<u8>

typedef std::vector<Rpt> NetWiimote;

#define NETPLAY_VERSION "Dolphin NetPlay 2013-08-18"
#define NETPLAY_VERSION "Dolphin NetPlay 2013-08-23"

// messages
enum
Expand Down

0 comments on commit 23ff314

Please sign in to comment.