diff --git a/Source/Core/Core/Src/Core.h b/Source/Core/Core/Src/Core.h index b6c13aff35..25cb7dfe41 100644 --- a/Source/Core/Core/Src/Core.h +++ b/Source/Core/Core/Src/Core.h @@ -59,6 +59,8 @@ namespace Core // Get core parameters kill use SConfig instead extern SCoreStartupParameter g_CoreStartupParameter; + void Callback_WiimoteInterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size); + void* GetWindowHandle(); #if defined HAVE_X11 && HAVE_X11 void* GetXWindow(); diff --git a/Source/Core/DolphinWX/Src/NetPlay.cpp b/Source/Core/DolphinWX/Src/NetPlay.cpp index e6700e2e4a..e3e6df601f 100644 --- a/Source/Core/DolphinWX/Src/NetPlay.cpp +++ b/Source/Core/DolphinWX/Src/NetPlay.cpp @@ -27,7 +27,7 @@ #include "HW/EXI_DeviceIPL.h" // to start/stop game #include "Frame.h" -// for OSD msgs +// for wiimote/ OSD messages #include "Core.h" Common::CriticalSection crit_netplay_ptr; @@ -44,17 +44,6 @@ THREAD_RETURN NetPlayThreadFunc(void* arg) return 0; } -//CritLocker::CritLocker(Common::CriticalSection& crit) -// : m_crit(crit) -//{ -// m_crit.Enter(); -//} -// -//CritLocker::~CritLocker() -//{ -// m_crit.Leave(); -//} - // called from ---GUI--- thread NetPlay::NetPlay() : m_is_running(false), m_do_loop(true) @@ -80,6 +69,10 @@ NetPlay::~NetPlay() { CritLocker crit(crit_netplay_ptr); ::netplay_ptr = NULL; + + // not perfect + if (m_is_running) + StopGame(); } NetPlay::Player::Player() @@ -145,6 +138,9 @@ void NetPlay::ClearBuffers() { while (m_pad_buffer[i].size()) m_pad_buffer[i].pop(); + while (m_wiimote_buffer[i].size()) + m_wiimote_buffer[i].pop(); + m_wiimote_input[i].clear(); } } @@ -212,46 +208,63 @@ bool NetPlay::GetNetPads(const u8 pad_nb, const SPADStatus* const pad_status, Ne // called from ---CPU--- thread void NetPlay::WiimoteInput(int _number, u16 _channelID, const void* _pData, u32 _Size) { - //m_crit.players.Enter(); // lock 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 + 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) - //{ - // //NetPad np(pad_status); + // does this local pad map in game? + if (in_game_num < 4) + { + m_crit.buffer.Enter(); + + 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; - // m_crit.buffer.Enter(); // lock buffer - // // adjust the buffer either up or down - // //while (m_pad_buffer[in_game_num].size() <= m_target_buffer_size) - // { - // // add to buffer - // //m_wiimote_buffer[in_game_num].push(np); - - // // send - // //SendPadState(pad_nb, np); - // } - // m_crit.buffer.Leave(); - //} - - //// get pad from pad buffer and send to game - //GetBufferedPad(pad_nb, netvalues); + m_crit.buffer.Leave(); + } + m_crit.players.Leave(); } // called from ---CPU--- thread void NetPlay::WiimoteUpdate(int _number) { - // temporary - if (_number) + m_crit.players.Enter(); // lock 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_crit.buffer.Enter(); + m_wiimote_buffer[in_game_num].push(m_wiimote_input[_number]); + + // TODO: send it + + m_wiimote_input[_number].clear(); + m_crit.buffer.Leave(); + } + + m_crit.players.Leave(); + + m_crit.buffer.Enter(); + + if (0 == m_wiimote_buffer[_number].size()) + { + //PanicAlert("PANIC"); return; + } - m_crit.buffer.Enter(); // lock buffer - ++m_wiimote_update_frame; + NetWiimote& nw = m_wiimote_buffer[_number].front(); + + 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); + + m_wiimote_buffer[_number].pop(); m_crit.buffer.Leave(); - - // TODO: prolly do some wiimote input here } // called from ---GUI--- thread @@ -274,6 +287,14 @@ bool NetPlay::StartGame(const std::string &path) ::main_frame->BootGame(path); //BootManager::BootCore(path); + // TODO: i dont know if i like this here + ClearBuffers(); + // temporary + NetWiimote nw; + for (unsigned int i = 0; i<4; ++i) + for (unsigned int f = 0; f<2; ++f) + m_wiimote_buffer[i].push(nw); + return true; } @@ -353,20 +374,21 @@ u8 CSIDevice_GCController::NetPlay_GetPadNum(u8 numPAD) // wiimote update / used for frame counting void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int _number) { - CritLocker crit(::crit_netplay_ptr); + //CritLocker crit(::crit_netplay_ptr); - return; + //if (::netplay_ptr) + // ::netplay_ptr->WiimoteUpdate(_number); } // called from ---CPU--- thread // int CWII_IPC_HLE_WiiMote::NetPlay_GetWiimoteNum(int _number) { - CritLocker crit(::crit_netplay_ptr); + //CritLocker crit(::crit_netplay_ptr); - if (::netplay_ptr) - return ::netplay_ptr->GetPadNum(_number); // just using gcpad mapping for now - else + //if (::netplay_ptr) + // return ::netplay_ptr->GetPadNum(_number); // just using gcpad mapping for now + //else return _number; } @@ -377,18 +399,19 @@ bool CWII_IPC_HLE_WiiMote::NetPlay_WiimoteInput(int _number, u16 _channelID, con CritLocker crit(::crit_netplay_ptr); if (::netplay_ptr) - { - if (_Size >= RPT_SIZE_HACK) - { - _Size -= RPT_SIZE_HACK; - return false; - } - else - { - ::netplay_ptr->WiimoteInput(_number, _channelID, _pData, _Size); + //{ + // if (_Size >= RPT_SIZE_HACK) + // { + // _Size -= RPT_SIZE_HACK; + // return false; + // } + // else + // { + // ::netplay_ptr->WiimoteInput(_number, _channelID, _pData, _Size); + // // don't use this packet return true; - } - } + // } + //} else return false; } diff --git a/Source/Core/DolphinWX/Src/NetPlay.h b/Source/Core/DolphinWX/Src/NetPlay.h index 1e7ac3f501..0da13d92b0 100644 --- a/Source/Core/DolphinWX/Src/NetPlay.h +++ b/Source/Core/DolphinWX/Src/NetPlay.h @@ -32,16 +32,13 @@ public: u32 nLo; }; -class NetWiimote +struct Rpt : public std::vector { -public: - NetWiimote& operator=(const NetWiimote&); - NetWiimote(const u32 _size) : size(_size), data(new u8[size]) {} - - const u32 size; - u8* const data; + u16 channel; }; +typedef std::vector NetWiimote; + #define NETPLAY_VERSION "Dolphin NetPlay 2.2" #ifdef _M_X64 @@ -124,7 +121,7 @@ public: void WiimoteUpdate(int _number); bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues); virtual bool ChangeGame(const std::string& game) = 0; - virtual void GetPlayerList(std::string& list) = 0; + virtual void GetPlayerList(std::string& list, std::vector& pid_list) = 0; virtual void SendChatMessage(const std::string& msg) = 0; virtual bool StartGame(const std::string &path); @@ -161,11 +158,10 @@ protected: std::string revision; }; - //LockingQueue m_pad_buffer[4]; - std::queue m_pad_buffer[4]; - std::map m_wiimote_buffer[4]; + std::queue m_pad_buffer[4]; + std::queue m_wiimote_buffer[4]; - FrameNum m_wiimote_update_frame; + NetWiimote m_wiimote_input[4]; NetPlayDiag* m_dialog; sf::SocketTCP m_socket; @@ -197,7 +193,7 @@ public: NetPlayServer(const u16 port, const std::string& name, NetPlayDiag* const npd = NULL, const std::string& game = ""); ~NetPlayServer(); - void GetPlayerList(std::string& list); + void GetPlayerList(std::string& list, std::vector& pid_list); // Send and receive pads values //bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues); @@ -207,6 +203,9 @@ public: bool StartGame(const std::string &path); bool StopGame(); + bool GetPadMapping(const int pid, int map[]); + bool SetPadMapping(const int pid, const int map[]); + u64 CalculateMinimumBufferTime(); void AdjustPadBufferSize(unsigned int size); @@ -226,6 +225,7 @@ private: unsigned int OnConnect(sf::SocketTCP& socket); unsigned int OnDisconnect(sf::SocketTCP& socket); unsigned int OnData(sf::Packet& packet, sf::SocketTCP& socket); + void UpdatePadMapping(); std::map m_players; @@ -242,7 +242,7 @@ public: NetPlayClient(const std::string& address, const u16 port, const std::string& name, NetPlayDiag* const npd = NULL); ~NetPlayClient(); - void GetPlayerList(std::string& list); + void GetPlayerList(std::string& list, std::vector& pid_list); // Send and receive pads values //bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues); diff --git a/Source/Core/DolphinWX/Src/NetPlayClient.cpp b/Source/Core/DolphinWX/Src/NetPlayClient.cpp index 13a42f8bb0..b9d54c9065 100644 --- a/Source/Core/DolphinWX/Src/NetPlayClient.cpp +++ b/Source/Core/DolphinWX/Src/NetPlayClient.cpp @@ -19,7 +19,7 @@ NetPlayClient::NetPlayClient(const std::string& address, const u16 port, const s is_connected = false; // why is false successful? documentation says true is - if (0 == m_socket.Connect(port, address)) + if (0 == m_socket.Connect(port, address, 5)) { // send connect message sf::Packet spac; @@ -193,7 +193,9 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet) case NP_MSG_START_GAME : { + m_crit.buffer.Enter(); // lock buffer packet >> m_on_game; + m_crit.buffer.Leave(); wxCommandEvent evt(wxEVT_THREAD, NP_GUI_EVT_START_GAME); m_dialog->GetEventHandler()->AddPendingEvent(evt); @@ -209,7 +211,7 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet) case NP_MSG_DISABLE_GAME : { - PanicAlert("Other client disconnected while game is running!! NetPlay is disabled. You must manually stop the game."); + PanicAlert("Other client disconnected while game is running!! NetPlay is disabled. You manually stop the game."); CritLocker game_lock(m_crit.game); // lock game state m_is_running = false; NetPlay_Disable(); @@ -257,7 +259,7 @@ void NetPlayClient::Entry() default : m_is_running = false; NetPlay_Disable(); - AppendChatGUI("< LOST CONNECION TO SERVER >"); + AppendChatGUI("< LOST CONNECTION TO SERVER >"); PanicAlert("Lost connection to server!"); m_do_loop = false; break; @@ -271,7 +273,7 @@ void NetPlayClient::Entry() } // called from ---GUI--- thread -void NetPlayClient::GetPlayerList(std::string &list) +void NetPlayClient::GetPlayerList(std::string& list, std::vector& pid_list) { CritLocker player_lock(m_crit.players); // lock players @@ -281,7 +283,10 @@ void NetPlayClient::GetPlayerList(std::string &list) i = m_players.begin(), e = m_players.end(); for ( ; i!=e; ++i) + { ss << i->second.ToString() << '\n'; + pid_list.push_back(i->second.pid); + } list = ss.str(); } @@ -294,9 +299,9 @@ void NetPlayClient::SendChatMessage(const std::string& msg) spac << (MessageId)NP_MSG_CHAT_MESSAGE; spac << msg; - m_crit.send.Enter(); // lock send + CritLocker player_lock(m_crit.players); // lock players + CritLocker send_lock(m_crit.send); // lock send m_socket.Send(spac); - m_crit.send.Leave(); } // called from ---CPU--- thread @@ -308,9 +313,8 @@ void NetPlayClient::SendPadState(const PadMapping local_nb, const NetPad& np) spac << local_nb; // local pad num spac << np.nHi << np.nLo; - m_crit.send.Enter(); // lock send + CritLocker send_lock(m_crit.send); // lock send m_socket.Send(spac); - m_crit.send.Leave(); } // called from ---GUI--- thread @@ -321,18 +325,15 @@ bool NetPlayClient::StartGame(const std::string &path) if (false == NetPlay::StartGame(path)) return false; - // TODO: i dont like this here - ClearBuffers(); - m_crit.buffer.Leave(); - // tell server i started the game sf::Packet spac; spac << (MessageId)NP_MSG_START_GAME; spac << m_on_game; - m_crit.send.Enter(); // lock send + m_crit.buffer.Leave(); + + CritLocker send_lock(m_crit.send); // lock send m_socket.Send(spac); - m_crit.send.Leave(); return true; } diff --git a/Source/Core/DolphinWX/Src/NetPlayServer.cpp b/Source/Core/DolphinWX/Src/NetPlayServer.cpp index c827c06e7c..e35a8d90d7 100644 --- a/Source/Core/DolphinWX/Src/NetPlayServer.cpp +++ b/Source/Core/DolphinWX/Src/NetPlayServer.cpp @@ -63,7 +63,7 @@ void NetPlayServer::Entry() spac << (MessageId)NP_MSG_PING; spac << m_ping_key; - CritLocker player_lock(m_crit.players); + //CritLocker player_lock(m_crit.players); CritLocker send_lock(m_crit.send); m_ping_timer.Start(); SendToClients(spac); @@ -218,14 +218,6 @@ unsigned int NetPlayServer::OnConnect(sf::SocketTCP& socket) spac << player.pid; socket.Send(spac); - // send user their pad mapping - spac.Clear(); - spac << (MessageId)NP_MSG_PAD_MAPPING; - spac << player.pid; - for (unsigned int pm = 0; pm<4; ++pm) - spac << player.pad_map[pm]; - socket.Send(spac); - // send new client the selected game spac.Clear(); spac << (MessageId)NP_MSG_CHANGE_GAME; @@ -239,13 +231,6 @@ unsigned int NetPlayServer::OnConnect(sf::SocketTCP& socket) spac << (MessageId)NP_MSG_PLAYER_JOIN; spac << i->second.pid << i->second.name << i->second.revision; socket.Send(spac); - - spac.Clear(); - spac << (MessageId)NP_MSG_PAD_MAPPING; - spac << i->second.pid; - for (unsigned int pm = 0; pm<4; ++pm) - spac << i->second.pad_map[pm]; - socket.Send(spac); } // LEAVE @@ -254,6 +239,9 @@ unsigned int NetPlayServer::OnConnect(sf::SocketTCP& socket) // add client to the player list m_crit.players.Enter(); // lock players m_players[socket] = player; + m_crit.send.Enter(); // lock send + UpdatePadMapping(); // sync pad mappings with everyone + m_crit.send.Leave(); m_crit.players.Leave(); // add client to selector/ used for receiving @@ -277,9 +265,8 @@ unsigned int NetPlayServer::OnDisconnect(sf::SocketTCP& socket) sf::Packet spac; spac << (MessageId)NP_MSG_DISABLE_GAME; // this thread doesnt need players lock - m_crit.send.Enter(); // lock send + CritLocker send_lock(m_crit.send); // lock send SendToClients(spac); - m_crit.send.Leave(); } sf::Packet spac; @@ -288,20 +275,100 @@ unsigned int NetPlayServer::OnDisconnect(sf::SocketTCP& socket) m_selector.Remove(socket); - m_crit.players.Enter(); // lock players + CritLocker player_lock(m_crit.players); // lock players m_players.erase(m_players.find(socket)); - m_crit.players.Leave(); // alert other players of disconnect - m_crit.send.Enter(); // lock send + CritLocker send_lock(m_crit.send); // lock send SendToClients(spac); - m_crit.send.Leave(); UpdateGUI(); return 0; } +// called from ---GUI--- thread +bool NetPlayServer::GetPadMapping(const int pid, int map[]) +{ + CritLocker player_lock(m_crit.players); // lock 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; +} + +// called from ---GUI--- thread +bool NetPlayServer::SetPadMapping(const int pid, const int map[]) +{ + CritLocker game_lock(m_crit.game); // lock game + if (m_is_running) + return false; + + CritLocker player_lock(m_crit.players); // lock 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; + } + + CritLocker send_lock(m_crit.send); // lock send + UpdatePadMapping(); // sync pad mappings with everyone + + UpdateGUI(); + + return true; +} + +// called from ---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); + } + +} + // called from ---GUI--- thread and ---NETPLAY--- thread u64 NetPlayServer::CalculateMinimumBufferTime() { @@ -312,7 +379,7 @@ u64 NetPlayServer::CalculateMinimumBufferTime() e = m_players.end(); std::priority_queue pings; for ( ;i!=e; ++i) - pings.push(i->second.ping); + pings.push(i->second.ping/2); unsigned int required_ms = pings.top(); // if there is more than 1 client, buffersize must be >= (2 highest ping times combined) @@ -339,11 +406,9 @@ void NetPlayServer::AdjustPadBufferSize(unsigned int size) spac << (MessageId)NP_MSG_PAD_BUFFER; spac << (u32)m_target_buffer_size; - m_crit.players.Enter(); // lock players - m_crit.send.Enter(); // lock send + CritLocker player_lock(m_crit.players); // lock players + CritLocker send_lock(m_crit.send); // lock send SendToClients(spac); - m_crit.send.Leave(); - m_crit.players.Leave(); } // called from ---NETPLAY--- thread @@ -414,9 +479,8 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, sf::SocketTCP& socket) spac << map; // in game mapping spac << np.nHi << np.nLo; - m_crit.send.Enter(); // lock send + CritLocker send_lock(m_crit.send); // lock send SendToClients(spac, player.pid); - m_crit.send.Leave(); } break; @@ -452,9 +516,9 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, sf::SocketTCP& socket) } // called from ---GUI--- thread -void NetPlayServer::GetPlayerList(std::string &list) +void NetPlayServer::GetPlayerList(std::string& list, std::vector& pid_list) { - CritLocker player_lock(m_crit.players); + CritLocker player_lock(m_crit.players); // lock players std::ostringstream ss; @@ -462,7 +526,10 @@ void NetPlayServer::GetPlayerList(std::string &list) i = m_players.begin(), e = m_players.end(); for ( ; i!=e; ++i) + { ss << i->second.ToString() << " " << i->second.ping << "ms\n"; + pid_list.push_back(i->second.pid); + } list = ss.str(); } @@ -475,9 +542,8 @@ void NetPlayServer::SendChatMessage(const std::string& msg) spac << (PlayerId)0; // server id always 0 spac << msg; - m_crit.send.Enter(); // lock send + CritLocker send_lock(m_crit.send); // lock send SendToClients(spac); - m_crit.send.Leave(); } // called from ---GUI--- thread @@ -492,11 +558,9 @@ bool NetPlayServer::ChangeGame(const std::string &game) spac << (MessageId)NP_MSG_CHANGE_GAME; spac << game; - m_crit.players.Enter(); // lock players - m_crit.send.Enter(); // lock send + CritLocker player_lock(m_crit.players); // lock players + CritLocker send_lock(m_crit.send); // lock send SendToClients(spac); - m_crit.send.Leave(); - m_crit.players.Leave(); return true; } @@ -510,9 +574,8 @@ void NetPlayServer::SendPadState(const PadMapping local_nb, const NetPad& np) spac << m_local_player->pad_map[local_nb]; // in-game pad num spac << np.nHi << np.nLo; - m_crit.send.Enter(); // lock send + CritLocker send_lock(m_crit.send); // lock send SendToClients(spac); - m_crit.send.Leave(); } // called from ---GUI--- thread @@ -525,7 +588,6 @@ bool NetPlayServer::StartGame(const std::string &path) // TODO: i dont like this here m_on_game = Common::Timer::GetTimeMs(); - ClearBuffers(); m_crit.buffer.Leave(); // no change, just update with clients @@ -536,11 +598,9 @@ bool NetPlayServer::StartGame(const std::string &path) spac << (MessageId)NP_MSG_START_GAME; spac << m_on_game; - m_crit.players.Enter(); // lock players - m_crit.send.Enter(); // lock send + CritLocker player_lock(m_crit.players); // lock players + CritLocker send_lock(m_crit.send); // lock send SendToClients(spac); - m_crit.send.Leave(); - m_crit.players.Leave(); return true; } @@ -556,11 +616,9 @@ bool NetPlayServer::StopGame() sf::Packet spac; spac << (MessageId)NP_MSG_STOP_GAME; - m_crit.players.Enter(); // lock players - m_crit.send.Enter(); // lock send + CritLocker player_lock(m_crit.players); // lock players + CritLocker send_lock(m_crit.send); // lock send SendToClients(spac); - m_crit.players.Leave(); - m_crit.send.Leave(); return true; } diff --git a/Source/Core/DolphinWX/Src/NetWindow.cpp b/Source/Core/DolphinWX/Src/NetWindow.cpp index 687c92eaee..49e1ecf9f8 100644 --- a/Source/Core/DolphinWX/Src/NetWindow.cpp +++ b/Source/Core/DolphinWX/Src/NetWindow.cpp @@ -15,6 +15,9 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ +#include +#include + #include "NetPlay.h" #include "NetWindow.h" @@ -34,13 +37,18 @@ NetPlaySetupDiag::NetPlaySetupDiag(wxWindow* const parent, const CGameListCtrl* : wxFrame(parent, wxID_ANY, wxT(NETPLAY_TITLEBAR), wxDefaultPosition, wxDefaultSize) , m_game_list(game_list) { - //PanicAlert("ALERT: NetPlay is not 100%% functional !!!!"); + IniFile inifile; + inifile.Load(std::string(File::GetUserPath(D_CONFIG_IDX)) + "Dolphin.ini"); + IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); wxPanel* const panel = new wxPanel(this); // top row wxStaticText* const nick_lbl = new wxStaticText(panel, wxID_ANY, wxT("Nickname :"), wxDefaultPosition, wxDefaultSize); - m_nickname_text = new wxTextCtrl(panel, wxID_ANY, wxT("Player")); + + std::string nickname; + netplay_section.Get("Nickname", &nickname, "Player"); + m_nickname_text = new wxTextCtrl(panel, wxID_ANY, wxString::FromAscii(nickname.c_str())); wxBoxSizer* const nick_szr = new wxBoxSizer(wxHORIZONTAL); nick_szr->Add(nick_lbl, 0, wxCENTER); @@ -58,9 +66,17 @@ NetPlaySetupDiag::NetPlaySetupDiag(wxWindow* const parent, const CGameListCtrl* // connect tab { wxStaticText* const ip_lbl = new wxStaticText(connect_tab, wxID_ANY, wxT("Address :"), wxDefaultPosition, wxDefaultSize); - m_connect_ip_text = new wxTextCtrl(connect_tab, wxID_ANY, wxT("localhost")); + + std::string address; + netplay_section.Get("Address", &address, "localhost"); + m_connect_ip_text = new wxTextCtrl(connect_tab, wxID_ANY, wxString::FromAscii(address.c_str())); + wxStaticText* const port_lbl = new wxStaticText(connect_tab, wxID_ANY, wxT("Port :"), wxDefaultPosition, wxDefaultSize); - m_connect_port_text = new wxTextCtrl(connect_tab, wxID_ANY, wxT("2626")); + + // string? w/e + std::string port; + netplay_section.Get("ConnectPort", &port, "2626"); + m_connect_port_text = new wxTextCtrl(connect_tab, wxID_ANY, wxString::FromAscii(port.c_str())); wxButton* const connect_btn = new wxButton(connect_tab, wxID_ANY, wxT("Connect")); _connect_macro_(connect_btn, NetPlaySetupDiag::OnJoin, wxEVT_COMMAND_BUTTON_CLICKED, this); @@ -96,7 +112,11 @@ NetPlaySetupDiag::NetPlaySetupDiag(wxWindow* const parent, const CGameListCtrl* // host tab { wxStaticText* const port_lbl = new wxStaticText(host_tab, wxID_ANY, wxT("Port :"), wxDefaultPosition, wxDefaultSize); - m_host_port_text = new wxTextCtrl(host_tab, wxID_ANY, wxT("2626")); + + // string? w/e + std::string port; + netplay_section.Get("HostPort", &port, "2626"); + m_host_port_text = new wxTextCtrl(host_tab, wxID_ANY, wxString::FromAscii(port.c_str())); wxButton* const host_btn = new wxButton(host_tab, wxID_ANY, wxT("Host")); _connect_macro_(host_btn, NetPlaySetupDiag::OnHost, wxEVT_COMMAND_BUTTON_CLICKED, this); @@ -143,6 +163,21 @@ NetPlaySetupDiag::NetPlaySetupDiag(wxWindow* const parent, const CGameListCtrl* Show(); } +NetPlaySetupDiag::~NetPlaySetupDiag() +{ + IniFile inifile; + const std::string dolphin_ini = std::string(File::GetUserPath(D_CONFIG_IDX)) + "Dolphin.ini"; + inifile.Load(dolphin_ini); + IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay"); + + netplay_section.Set("Nickname", m_nickname_text->GetValue().mb_str()); + netplay_section.Set("Address", m_connect_ip_text->GetValue().mb_str()); + netplay_section.Set("ConnectPort", m_connect_port_text->GetValue().mb_str()); + netplay_section.Set("HostPort", m_host_port_text->GetValue().mb_str()); + + inifile.Save(dolphin_ini); +} + void NetPlaySetupDiag::OnHost(wxCommandEvent& event) { // warning removal @@ -266,8 +301,8 @@ NetPlayDiag::NetPlayDiag(wxWindow* const parent, const CGameListCtrl* const game // player list if (is_hosting) { - wxButton* const player_config_btn = new wxButton(panel, wxID_ANY, wxT("Configure Pads [not implemented]")); - player_config_btn->Disable(); + wxButton* const player_config_btn = new wxButton(panel, wxID_ANY, wxT("Configure Pads")); + _connect_macro_(player_config_btn, NetPlayDiag::OnConfigPads, wxEVT_COMMAND_BUTTON_CLICKED, this); player_szr->Add(player_config_btn, 0, wxEXPAND | wxTOP, 5); } @@ -380,8 +415,8 @@ void NetPlayDiag::OnPadBuffHelp(wxCommandEvent& event) const u64 time = ((NetPlayServer*)::netplay_ptr)->CalculateMinimumBufferTime(); std::ostringstream ss; ss << "< Calculated from pings: required buffer: " - << time * (60/1000) << "(60fps) / " - << time * (50/1000) << "(50fps) >\n"; + << time * (60.0f/1000) << "(60fps) / " + << time * (50.0f/1000) << "(50fps) >\n"; m_chat_text->AppendText(wxString(ss.str().c_str(), *wxConvCurrent)); } @@ -412,14 +447,19 @@ void NetPlayDiag::OnThread(wxCommandEvent& event) event.GetId(); // player list + m_playerids.clear(); std::string tmps; - ::netplay_ptr->GetPlayerList(tmps); + ::netplay_ptr->GetPlayerList(tmps, m_playerids); + + const int selection = m_player_lbox->GetSelection(); m_player_lbox->Clear(); std::istringstream ss(tmps); while (std::getline(ss, tmps)) m_player_lbox->Append(wxString(tmps.c_str(), *wxConvCurrent)); + m_player_lbox->SetSelection(selection); + switch (event.GetId()) { case NP_GUI_EVT_CHANGE_GAME : @@ -472,6 +512,30 @@ void NetPlayDiag::OnChangeGame(wxCommandEvent& event) } } +void NetPlayDiag::OnConfigPads(wxCommandEvent& event) +{ + // warning removal + event.GetId(); + + int mapping[4]; + + // get selected player id + int pid = m_player_lbox->GetSelection(); + if (pid < 0) + return; + pid = m_playerids.at(pid); + + if (false == ((NetPlayServer*)::netplay_ptr)->GetPadMapping(pid, mapping)) + return; + + PadMapDiag* const pmd = new PadMapDiag(this, mapping); + pmd->ShowModal(); + pmd->Destroy(); + + if (false == ((NetPlayServer*)::netplay_ptr)->SetPadMapping(pid, mapping)) + PanicAlert("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)"); +} + ChangeGameDiag::ChangeGameDiag(wxWindow* const parent, const CGameListCtrl* const game_list, wxString& game_name) : wxDialog(parent, wxID_ANY, wxT("Change Game"), wxDefaultPosition, wxDefaultSize) , m_game_name(game_name) @@ -510,3 +574,58 @@ void ChangeGameDiag::OnPick(wxCommandEvent& event) m_game_name = m_game_lbox->GetStringSelection(); Destroy(); } + +PadMapDiag::PadMapDiag(wxWindow* const parent, int map[]) + : wxDialog(parent, wxID_ANY, wxT("Configure Pads"), wxDefaultPosition, wxDefaultSize) + , m_mapping(map) +{ + wxPanel* const panel = new wxPanel(this); + + wxBoxSizer* const h_szr = new wxBoxSizer(wxHORIZONTAL); + + h_szr->AddSpacer(20); + + // labels + wxBoxSizer* const label_szr = new wxBoxSizer(wxVERTICAL); + label_szr->Add(new wxStaticText(panel,wxID_ANY, wxT("Local")), 0, wxALIGN_TOP); + label_szr->AddStretchSpacer(1); + label_szr->Add(new wxStaticText(panel,wxID_ANY, wxT("In-Game")), 0, wxALIGN_BOTTOM); + + h_szr->Add(label_szr, 1, wxTOP | wxBOTTOM | wxEXPAND, 20); + + // set up choices + wxString pad_names[5]; + pad_names[0] = wxT("None"); + for (unsigned int i=1; i<5; ++i) + pad_names[i] = wxString(wxT("Pad ")) + (wxChar)(wxT('0')+i); + + for (unsigned int i=0; i<4; ++i) + { + wxChoice* const pad_cbox = m_map_cbox[i] + = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 5, pad_names); + pad_cbox->Select(m_mapping[i] + 1); + + _connect_macro_(pad_cbox, PadMapDiag::OnAdjust, wxEVT_COMMAND_CHOICE_SELECTED, this); + + wxBoxSizer* const v_szr = new wxBoxSizer(wxVERTICAL); + v_szr->Add(new wxStaticText(panel,wxID_ANY, pad_names[i + 1]), 1, wxALIGN_CENTER_HORIZONTAL); + v_szr->Add(pad_cbox, 1); + + h_szr->Add(v_szr, 1, wxTOP | wxBOTTOM | wxEXPAND, 20); + } + + h_szr->AddSpacer(20); + + panel->SetSizerAndFit(h_szr); + + wxBoxSizer* const dlg_szr = new wxBoxSizer(wxVERTICAL); + dlg_szr->Add(panel, 1, wxEXPAND); + SetSizerAndFit(dlg_szr); +} + +void PadMapDiag::OnAdjust(wxCommandEvent& event) +{ + (void)event; + for (unsigned int i=0; i<4; ++i) + m_mapping[i] = m_map_cbox[i]->GetSelection() - 1; +} diff --git a/Source/Core/DolphinWX/Src/NetWindow.h b/Source/Core/DolphinWX/Src/NetWindow.h index 0d6a9958a2..fb6306a994 100644 --- a/Source/Core/DolphinWX/Src/NetWindow.h +++ b/Source/Core/DolphinWX/Src/NetWindow.h @@ -60,7 +60,7 @@ class NetPlaySetupDiag : public wxFrame { public: NetPlaySetupDiag(wxWindow* const parent, const CGameListCtrl* const game_list); - + ~NetPlaySetupDiag(); private: void OnJoin(wxCommandEvent& event); void OnHost(wxCommandEvent& event); @@ -98,6 +98,7 @@ private: void OnThread(wxCommandEvent& event); void OnChangeGame(wxCommandEvent& event); void OnAdjustBuffer(wxCommandEvent& event); + void OnConfigPads(wxCommandEvent& event); wxListBox* m_player_lbox; wxTextCtrl* m_chat_text; @@ -106,6 +107,8 @@ private: std::string m_selected_game; wxButton* m_game_btn; + std::vector m_playerids; + const CGameListCtrl* const m_game_list; //NetPlay* const m_netplay; }; @@ -124,5 +127,17 @@ private: wxString& m_game_name; }; +class PadMapDiag : public wxDialog +{ +public: + PadMapDiag(wxWindow* const parent, int map[]); + +private: + void OnAdjust(wxCommandEvent& event); + + wxChoice* m_map_cbox[4]; + int* const m_mapping; +}; + #endif // _NETWINDOW_H_ diff --git a/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.cpp b/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.cpp index 3ad2c00e18..35b006a211 100644 --- a/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.cpp +++ b/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.cpp @@ -57,7 +57,7 @@ void ControllerInterface::Init() // // remove all devices/ call library cleanup functions // -void ControllerInterface::DeInit() +void ControllerInterface::DeInit(const bool hacks_no_sdl_quit) { if ( false == m_is_init ) return; @@ -73,6 +73,13 @@ void ControllerInterface::DeInit() (*d)->SetOutputState( *o, 0 ); // update output (*d)->UpdateOutput(); + + // TODO: remove this + // major hacks to prevent gcpad/wiimote new from crashing eachother + if (hacks_no_sdl_quit) + if ((*d)->GetSource() == "SDL") + continue; + //delete device delete *d; } @@ -92,8 +99,9 @@ void ControllerInterface::DeInit() ciface::OSX::DeInit(); #endif #ifdef CIFACE_USE_SDL - // there seems to be some sort of memory leak with SDL, quit isn't freeing everything up - SDL_Quit(); + // TODO: there seems to be some sort of memory leak with SDL, quit isn't freeing everything up + if (false == hacks_no_sdl_quit) + SDL_Quit(); #endif m_is_init = false; diff --git a/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.h b/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.h index 4133b02b5e..0a9a11fd46 100644 --- a/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.h +++ b/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.h @@ -240,7 +240,8 @@ public: void SetHwnd( void* const hwnd ); void Init(); - void DeInit(); + // TODO: remove this hack param + void DeInit(const bool hacks_no_sdl_quit = false); bool IsInit(); void UpdateReference( ControlReference* control ); diff --git a/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.cpp b/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.cpp index 1ccf3f460b..5bed65fd88 100644 --- a/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.cpp +++ b/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.cpp @@ -20,15 +20,21 @@ namespace SDL void Init( std::vector& devices ) { - if ( SDL_Init( SDL_INIT_FLAGS ) >= 0 ) + // just a struct with an int that is set to ZERO by default + struct ZeroedInt{ZeroedInt():value(0){}unsigned int value;}; + // this is used to number the joysticks + // multiple joysticks with the same name shall get unique ids starting at 0 + std::map name_counts; + + if (SDL_Init( SDL_INIT_FLAGS ) >= 0) { // joysticks - for( int i = 0; i < SDL_NumJoysticks(); ++i ) + for(int i = 0; i < SDL_NumJoysticks(); ++i) { - SDL_Joystick* dev = SDL_JoystickOpen( i ); + SDL_Joystick* dev = SDL_JoystickOpen(i); if ( dev ) { - Joystick* js = new Joystick( dev, i ); + Joystick* js = new Joystick(dev, i, name_counts[SDL_JoystickName(i)].value++); // only add if it has some inputs/outputs if ( js->Inputs().size() || js->Outputs().size() ) devices.push_back( js ); @@ -39,8 +45,32 @@ void Init( std::vector& devices ) } } -Joystick::Joystick( SDL_Joystick* const joystick, const unsigned int index ) : m_joystick(joystick), m_index(index) +Joystick::Joystick(SDL_Joystick* const joystick, const int sdl_index, const unsigned int index) + : m_joystick(joystick) + , m_sdl_index(sdl_index) + , m_index(index) { + // really bad HACKS: + // to not use SDL for an XInput device + // too many people on the forums pick the SDL device and ask: + // "why don't my 360 gamepad triggers/rumble work correctly" + #ifdef _WIN32 + // checking the name is probably good (and hacky) enough + // but i'll double check with the num of buttons/axes + if ( + ("Controller (Xbox 360 Wireless Receiver for Windows)" == GetName()) + && (10 == SDL_JoystickNumButtons(joystick)) + && (5 == SDL_JoystickNumAxes(joystick)) + && (1 == SDL_JoystickNumHats(joystick)) + && (0 == SDL_JoystickNumBalls(joystick)) + ) + { + // this device won't be used + return; + } + + #endif + // get buttons for ( int i = 0; i < SDL_JoystickNumButtons( m_joystick ); ++i ) { @@ -210,7 +240,7 @@ bool Joystick::UpdateOutput() std::string Joystick::GetName() const { - return StripSpaces(SDL_JoystickName(m_index)); + return StripSpaces(SDL_JoystickName(m_sdl_index)); } std::string Joystick::GetSource() const diff --git a/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.h b/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.h index 6a9cbe45ed..b8d9d668a2 100644 --- a/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.h +++ b/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.h @@ -135,7 +135,7 @@ protected: void SetOutputState( const ControllerInterface::Device::Output* const output, const ControlState state ); public: - Joystick( SDL_Joystick* const joystick, const unsigned int index ); + Joystick(SDL_Joystick* const joystick, const int sdl_index, const unsigned int index); ~Joystick(); std::string GetName() const; @@ -144,6 +144,7 @@ public: private: SDL_Joystick* const m_joystick; + const int m_sdl_index; const unsigned int m_index; #ifdef USE_SDL_HAPTIC diff --git a/Source/Plugins/InputPluginCommon/Src/ConfigDiag.cpp b/Source/Plugins/InputPluginCommon/Src/ConfigDiag.cpp index 3413a334e3..629f504196 100644 --- a/Source/Plugins/InputPluginCommon/Src/ConfigDiag.cpp +++ b/Source/Plugins/InputPluginCommon/Src/ConfigDiag.cpp @@ -373,6 +373,8 @@ void GamepadPage::ClearControl( wxCommandEvent& event ) btn->control_reference->device_qualifier = controller->default_device; g_plugin->controls_crit.Enter(); + if (btn->control_reference->is_input) + ((ControllerInterface::InputReference*)btn->control_reference)->mode = 0; controller->UpdateReferences( g_plugin->controller_interface ); g_plugin->controls_crit.Leave(); @@ -618,22 +620,33 @@ ControlGroupBox::ControlGroupBox( ControllerEmu::ControlGroup* const group, wxWi static_bitmap = NULL; wxFont m_SmallFont(7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL); - for ( unsigned int c = 0; c < group->controls.size(); ++c ) + std::vector::iterator + ci = group->controls.begin(), + ce = group->controls.end(); + for ( ; ci != ce; ++ci) { - wxStaticText* const label = new wxStaticText( parent, -1, wxString::FromAscii( group->controls[c]->name )/*.append(wxT(" :"))*/ ); + wxStaticText* const label = new wxStaticText(parent, -1, wxString::FromAscii((*ci)->name)/*.append(wxT(" :"))*/ ); - ControlButton* const control_button = new ControlButton( parent, group->controls[c]->control_ref, 80 ); + ControlButton* const control_button = new ControlButton(parent, (*ci)->control_ref, 80); control_button->SetFont(m_SmallFont); - controls.push_back( control_button ); - control_buttons.push_back( control_button ); + controls.push_back(control_button); + control_buttons.push_back(control_button); - control_button->SetToolTip(wxT("Right-click for more options.\nMiddle-click to clear.")); + if ((*ci)->control_ref->is_input) + { + control_button->SetToolTip(wxT("Left-click to detect input.\nMiddle-click to clear.\nRight-click for more options.")); + _connect_macro_( control_button, GamepadPage::DetectControl, wxEVT_COMMAND_BUTTON_CLICKED, eventsink ); + } + else + { + control_button->SetToolTip(wxT("Left/Right-click for more options.\nMiddle-click to clear.")); + _connect_macro_( control_button, GamepadPage::ConfigControl, wxEVT_COMMAND_BUTTON_CLICKED, eventsink ); + } - _connect_macro_( control_button, GamepadPage::DetectControl, wxEVT_COMMAND_BUTTON_CLICKED, eventsink ); - _connect_macro_( control_button, GamepadPage::ConfigControl, wxEVT_RIGHT_UP, eventsink ); _connect_macro_( control_button, GamepadPage::ClearControl, wxEVT_MIDDLE_DOWN, eventsink ); + _connect_macro_( control_button, GamepadPage::ConfigControl, wxEVT_RIGHT_UP, eventsink ); wxBoxSizer* const control_sizer = new wxBoxSizer( wxHORIZONTAL ); control_sizer->AddStretchSpacer( 1 ); diff --git a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteNew.cpp b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteNew.cpp index dc42569ef9..02f2b51610 100644 --- a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteNew.cpp +++ b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteNew.cpp @@ -99,7 +99,9 @@ void DeInitPlugin() delete *i; g_plugin.controllers.clear(); - g_plugin.controller_interface.DeInit(); + // true parameter to make SDL not quit in the wiimote plugin, + // the old wiimote plugin uses this hack as well, to prevent crash on stop + g_plugin.controller_interface.DeInit(true); } } @@ -276,7 +278,7 @@ void DllConfig(HWND _hParent) frame->Destroy(); // / - if ( false == was_init ) // hack for showing dialog when game isnt running + if ( false == was_init ) DeInitPlugin(); #endif }