diff --git a/Source/Core/Core/Src/NetPlayClient.cpp b/Source/Core/Core/Src/NetPlayClient.cpp index 33f31a1815..fc8f005fad 100644 --- a/Source/Core/Core/Src/NetPlayClient.cpp +++ b/Source/Core/Core/Src/NetPlayClient.cpp @@ -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; @@ -200,16 +184,8 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet) case NP_MSG_PAD_MAPPING : { - PlayerId pid; - packet >> pid; - - { - std::lock_guard 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(); } @@ -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; @@ -361,13 +337,36 @@ void NetPlayClient::GetPlayerList(std::string& list, std::vector& 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 &player_list) +{ + std::lock_guard lkp(m_crit.players); + std::map::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) @@ -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 lks(m_crit.send); @@ -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 lkp(m_crit.players); + // 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. - // in game mapping for this local pad - unsigned int in_game_num = m_local_player->pad_map[pad_nb]; + int in_game_num = GetPadNum(pad_nb); - // does this local pad map in game? + // If this in-game pad is one of ours, then update from the + // information given. if (in_game_num < 4) { NetPad np(pad_status); @@ -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 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) @@ -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]) - break; + // 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++; - return i; + if (local_pad_count == numPAD) + break; + } + + return ingame_pad; } // stuff hacked into dolphin @@ -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 @@ -684,19 +651,7 @@ bool CWII_IPC_HLE_WiiMote::NetPlay_WiimoteInput(int, u16, const void*, u32&) std::lock_guard 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; } diff --git a/Source/Core/Core/Src/NetPlayClient.h b/Source/Core/Core/Src/NetPlayClient.h index d44a4c84b8..23529dbb95 100644 --- a/Source/Core/Core/Src/NetPlayClient.h +++ b/Source/Core/Core/Src/NetPlayClient.h @@ -50,6 +50,15 @@ public: extern NetSettings g_NetPlaySettings; +class Player +{ + public: + PlayerId pid; + std::string name; + std::string revision; + u32 ping; +}; + class NetPlayClient { public: @@ -59,6 +68,7 @@ public: ~NetPlayClient(); void GetPlayerList(std::string& list, std::vector& pid_list); + void GetPlayers(std::vector& player_list); bool is_connected; @@ -84,19 +94,6 @@ protected: 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 m_pad_buffer[4]; Common::FifoQueue m_wiimote_buffer[4]; @@ -117,8 +114,10 @@ protected: 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; diff --git a/Source/Core/Core/Src/NetPlayProto.h b/Source/Core/Core/Src/NetPlayProto.h index d4abf60cb8..432b9766e5 100644 --- a/Source/Core/Core/Src/NetPlayProto.h +++ b/Source/Core/Core/Src/NetPlayProto.h @@ -24,7 +24,7 @@ struct Rpt : public std::vector typedef std::vector NetWiimote; -#define NETPLAY_VERSION "Dolphin NetPlay 2013-08-18" +#define NETPLAY_VERSION "Dolphin NetPlay 2013-08-23" // messages enum diff --git a/Source/Core/Core/Src/NetPlayServer.cpp b/Source/Core/Core/Src/NetPlayServer.cpp index 134045c5bf..30b1d26664 100644 --- a/Source/Core/Core/Src/NetPlayServer.cpp +++ b/Source/Core/Core/Src/NetPlayServer.cpp @@ -4,11 +4,6 @@ #include "NetPlayServer.h" -NetPlayServer::Client::Client() -{ - memset(pad_map, -1, sizeof(pad_map)); -} - NetPlayServer::~NetPlayServer() { if (is_connected) @@ -29,6 +24,7 @@ NetPlayServer::~NetPlayServer() // called from ---GUI--- thread NetPlayServer::NetPlayServer(const u16 port) : is_connected(false), m_is_running(false) { + memset(m_pad_map, -1, sizeof(m_pad_map)); if (m_socket.Listen(port)) { is_connected = true; @@ -155,45 +151,16 @@ unsigned int NetPlayServer::OnConnect(sf::SocketTCP& socket) rpac >> player.name; // give new client first available id - player.pid = 0; - std::map::const_iterator - i, - e = m_players.end(); - for (PlayerId p = 1; 0 == player.pid; ++p) - { - for (i = m_players.begin(); ; ++i) - { - if (e == i) - { - player.pid = p; - break; - } - if (p == i->second.pid) - break; - } - } + player.pid = m_players.size() + 1; - // TODO: this is crappy // try to automatically assign new user a pad + for (unsigned int m = 0; m < 4; ++m) { - bool is_mapped[4] = {false,false,false,false}; - - for ( unsigned int m = 0; m<4; ++m) - { - for (i = m_players.begin(); i!=e; ++i) + if (m_pad_map[m] == -1) { - if (i->second.pad_map[m] >= 0) - is_mapped[(unsigned)i->second.pad_map[m]] = true; - } - } - - for ( unsigned int m = 0; m<4; ++m) - if (false == is_mapped[m]) - { - player.pad_map[0] = m; + m_pad_map[m] = player.pid; break; } - } { @@ -221,6 +188,9 @@ unsigned int NetPlayServer::OnConnect(sf::SocketTCP& socket) } // sync values with new client + std::map::const_iterator + i, + e = m_players.end(); for (i = m_players.begin(); i!=e; ++i) { spac.Clear(); @@ -279,83 +249,28 @@ unsigned int NetPlayServer::OnDisconnect(sf::SocketTCP& socket) } // called from ---GUI--- thread -bool NetPlayServer::GetPadMapping(const int pid, int map[]) +void NetPlayServer::GetPadMapping(PadMapping map[4]) { - std::lock_guard lkp(m_crit.players); - std::map::const_iterator - i = m_players.begin(), - e = m_players.end(); - for (; i!=e; ++i) - if (pid == i->second.pid) - break; - - // player not found - if (i == e) - return false; - - // get pad mapping - for (unsigned int m = 0; m<4; ++m) - map[m] = i->second.pad_map[m]; - - return true; + for (int i = 0; i < 4; i++) + map[i] = m_pad_map[i]; } // called from ---GUI--- thread -bool NetPlayServer::SetPadMapping(const int pid, const int map[]) +void NetPlayServer::SetPadMapping(const PadMapping map[4]) { - std::lock_guard lkg(m_crit.game); - if (m_is_running) - return false; - - std::lock_guard lkp(m_crit.players); - std::map::iterator - i = m_players.begin(), - e = m_players.end(); - for (; i!=e; ++i) - if (pid == i->second.pid) - break; - - // player not found - if (i == e) - return false; - - Client& player = i->second; - - // set pad mapping - for (unsigned int m = 0; m<4; ++m) - { - player.pad_map[m] = (PadMapping)map[m]; - - // remove duplicate mappings - for (i = m_players.begin(); i!=e; ++i) - for (unsigned int p = 0; p<4; ++p) - if (p != m || i->second.pid != pid) - if (player.pad_map[m] == i->second.pad_map[p]) - i->second.pad_map[p] = -1; - } - - std::lock_guard lks(m_crit.send); - UpdatePadMapping(); // sync pad mappings with everyone - - return true; + for (int i = 0; i < 4; i++) + m_pad_map[i] = map[i]; + UpdatePadMapping(); } -// called from ---NETPLAY--- thread +// called from ---GUI--- thread and ---NETPLAY--- thread void NetPlayServer::UpdatePadMapping() { - std::map::const_iterator - i = m_players.begin(), - e = m_players.end(); - for (; i!=e; ++i) - { - sf::Packet spac; - spac << (MessageId)NP_MSG_PAD_MAPPING; - spac << i->second.pid; - for (unsigned int pm = 0; pm<4; ++pm) - spac << i->second.pad_map[pm]; - SendToClients(spac); - } - + sf::Packet spac; + spac << (MessageId)NP_MSG_PAD_MAPPING; + for (int i = 0; i < 4; i++) + spac << m_pad_map[i]; + SendToClients(spac); } // called from ---GUI--- thread and ---NETPLAY--- thread @@ -415,23 +330,15 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, sf::SocketTCP& socket) int hi, lo; packet >> map >> hi >> lo; - // check if client's pad indeed maps in game - if (map >= 0 && map < 4) - map = player.pad_map[(unsigned)map]; - else - map = -1; - - // if not, they are hacking, so disconnect them - // this could happen right after a pad map change, but that isn't implemented yet - if (map < 0) + // If the data is not from the correct player, + // then disconnect them. + if (m_pad_map[map] != player.pid) return 1; - - // relay to clients + // Relay to clients sf::Packet spac; spac << (MessageId)NP_MSG_PAD_DATA; - spac << map; // in game mapping - spac << hi << lo; + spac << map << hi << lo; std::lock_guard lks(m_crit.send); SendToClients(spac, player.pid); diff --git a/Source/Core/Core/Src/NetPlayServer.h b/Source/Core/Core/Src/NetPlayServer.h index 4ef601bf06..5fbdb42802 100644 --- a/Source/Core/Core/Src/NetPlayServer.h +++ b/Source/Core/Core/Src/NetPlayServer.h @@ -35,8 +35,8 @@ public: bool StartGame(const std::string &path); bool StopGame(); - bool GetPadMapping(const int pid, int map[]); - bool SetPadMapping(const int pid, const int map[]); + void GetPadMapping(PadMapping map[]); + void SetPadMapping(const PadMapping map[]); void AdjustPadBufferSize(unsigned int size); @@ -50,11 +50,8 @@ private: class Client { public: - Client(); - PlayerId pid; std::string name; - PadMapping pad_map[4]; std::string revision; sf::SocketTCP socket; @@ -77,6 +74,7 @@ private: bool m_update_pings; u32 m_current_game; unsigned int m_target_buffer_size; + PadMapping m_pad_map[4]; std::map m_players; diff --git a/Source/Core/DolphinWX/Src/NetWindow.cpp b/Source/Core/DolphinWX/Src/NetWindow.cpp index 7f1b7c6866..c01b3b788e 100644 --- a/Source/Core/DolphinWX/Src/NetWindow.cpp +++ b/Source/Core/DolphinWX/Src/NetWindow.cpp @@ -559,23 +559,13 @@ void NetPlayDiag::OnChangeGame(wxCommandEvent&) void NetPlayDiag::OnConfigPads(wxCommandEvent&) { - int mapping[4]; - - // get selected player id - int pid = m_player_lbox->GetSelection(); - if (pid < 0) - return; - pid = m_playerids.at(pid); - - if (false == netplay_server->GetPadMapping(pid, mapping)) - return; - - PadMapDiag pmd(this, mapping); + PadMapping mapping[4]; + std::vector player_list; + netplay_server->GetPadMapping(mapping); + netplay_client->GetPlayers(player_list); + PadMapDiag pmd(this, mapping, player_list); pmd.ShowModal(); - - if (false == netplay_server->SetPadMapping(pid, mapping)) - PanicAlertT("Could not set pads. The player left or the game is currently running!\n" - "(setting pads while the game is running is not yet supported)"); + netplay_server->SetPadMapping(mapping); } ChangeGameDiag::ChangeGameDiag(wxWindow* const parent, const CGameListCtrl* const game_list, wxString& game_name) @@ -605,45 +595,39 @@ void ChangeGameDiag::OnPick(wxCommandEvent& event) EndModal(wxID_OK); } -PadMapDiag::PadMapDiag(wxWindow* const parent, int map[]) +PadMapDiag::PadMapDiag(wxWindow* const parent, PadMapping map[], std::vector& player_list) : wxDialog(parent, wxID_ANY, _("Configure Pads"), wxDefaultPosition, wxDefaultSize) , m_mapping(map) + , m_player_list(player_list) { wxBoxSizer* const h_szr = new wxBoxSizer(wxHORIZONTAL); - h_szr->AddSpacer(20); - - // labels - wxBoxSizer* const label_szr = new wxBoxSizer(wxVERTICAL); - label_szr->Add(new wxStaticText(this, wxID_ANY, _("Local")), 0, wxALIGN_TOP); - label_szr->AddStretchSpacer(1); - label_szr->Add(new wxStaticText(this, wxID_ANY, _("In-Game")), 0, wxALIGN_BOTTOM); - - h_szr->Add(label_szr, 1, wxTOP | wxEXPAND, 20); - - // set up choices - wxString pad_names[5]; - pad_names[0] = _("None"); - for (unsigned int i=1; i<5; ++i) - pad_names[i] = wxString(_("Pad ")) + (wxChar)(wxT('0')+i); + wxArrayString player_names; + player_names.Add(_("None")); + for (unsigned int i = 0; i < m_player_list.size(); i++) + player_names.Add(m_player_list[i]->name); for (unsigned int i=0; i<4; ++i) { - wxChoice* const pad_cbox = m_map_cbox[i] - = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 5, pad_names); - pad_cbox->Select(m_mapping[i] + 1); - - pad_cbox->Bind(wxEVT_COMMAND_CHOICE_SELECTED, &PadMapDiag::OnAdjust, this); - wxBoxSizer* const v_szr = new wxBoxSizer(wxVERTICAL); - v_szr->Add(new wxStaticText(this,wxID_ANY, pad_names[i + 1]), 1, wxALIGN_CENTER_HORIZONTAL); - v_szr->Add(pad_cbox, 1); + v_szr->Add(new wxStaticText(this, wxID_ANY, (wxString(_("Pad ")) + (wxChar)(wxT('0')+i))), + 1, wxALIGN_CENTER_HORIZONTAL); + + m_map_cbox[i] = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, player_names); + m_map_cbox[i]->Bind(wxEVT_COMMAND_CHOICE_SELECTED, &PadMapDiag::OnAdjust, this); + if (m_mapping[i] == -1) + m_map_cbox[i]->Select(0); + else + for (unsigned int j = 0; j < m_player_list.size(); j++) + if (m_mapping[i] == m_player_list[j]->pid) + m_map_cbox[i]->Select(j + 1); + + v_szr->Add(m_map_cbox[i], 1); h_szr->Add(v_szr, 1, wxTOP | wxEXPAND, 20); + h_szr->AddSpacer(10); } - h_szr->AddSpacer(20); - wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); main_szr->Add(h_szr); main_szr->AddSpacer(5); @@ -656,8 +640,14 @@ PadMapDiag::PadMapDiag(wxWindow* const parent, int map[]) void PadMapDiag::OnAdjust(wxCommandEvent& event) { (void)event; - for (unsigned int i=0; i<4; ++i) - m_mapping[i] = m_map_cbox[i]->GetSelection() - 1; + for (unsigned int i = 0; i < 4; i++) + { + int player_idx = m_map_cbox[i]->GetSelection(); + if (player_idx > 0) + m_mapping[i] = m_player_list[player_idx - 1]->pid; + else + m_mapping[i] = -1; + } } void NetPlay::StopGame() diff --git a/Source/Core/DolphinWX/Src/NetWindow.h b/Source/Core/DolphinWX/Src/NetWindow.h index 75f9964e9d..3f8502a6ee 100644 --- a/Source/Core/DolphinWX/Src/NetWindow.h +++ b/Source/Core/DolphinWX/Src/NetWindow.h @@ -124,13 +124,14 @@ private: class PadMapDiag : public wxDialog { public: - PadMapDiag(wxWindow* const parent, int map[]); + PadMapDiag(wxWindow* const parent, PadMapping map[], std::vector& player_list); private: void OnAdjust(wxCommandEvent& event); wxChoice* m_map_cbox[4]; - int* const m_mapping; + PadMapping* const m_mapping; + std::vector& m_player_list; }; namespace NetPlay