From a6d6d2732847720119410c28ba4e0f4f863a2c05 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Sat, 1 May 2010 19:10:35 +0000 Subject: [PATCH] NetPlay: completely redone - should be somewhat usable when using Single Core and DSP LLE Plugin. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5425 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Common/Src/Common.h | 1 + Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp | 7 +- Source/Core/Core/Src/HW/EXI_DeviceIPL.h | 2 + Source/Core/DolphinWX/DolphinWX.vcproj | 182 +--- Source/Core/DolphinWX/Src/FrameTools.cpp | 5 +- Source/Core/DolphinWX/Src/LockingQueue.h | 47 ++ Source/Core/DolphinWX/Src/NetEvent.cpp | 289 ------- Source/Core/DolphinWX/Src/NetFunctions.cpp | 588 ------------- Source/Core/DolphinWX/Src/NetPlay.cpp | 912 +++++++++++++++++++++ Source/Core/DolphinWX/Src/NetPlay.h | 190 +++++ Source/Core/DolphinWX/Src/NetSockets.cpp | 607 -------------- Source/Core/DolphinWX/Src/NetSockets.h | 128 --- Source/Core/DolphinWX/Src/NetStructs.h | 26 - Source/Core/DolphinWX/Src/NetWindow.cpp | 818 +++++++----------- Source/Core/DolphinWX/Src/NetWindow.h | 235 ++---- Source/Core/DolphinWX/Src/SConscript | 4 +- 16 files changed, 1544 insertions(+), 2497 deletions(-) create mode 100644 Source/Core/DolphinWX/Src/LockingQueue.h delete mode 100644 Source/Core/DolphinWX/Src/NetEvent.cpp delete mode 100644 Source/Core/DolphinWX/Src/NetFunctions.cpp create mode 100644 Source/Core/DolphinWX/Src/NetPlay.cpp create mode 100644 Source/Core/DolphinWX/Src/NetPlay.h delete mode 100644 Source/Core/DolphinWX/Src/NetSockets.cpp delete mode 100644 Source/Core/DolphinWX/Src/NetSockets.h delete mode 100644 Source/Core/DolphinWX/Src/NetStructs.h diff --git a/Source/Core/Common/Src/Common.h b/Source/Core/Common/Src/Common.h index b254076165..12b36fbb3f 100644 --- a/Source/Core/Common/Src/Common.h +++ b/Source/Core/Common/Src/Common.h @@ -86,6 +86,7 @@ #define HAVE_OPENAL 1 #define HAVE_ALSA 0 #define HAVE_PORTAUDIO 0 + #define HAVE_SFML 1 // it is VERY DANGEROUS to mix _SECURE_SCL=0 and _SECURE_SCL=1 compiled libraries. // You will get bizarre crash bugs whenever you use STL. diff --git a/Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp b/Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp index cdbb59500b..7ba24d00ce 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp +++ b/Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp @@ -415,7 +415,12 @@ u32 CEXIIPL::GetGCTime() u64 ltime = Common::Timer::GetTimeSinceJan1970(); return ((u32)ltime - cJanuary2000 - Bias); #else - u64 ltime = Common::Timer::GetLocalTimeSinceJan1970(); + + // hack in some netplay stuff + u64 ltime = GetNetGCTime(); + if (0 == ltime) + ltime = Common::Timer::GetLocalTimeSinceJan1970(); + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii) return ((u32)ltime - cJanuary2000 - cWiiBias/* + 32434790*/); else diff --git a/Source/Core/Core/Src/HW/EXI_DeviceIPL.h b/Source/Core/Core/Src/HW/EXI_DeviceIPL.h index edabe44598..b2e3dcc54f 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceIPL.h +++ b/Source/Core/Core/Src/HW/EXI_DeviceIPL.h @@ -32,6 +32,8 @@ public: void DoState(PointerWrap &p); static u32 GetGCTime(); + static u32 GetNetGCTime(); + static void Descrambler(u8* data, u32 size); private: diff --git a/Source/Core/DolphinWX/DolphinWX.vcproj b/Source/Core/DolphinWX/DolphinWX.vcproj index 51b141d23c..a8568318aa 100644 --- a/Source/Core/DolphinWX/DolphinWX.vcproj +++ b/Source/Core/DolphinWX/DolphinWX.vcproj @@ -923,185 +923,15 @@ Name="NetPlay" > - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + Append(IDM_CHEATS, _T("Action &Replay Manager")); #if defined(HAVE_SFML) && HAVE_SFML - // Disabled for now, netplay doesn't quite work currently - // toolsMenu->Append(IDM_NETPLAY, _T("Start &NetPlay")); + toolsMenu->Append(IDM_NETPLAY, _T("Start &NetPlay")); #endif if (DiscIO::CNANDContentManager::Access().GetNANDLoader(std::string (File::GetUserPath(D_WIIMENU_IDX))).IsValid()) @@ -1000,7 +999,7 @@ void CFrame::StatusBarMessage(const char * Text, ...) void CFrame::OnNetPlay(wxCommandEvent& WXUNUSED (event)) { #if defined(HAVE_SFML) && HAVE_SFML - new NetPlay(this, m_GameListCtrl->GetGamePaths(), m_GameListCtrl->GetGameNames()); + new NetPlaySetupDiag(this, m_GameListCtrl); #endif } diff --git a/Source/Core/DolphinWX/Src/LockingQueue.h b/Source/Core/DolphinWX/Src/LockingQueue.h new file mode 100644 index 0000000000..3975091698 --- /dev/null +++ b/Source/Core/DolphinWX/Src/LockingQueue.h @@ -0,0 +1,47 @@ +#ifndef _LOCKINGQUEUE_H_ +#define _LOCKINGQUEUE_H_ + +#include "Thread.h" +#include + +// i should make one of those single reader/ single writer queues + +template +class LockingQueue +{ +public: + size_t Size() + { + m_crit.Enter(); + const size_t s = m_queue.size(); + m_crit.Leave(); + return s; + } + + void Push(const T& t) + { + m_crit.Enter(); + m_queue.push(t); + m_crit.Leave(); + } + + bool Pop(T& t) + { + m_crit.Enter(); + if (m_queue.size()) + { + t = m_queue.front(); + m_queue.pop(); + m_crit.Leave(); + return true; + } + m_crit.Leave(); + return false; + } + +private: + std::queue m_queue; + Common::CriticalSection m_crit; +}; + +#endif diff --git a/Source/Core/DolphinWX/Src/NetEvent.cpp b/Source/Core/DolphinWX/Src/NetEvent.cpp deleted file mode 100644 index 8ded2dd5b5..0000000000 --- a/Source/Core/DolphinWX/Src/NetEvent.cpp +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "NetSockets.h" -#include "NetWindow.h" - -void ClientSide::OnClientData(unsigned char data) -{ - unsigned char sent = 0; - u32 buffer_size; - size_t recv_size; - char *buffer = NULL; - - switch (data) - { - case 0x10: // Player joined server - { - // Read GameFound - m_socket.Receive((char*)&sent, 1, recv_size); - - // Read nickname - m_socket.Receive((char*)&buffer_size, 4, recv_size); - buffer = new char[buffer_size+1]; - m_socket.Receive(buffer, buffer_size+1, recv_size); - Event->AppendText(wxString::FromAscii(StringFromFormat("*Player : %s is now connected to Host...\n", buffer).c_str())); - - if (sent != 0x1F) - for (int i = 0; i < 4; i++) - Event->AppendText(_("WARNING : Game Not Found on Client Side!\n")); - - m_numplayers++; - Event->SendEvent(HOST_NEWPLAYER); - break; - } - case 0x11: // Player left server - { - // Read Nickname - m_socket.Receive((char*)&buffer_size, 4, recv_size); - buffer = new char[buffer_size+1]; - m_socket.Receive(buffer, buffer_size+1, recv_size); - - Event->AppendText(wxString::FromAscii(StringFromFormat("*Player : %s left the game\n\n", buffer).c_str())); - - m_numplayers--; - Event->SendEvent(HOST_PLAYERLEFT); - break; - } - case 0x15: // Ping Player - { - m_socket.Receive((char*)&buffer_size, 4, recv_size); - m_socket.Send((const char*)&buffer_size, 4); - - break; - } - case 0x20: // IP request - { - //buffer_size = m_addr.size(); - //m_socket.Send((const char*)&buffer_size, 4); - m_socket.Send((const char*)&data, 1); - m_socket.Send(m_addr.c_str(), m_addr.size() + 1); - - break; - } - case 0x30: // Chat message received from server - { - m_socket.Receive((char*)&buffer_size, 4, recv_size); - buffer = new char[buffer_size+1]; - m_socket.Receive(buffer, buffer_size+1, recv_size); - - if (recv_size > 1024) - { - //something wrong... - delete[] buffer; - return; - } - - Event->AppendText(wxString::FromAscii(buffer)); - - break; - } - case 0x35: // ChangeGame message received - { - m_socket.Receive((char*)&buffer_size, 4, recv_size); - buffer = new char[buffer_size+1]; - m_socket.Receive(buffer, buffer_size+1, recv_size); - - m_selectedgame = std::string(buffer); - Event->AppendText(wxString::FromAscii(StringFromFormat("*Host changed Game to : %s\n", buffer).c_str())); - - // Tell the server if the game's been found - m_socket.Send((const char*)&data, 1); - CheckGameFound(); - - Event->SendEvent(GUI_UPDATE); - - break; - } - case 0x40: // Ready message received - { - m_socket.Receive((char*)&buffer_size, 4, recv_size); - buffer = new char[buffer_size+1]; - m_socket.Receive(buffer, buffer_size+1, recv_size); - - if (recv_size > 1024) - { - delete[] buffer; - return; - } - - Event->AppendText(wxString::FromAscii(buffer)); - - break; - } - case 0x50: // Everyone is Ready message received - { - // Load the game and start synching - m_netptr->LoadGame(); - - break; - } - case 0xA1: // Received pad data from host in versus mode - { - if (m_data_received) - wxThread::Sleep(10); - - m_socket.Receive((char*)m_netvalues[0], 8, recv_size); - m_data_received = true; - -#ifdef NET_DEBUG - char msgbuf[64]; - sprintf(msgbuf, "Received Values: 0x%08x : 0x%08x \n", m_netvalues[0][0], m_netvalues[0][1]); - Event->AppendText(wxString::FromAscii(msgbuf)); -#endif - break; - } - } - - delete[] buffer; -} - -void ServerSide::OnServerData(int sock, unsigned char data) -{ - size_t recv_size; - char *buffer = NULL; - unsigned char sent; - unsigned int four_bytes; - - switch (data) - { - case 0x15: // Ping Request - { - m_client[sock].socket.Receive((char*)&four_bytes, 4, recv_size); - m_client[sock].socket.Send((const char*)&four_bytes, 4); - - break; - } - case 0x20: // IP request response - { - buffer = new char[24]; - // Read IP Address - m_client[sock].socket.Receive(buffer, 24, recv_size); - - Event->AppendText(wxString::FromAscii(StringFromFormat("> Your IP is : %s\n", buffer).c_str())); - - break; - } - case 0x30: // Chat message - { - buffer = new char[1024]; - - m_client[sock].socket.Receive((char*)&four_bytes, 4, recv_size); - m_client[sock].socket.Receive((char*)buffer, four_bytes + 1, recv_size); - - if (recv_size > 1024) - { - //something wrong... - delete[] buffer; - return; - } - - sent = 0x30; - // Send to all - for (int i=0; i < m_numplayers ; i++) - { - if (i == sock) - continue; - - m_client[i].socket.Send((const char*)&sent, 1); - - m_client[1].socket.Send((const char*)&four_bytes, 4); - m_client[i].socket.Send(buffer, recv_size); - } - - Event->AppendText(wxString::FromAscii(buffer)); - - break; - } - case 0x35: // Change game response received - { - // Receive isGameFound response (0x1F / 0x1A) - m_client[sock].socket.Receive((char*)&sent, 1, recv_size); - - // If game is not found - if (sent != 0x1F) - { - sent = 0x30; - - wxString error_str = wxString::FromAscii( - StringFromFormat("WARNING : Player %s does Not have this Game !\n", m_client[sock].nick.c_str()).c_str()); - four_bytes = (int)error_str.size(); - - for (int i=0; i < 2; i++) - Event->AppendText(error_str); - - // Send to all - for (int i=0; i < m_numplayers ; i++) - { - if (i == sock) - continue; - m_client[i].socket.Send((const char*)&sent, 1); - - m_client[i].socket.Send((const char*)&four_bytes, 4); - m_client[i].socket.Send(error_str.mb_str(), four_bytes + 1); - } - } - - break; - } - case 0x40: // Ready message received - { - std::string buffer_str; - - m_client[sock].ready = !m_client[sock].ready; - - if (m_client[sock].ready) - buffer_str = ">> "+m_client[sock].nick+" is now ready !\n"; - else - buffer_str = ">> "+m_client[sock].nick+" is now Unready !\n"; - - four_bytes = (int)buffer_str.size(); - - // Send to all - for (int i=0; i < m_numplayers ; i++) - { - m_client[i].socket.Send((const char*)&data, 1); - - m_client[i].socket.Send((const char*)&four_bytes, 4); - m_client[i].socket.Send(buffer_str.c_str(), four_bytes+1); - } - - Event->AppendText(wxString::FromAscii(buffer_str.c_str())); - IsEveryoneReady(); - - break; - } - case 0xA1: // Received pad data from a client - { - if (m_data_received) - wxThread::Sleep(10); - - m_client[sock].socket.Receive((char*)m_netvalues[sock], 8, recv_size); - m_data_received = true; - -#ifdef NET_DEBUG - char msgbuf[64]; - sprintf(msgbuf, "Received Values: 0x%08x : 0x%08x \n", m_netvalues[sock][0], m_netvalues[sock][1]); - Event->AppendText(wxString::FromAscii(msgbuf)); -#endif - break; - } - } - - delete[] buffer; -} - diff --git a/Source/Core/DolphinWX/Src/NetFunctions.cpp b/Source/Core/DolphinWX/Src/NetFunctions.cpp deleted file mode 100644 index 4faf04f677..0000000000 --- a/Source/Core/DolphinWX/Src/NetFunctions.cpp +++ /dev/null @@ -1,588 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "NetSockets.h" -#include "NetWindow.h" -#include "HW/SI_DeviceGCController.h" - -NetPlay *NetClass_ptr = NULL; - -void NetPlay::IsGameFound(unsigned char * ptr, std::string m_selected) -{ - m_critical.Enter(); - - m_selectedGame = m_selected; - - if (m_games.find(m_selected) != std::string::npos) - *ptr = 0x1F; - else - *ptr = 0x1A; - - m_critical.Leave(); -} - -void NetPlay::OnNetEvent(wxCommandEvent& event) -{ - switch (event.GetId()) - { - case HOST_FULL: - { - AppendText(_(" Server is Full !\n*You have been Disconnected.\n\n")); - m_isHosting = 2; - } - break; - case HOST_ERROR: - { - if (m_isHosting == 0) - { - AppendText(_("ERROR : Network Error !\n*You have been Disconnected.\n\n")); - m_isHosting = 2; - } - else - { - m_numClients--; - AppendText( wxString::Format(wxT("ERROR : Network Error !\n") - wxT("*Player : %s has been dropped from the game.\n\n"), - (const char *)event.GetString().mb_str()) ); - } - } - break; - case HOST_DISCONNECTED: - { - // Event sent from Client's thread, it means that the thread - // has been killed and so we tell the GUI thread. - AppendText(_("*Connection to Host lost.\n*You have been Disconnected.\n\n")); - m_isHosting = 2; - m_numClients--; - } - break; - case HOST_PLAYERLEFT: - { - m_numClients--; - } - break; - case HOST_NEWPLAYER: - { - m_numClients++; - m_NetModel = event.GetInt(); - } - break; - case CLIENTS_READY: - { - m_clients_ready = true; - - // Tell clients everyone is ready... - if (m_ready) - LoadGame(); - } - break; - case CLIENTS_NOTREADY: - { - m_clients_ready = false; - } - break; - case GUI_UPDATE: - UpdateNetWindow(false); - break; - case ADD_TEXT: - AppendText(event.GetString()); - break; - case ADD_INFO: - UpdateNetWindow(true, event.GetString()); - break; - } -} - -void ServerSide::IsEveryoneReady() -{ - int nb_ready = 0; - - for (int i=0; i < m_numplayers ; i++) - if (m_client[i].ready) - nb_ready++; - - if (nb_ready == m_numplayers) - Event->SendEvent(CLIENTS_READY); - else - Event->SendEvent(CLIENTS_NOTREADY); -} - -// Actual Core function which is called on every frame -int CSIDevice_GCController::GetNetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus) -{ - if (NetClass_ptr != NULL) - return NetClass_ptr->GetNetPads(numPAD, PadStatus, PADStatus) ? 1 : 0; - else - return 2; -} - -void NetPlay::LoadGame() -{ - // Two implementations, one "p2p" implementation which sends to peer - // and receive from peer 2 players max. and another which uses server model - // and always sends to the server which then send it back to all the clients - // -> P2P model is faster, but is limited to 2 players - // -> Server model is slower, but supports up to 4 players - - if (m_isHosting == 1) - { - long ping[3] = {0}; - unsigned char value = 0x50; - - // Get ping - m_sock_server->Write(0, 0, 0, ping); - float fping = (ping[0]+ping[1]+ping[2])/(float)m_numClients; - - // Tell client everyone is ready - for (int i=0; i < m_numClients ; i++) - m_sock_server->Write(i, (const char*)&value, 1); - - // Sleep a bit to start the game at more or less the same time than the peer - wxMilliSleep(fping/2); - - m_Logging->AppendText(wxString::Format(wxT("** Everyone is ready... Loading Game ! **\n") - wxT("** Ping to client(s) is : %f ms\n"), fping)); - } - else - m_Logging->AppendText(_("** Everyone is ready... Loading Game ! **\n")); - - // TODO : Throttle should be on by default, to avoid stuttering - //soundStream->GetMixer()->SetThrottle(true); - - int line_p = 0; - int line_n = 0; - - m_critical.Enter(); - std::string tmp = m_games.substr(0, m_games.find(m_selectedGame)); - - for (int i=0; i < (int)tmp.size(); i++) - if (tmp.c_str()[i] == '\n') - line_n++; - - // Enable - NetClass_ptr = this; - m_timer.Start(); - m_data_received = false; - m_critical.Leave(); - - // Find corresponding game path - for (int i=0; i < (int)m_paths.size(); i++) - { - if (m_paths.c_str()[i] == '\n') - line_p++; - - if (line_n == line_p) { - // Game path found, get its string - int str_pos = line_p > 0 ? i+1 : i; - int str_end = (int)m_paths.find('\n', str_pos); - // Boot the selected game - BootManager::BootCore(m_paths.substr(str_pos, str_end - str_pos)); - break; - } - } -} - -bool NetPlay::GetNetPads(u8 padnb, SPADStatus PadStatus, u32 *netValues) -{ - if (m_numClients < 1) - { - m_Logging->AppendText(_("** WARNING : Ping too high (>2000ms) or connection lost ! \n** WARNING : Stopping Netplay... \n")); - NetClass_ptr = NULL; - return false; - } - - // Store current pad status in netValues[] - netValues[0] = (u32)((u8)PadStatus.stickY); - netValues[0] |= (u32)((u8)PadStatus.stickX << 8); - netValues[0] |= (u32)((u16)PadStatus.button << 16); - netValues[0] |= 0x00800000; - netValues[1] = (u8)PadStatus.triggerRight; - netValues[1] |= (u32)((u8)PadStatus.triggerLeft << 8); - netValues[1] |= (u32)((u8)PadStatus.substickY << 16); - netValues[1] |= (u32)((u8)PadStatus.substickX << 24); - - if (m_NetModel == 0) // Use 2 players Model - { - if (padnb == 0) - { - // Update the timer and increment total frame number - m_frame++; - - if (m_frame == 1) - { - // We make sure everyone's pad is enabled - for (int i = 0; i < m_numClients+1; i++) - SerialInterface::ChangeDevice(SI_GC_CONTROLLER, i); - - // Better disable unused ports - for (int i = m_numClients+1; i < 4; i++) - SerialInterface::ChangeDevice(SI_NONE, i); - } - - if (m_timer.GetTimeDifference() > 1000) - m_timer.Update(); - -#ifdef NET_DEBUG - char sent[64]; - sprintf(sent, "Sent Values: 0x%08x : 0x%08x \n", netValues[0], netValues[1]); - m_Logging->AppendText(wxString::FromAscii(sent)); -#endif - unsigned char player = 0; - -#ifdef USE_TCP - unsigned char init_value = 0xA1; - - if (m_isHosting == 1) { - // Send pads values - m_sock_server->Write(0, (const char*)&init_value, 1); - m_sock_server->Write(0, (const char*)netValues, 8); - } - else { - // Send pads values - m_sock_client->Write((const char*)&init_value, 1); - m_sock_client->Write((const char*)netValues, 8); - player = 1; - } -#else // UDP - u32 padsValues[3]; - - padsValues[0] = m_frame; - padsValues[1] = netValues[0]; - padsValues[2] = netValues[1]; - - if (m_isHosting == 1) { - // Send pads values - m_sock_server->WriteUDP(0, (const char*)padsValues, 12); - } - else { - // Send pads values - m_sock_client->WriteUDP((const char*)padsValues, 12); - player = 1; - } -#endif - - if (!m_data_received) - { - // Save pad values - m_pads[player].nHi[m_loopframe] = netValues[0]; - m_pads[player].nLow[m_loopframe] = netValues[1]; - - // Try to read from peer... - if (m_isHosting == 1) - m_data_received = m_sock_server->isNewPadData(0, false); - else - m_data_received = m_sock_client->isNewPadData(0, false); - - if (m_data_received) - { - // Set our practical frame delay - m_frameDelay = m_loopframe; - m_loopframe = 0; - - // First Data has been received ! - m_Logging->AppendText(_("** Data received from Peer. Starting Sync !")); - m_Logging->AppendText(wxString::Format(wxT(" Frame Delay : %d **\n"), m_frameDelay)); - } - else { - if (m_loopframe > 126) - { - m_Logging->AppendText(_("** WARNING : Ping too high (>2000ms) or connection lost ! \n** WARNING : Stopping Netplay... \n")); - NetClass_ptr = NULL; - } - - m_loopframe++; - return false; - } - } - - if (m_data_received) - { - // We have successfully received the data, now use it... - // If we received data, we can update our pads on each frame, here's the behaviour : - // we received our init number, so we should receive our pad values on each frames - // with a frame delay of 'm_frameDelay' frames from the peer. So here, we just wait - // for the pad status. note : if the peer can't keep up, sending the values - // (i.e : framerate is too low) we have to wait for it thus slowing down emulation - - // Save current pad values, it will be used in 'm_frameDelay' frames :D - int saveslot = (m_loopframe - 1 < 0 ? m_frameDelay : m_loopframe - 1); - u32 recvedValues[2]; - - m_pads[player].nHi[saveslot] = netValues[0]; - m_pads[player].nLow[saveslot] = netValues[1]; - - // Read the socket for pad values - if (m_isHosting == 1) - m_sock_server->isNewPadData(recvedValues, true); - else - m_sock_client->isNewPadData(recvedValues, true); - - if (player == 0) - { - // Store received peer values - m_pads[1].nHi[m_loopframe] = recvedValues[0]; - m_pads[1].nLow[m_loopframe] = recvedValues[1]; - - // Apply synced pad values - netValues[0] = m_pads[0].nHi[m_loopframe]; - netValues[1] = m_pads[0].nLow[m_loopframe]; - } - else - { - // Apply received pad values - netValues[0] = recvedValues[0]; - netValues[1] = recvedValues[1]; - } - } - -#ifdef NET_DEBUG - char usedval[64]; - sprintf(usedval, "Player 1 Values: 0x%08x : 0x%08x \n", netValues[0], netValues[1]); - m_Logging->AppendText(wxString::FromAscii(usedval)); -#endif - return true; - } - else if (padnb == 1) - { - if (m_data_received) - { - netValues[0] = m_pads[1].nHi[m_loopframe]; - netValues[1] = m_pads[1].nLow[m_loopframe]; - - // Reset the loop to avoid reading unused values - if (m_loopframe == m_frameDelay) - m_loopframe = 0; - else - m_loopframe++; - } - else - return false; -#ifdef NET_DEBUG - char usedval[64]; - sprintf(usedval, "Player 2 Values: 0x%08x : 0x%08x \n", netValues[0], netValues[1]); - m_Logging->AppendText(wxString::FromAscii(usedval)); -#endif - - return true; - } - } - else - { - // TODO : :D - return false; - } - - return false; -} - -void NetPlay::ChangeSelectedGame(std::string game) -{ - wxCriticalSectionLocker lock(m_critical); - if (m_isHosting == 0) - { - m_selectedGame = game; - return; - } - - if (game != m_selectedGame) - { - unsigned char value = 0x35; - int game_size = (int)game.size(); - - // Send command then Game String - for (int i=0; i < m_numClients ; i++) - { - m_sock_server->Write(i, (const char*)&value, 1); // 0x35 -> Change game - - m_sock_server->Write(i, (const char*)&game_size, 4); - m_sock_server->Write(i, game.c_str(), game_size + 1); - } - - m_selectedGame = game; - UpdateNetWindow(false); - m_Logging->AppendText(wxString::Format( wxT(" *Game has been changed to : %s \r\n "), wxString(game.c_str(), wxConvUTF8).c_str())); - NOTICE_LOG(NETPLAY,"Game has been changed to : %s \n",game.c_str()); - } -} - -void NetPlay::OnQuit(wxCloseEvent& WXUNUSED(event)) -{ - // Disable netplay - NetClass_ptr = NULL; - - // Destroy the Window - Destroy(); - - // Then Kill the threads - if (m_isHosting == 0) - m_sock_client->Delete(); - else if (m_isHosting == 1) { - m_sock_server->Delete(); - } - -} - -void NetPlay::OnDisconnect(wxCommandEvent& WXUNUSED(event)) -{ - wxCloseEvent close; - OnQuit(close); -} - -bool ClientSide::isNewPadData(u32 *netValues, bool current, bool isVersus) -{ -#ifdef USE_TCP - if (current) - { - while (1) - { - m_CriticalSection.Enter(); - if (m_data_received && isVersus) - { - netValues[0] = m_netvalues[0][0]; - netValues[1] = m_netvalues[0][1]; - m_data_received = false; - - m_CriticalSection.Leave(); - break; - } - m_CriticalSection.Leave(); - - if (TestDestroy()) - break; - } - - return true; - } - else - wxCriticalSectionLocker lock(m_CriticalSection); - - return m_data_received; -#else - size_t recv_size; - - if (current) - { - m_CriticalSection.Enter(); - - if (isVersus) - { - if (m_netvalues[0][1] != 0) - { - netValues[0] = m_netvalues[0][1]; - netValues[1] = m_netvalues[0][2]; - } - else - { - while (true) - { - u32 frame_saved = m_netvalues[0][0]; - bool pass = RecvT(m_socketUDP, (char*)&m_netvalues[0], 12, recv_size, 5); - - if (m_netvalues[0][0] < frame_saved+1) - continue; - if (m_netvalues[0][0] > frame_saved+1 || !pass) - PanicAlert("Network ERROR !"); - - netValues[0] = m_netvalues[0][1]; - netValues[1] = m_netvalues[0][2]; - break; - } - } - } - - m_netvalues[0][1] = 0; - m_CriticalSection.Leave(); - - return true; - } - else - return RecvT(m_socketUDP, (char*)&m_netvalues[0], 12, recv_size, 1/1000); - -#endif - -} - -bool ServerSide::isNewPadData(u32 *netValues, bool current, int client) -{ -#ifdef USE_TCP - if (current) - { - while (1) - { - m_CriticalSection.Enter(); - if (m_data_received) - { - netValues[0] = m_netvalues[client][0]; - netValues[1] = m_netvalues[client][1]; - m_data_received = false; - - m_CriticalSection.Leave(); - break; - } - m_CriticalSection.Leave(); - - if (TestDestroy()) - break; - } - - return true; - } - else - wxCriticalSectionLocker lock(m_CriticalSection); - - return m_data_received; -#else - size_t recv_size; - - if (current) - { - m_CriticalSection.Enter(); - - if (m_netvalues[0][1] != 0) - { - netValues[0] = m_netvalues[client][1]; - netValues[1] = m_netvalues[client][2]; - } - else - { - while (true) - { - u32 frame_saved = m_netvalues[client][0]; - bool pass = RecvT(m_socketUDP, (char*)&m_netvalues[client], 12, recv_size, 5); - - if (m_netvalues[client][0] < frame_saved+1) - continue; - if (m_netvalues[client][0] > frame_saved+1 || !pass) - PanicAlert("Network ERROR !"); - - netValues[0] = m_netvalues[client][1]; - netValues[1] = m_netvalues[client][2]; - break; - } - } - - m_netvalues[client][1] = 0; - m_CriticalSection.Leave(); - - return true; - } - else - return RecvT(m_socketUDP, (char*)&m_netvalues[client], 12, recv_size, 1/1000); - -#endif -} - diff --git a/Source/Core/DolphinWX/Src/NetPlay.cpp b/Source/Core/DolphinWX/Src/NetPlay.cpp new file mode 100644 index 0000000000..aecf0e0a8d --- /dev/null +++ b/Source/Core/DolphinWX/Src/NetPlay.cpp @@ -0,0 +1,912 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#include "HW/SI_DeviceGCController.h" +#include "HW/EXI_DeviceIPL.h" + +#include "Frame.h" + +#include "NetPlay.h" +#include "NetWindow.h" + +#include + +// this will be removed soon +#define TEMP_FIXED_BUFFER 20 + +enum +{ + CON_ERR_SERVER_FULL = 1, + CON_ERR_GAME_RUNNING, + CON_ERR_VERSION_MISMATCH +}; + +NetPlay* NetClass_ptr = NULL; +extern CFrame* main_frame; + +DEFINE_EVENT_TYPE(wxEVT_THREAD) + +THREAD_RETURN NetPlayThreadFunc(void* arg) +{ + ((NetPlay*)arg)->Entry(); + return 0; +} + +NetPlay::~NetPlay() +{ + ::NetClass_ptr = NULL; +} + +NetPlayServer::~NetPlayServer() +{ + if (is_connected) + { + m_do_loop = false; + m_thread->WaitForDeath(); + delete m_thread; + } +} + +NetPlayClient::~NetPlayClient() +{ + if (is_connected) + { + m_do_loop = false; + m_thread->WaitForDeath(); + delete m_thread; + } +} + +NetPlayServer::Player::Player() +{ + memset(pad_map, -1, sizeof(pad_map)); +} + +NetPlayClient::Player::Player() +{ + memset(pad_map, -1, sizeof(pad_map)); +} + +NetPlayServer::NetPlayServer(const u16 port, const std::string& name, NetPlayDiag* const npd, const std::string& game) +{ + m_dialog = npd; + m_selected_game = game; + + if (m_socket.Listen(port)) + { + Player player; + player.pid = 0; + player.revision = NETPLAY_DOLPHIN_VER; + player.socket = m_socket; + player.name = name; + + // map local pad 1 to game pad 1 + player.pad_map[0] = 0; + + // add self to player list + m_players[m_socket] = player; + //PanicAlert("Listening"); + + UpdateGUI(); + + is_connected = true; + + m_selector.Add(m_socket); + m_thread = new Common::Thread(NetPlayThreadFunc, this); + } + else + is_connected = false; +} + +NetPlayClient::NetPlayClient(const std::string& address, const u16 port, const std::string& name, NetPlayDiag* const npd) +{ + m_dialog = npd; + is_connected = false; + + // why is false successful? documentation says true is + if (0 == m_socket.Connect(port, address)) + { + // send connect message + sf::Packet spac; + spac << NETPLAY_VERSION; + spac << NETPLAY_DOLPHIN_VER; + spac << name; + m_socket.Send(spac); + + sf::Packet rpac; + // TODO: make this not hang + m_socket.Receive(rpac); + u8 error; + rpac >> error; + + // got error message + if (error) + { + switch (error) + { + case CON_ERR_SERVER_FULL : + PanicAlert("The server is full!"); + break; + case CON_ERR_VERSION_MISMATCH : + PanicAlert("The NetPlay versions are incompatible!"); + break; + case CON_ERR_GAME_RUNNING : + PanicAlert("The game is currently running!"); + break; + } + m_socket.Close(); + } + else + { + rpac >> m_pid; + + Player player; + player.name = "Player"; + player.pid = m_pid; + player.revision = NETPLAY_DOLPHIN_VER; + + // add self to player list + m_players[m_pid] = player; + + UpdateGUI(); + + //PanicAlert("Connection successful: assigned player id: %d", m_pid); + is_connected = true; + + m_selector.Add(m_socket); + m_thread = new Common::Thread(NetPlayThreadFunc, this); + } + } + else + PanicAlert("Failed to Connect!"); + +} + +void NetPlayServer::Entry() +{ + while (m_do_loop) + { + const unsigned int num = m_selector.Wait(0.01f); + + for (unsigned int i=0; i::reverse_iterator + i = m_players.rbegin(), + e = m_players.rend(); + for ( ; i!=e; ++i) + i->second.socket.Close(); + } + + return; +} + +unsigned int NetPlayServer::OnConnect(sf::SocketTCP& socket) +{ + sf::Packet rpac; + // TODO: make this not hang / check if good packet + socket.Receive(rpac); + + std::string npver; + rpac >> npver; + // dolphin netplay version + if (npver != NETPLAY_VERSION) + return CON_ERR_VERSION_MISMATCH; + + // game is currently running + if (m_is_running) + return CON_ERR_GAME_RUNNING; + + // too many players + if (m_players.size() >= 255) + return CON_ERR_SERVER_FULL; + + Player player; + player.socket = socket; + rpac >> player.revision; + rpac >> player.name; + + // give new client first available id + player.pid = 0; + std::map::const_iterator + i, + e = m_players.end(); + for (u8 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; + } + } + + // TODO: this is crappy + // try to automatically assign new user a pad + { + 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 (i->second.pad_map[m] >= 0) + is_mapped[i->second.pad_map[m]] = true; + } + } + + for ( unsigned int m = 0; m<4; ++m) + if (false == is_mapped[m]) + { + player.pad_map[0] = m; + break; + } + + } + + // ENTER + m_crit.send.Enter(); + + // send join message to already connected clients + sf::Packet spac; + spac << (MessageId)NP_MSG_PLAYER_JOIN; + spac << player.pid << player.name << player.revision; + SendToClients(spac); + + // send new client success message with their id + spac.Clear(); + spac << (MessageId)0; + 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; + spac << m_selected_game; + socket.Send(spac); + + // sync values with new client + for (i = m_players.begin(); i!=e; ++i) + { + spac.Clear(); + 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 + m_crit.send.Leave(); + + // add client to the player list + m_crit.players.Enter(); + m_players[socket] = player; + m_crit.players.Leave(); + + // add client to selector/ used for receiving + m_selector.Add(socket); + + UpdateGUI(); + + return 0; +} + +unsigned int NetPlayServer::OnDisconnect(sf::SocketTCP& socket) +{ + if (m_is_running) + PanicAlert("Disconnect while game is running. Game will likely hang!"); + + sf::Packet spac; + spac << (MessageId)NP_MSG_PLAYER_LEAVE; + spac << m_players[socket].pid; + + m_selector.Remove(socket); + + m_crit.players.Enter(); + m_players.erase(m_players.find(socket)); + m_crit.players.Leave(); + + UpdateGUI(); + + m_crit.send.Enter(); + SendToClients(spac); + m_crit.send.Leave(); + + return 0; +} + +void NetPlay::UpdateGUI() +{ + if (m_dialog) + { + wxCommandEvent evt(wxEVT_THREAD, 1); + m_dialog->AddPendingEvent(evt); + } +} + +void NetPlayServer::SendToClients(sf::Packet& packet, const u8 skip_pid) +{ + std::map::iterator + i = m_players.begin(), + e = m_players.end(); + for ( ; i!=e; ++i) + if (i->second.pid && (i->second.pid != skip_pid)) + i->second.socket.Send(packet); +} + +unsigned int NetPlayServer::OnData(sf::Packet& packet, sf::SocketTCP& socket) +{ + MessageId mid; + packet >> mid; + + // don't need lock because this is the only thread that modifies the players + // only need locks for writes to m_players in this thread + Player& player = m_players[socket]; + + switch (mid) + { + case NP_MSG_CHAT_MESSAGE : + { + std::string msg; + packet >> msg; + + // send msg to other clients + sf::Packet spac; + spac << (MessageId)NP_MSG_CHAT_MESSAGE; + spac << player.pid; + spac << msg; + + m_crit.send.Enter(); + SendToClients(spac, player.pid); + m_crit.send.Leave(); + + // add to gui + std::ostringstream ss; + ss << player.name << '[' << (char)(player.pid+'0') << "]: " << msg; + + m_dialog->chat_msgs.Push(ss.str()); + + UpdateGUI(); + } + break; + + case NP_MSG_PAD_DATA : + { + PadMapping map; + NetPad np; + packet >> map >> np.nHi >> np.nLo; + + // check if client's pad indeed maps in game + if (map >= 0 && map < 4) + map = player.pad_map[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 implimented yet + if (map < 0) + return 1; + + // add to pad buffer + m_crit.buffer.Enter(); + m_pad_buffer[map].push(np); + m_crit.buffer.Leave(); + + // relay to clients + sf::Packet spac; + spac << (MessageId)NP_MSG_PAD_DATA; + spac << map; // in game mapping + spac << np.nHi << np.nLo; + + m_crit.send.Enter(); + SendToClients(spac, player.pid); + m_crit.send.Leave(); + } + break; + + default : + //PanicAlert("Unknown message received with id : %d", mid); + // unknown message, kick the client + return 1; + break; + } + + return 0; +} + +unsigned int NetPlayClient::OnData(sf::Packet& packet) +{ + MessageId mid; + packet >> mid; + + switch (mid) + { + case NP_MSG_PLAYER_JOIN : + { + Player player; + packet >> player.pid; + packet >> player.name; + packet >> player.revision; + + m_crit.players.Enter(); + m_players[player.pid] = player; + m_crit.players.Leave(); + + UpdateGUI(); + } + break; + + case NP_MSG_PLAYER_LEAVE : + { + PlayerId pid; + packet >> pid; + + m_crit.players.Enter(); + m_players.erase(m_players.find(pid)); + m_crit.players.Leave(); + + UpdateGUI(); + } + break; + + case NP_MSG_CHAT_MESSAGE : + { + PlayerId pid; + packet >> pid; + std::string msg; + packet >> msg; + + // don't need lock to read in this thread + const Player& player = m_players[pid]; + + // add to gui + std::ostringstream ss; + ss << player.name << '[' << (char)(pid+'0') << "]: " << msg; + + m_dialog->chat_msgs.Push(ss.str()); + UpdateGUI(); + } + break; + + case NP_MSG_PAD_MAPPING : + { + PlayerId pid; + packet >> pid; + + m_crit.players.Enter(); + Player& player = m_players[pid]; + + for (unsigned int i=0; i<4; ++i) + packet >> player.pad_map[i]; + m_crit.players.Leave(); + + UpdateGUI(); + } + break; + + case NP_MSG_PAD_DATA : + { + PadMapping map; + NetPad np; + packet >> map >> np.nHi >> np.nLo; + + // add to pad buffer + m_crit.buffer.Enter(); + m_pad_buffer[map].push(np); + m_crit.buffer.Leave(); + } + break; + + case NP_MSG_CHANGE_GAME : + { + m_crit.other.Enter(); + packet >> m_selected_game; + m_crit.other.Leave(); + + // update gui + wxCommandEvent evt(wxEVT_THREAD, 45); + evt.SetString(wxString(m_selected_game.c_str(), *wxConvCurrent)); + m_dialog->AddPendingEvent(evt); + } + break; + + case NP_MSG_START_GAME : + { + // kinda silly + wxCommandEvent evt; + m_dialog->OnStart(evt); + } + break; + + default : + PanicAlert("Unknown message received with id : %d", mid); + break; + + } + + return 0; +} + +void NetPlayClient::Entry() +{ + while (m_do_loop) + { + if (m_selector.Wait(0.01f)) + { + sf::Packet rpac; + switch (m_socket.Receive(rpac)) + { + case sf::Socket::Done : + OnData(rpac); + break; + + case sf::Socket::Disconnected : + PanicAlert("Lost connection to server! If the game is running, it will likely hang!"); + m_do_loop = false; + break; + } + } + } + + m_socket.Close(); + + return; +} + +template +static inline std::string PlayerToString(const P& p) +{ + std::ostringstream ss; + ss << p.name << '[' << (char)(p.pid+'0') << "] : " << p.revision << " |"; + for (unsigned int i=0; i<4; ++i) + ss << (p.pad_map[i]>=0 ? (char)(p.pad_map[i]+'1') : '-'); + ss << '|'; + return ss.str(); +} + +void NetPlayClient::GetPlayerList(std::string &list) +{ + m_crit.players.Enter(); + + std::ostringstream ss; + + std::map::const_iterator + i = m_players.begin(), + e = m_players.end(); + for ( ; i!=e; ++i) + ss << PlayerToString(i->second) << '\n'; + + list = ss.str(); + + m_crit.players.Leave(); +} + +void NetPlayServer::GetPlayerList(std::string &list) +{ + m_crit.players.Enter(); + + std::ostringstream ss; + + std::map::const_iterator + i = m_players.begin(), + e = m_players.end(); + for ( ; i!=e; ++i) + ss << PlayerToString(i->second) << '\n'; + + list = ss.str(); + + m_crit.players.Leave(); +} + +void NetPlayServer::SendChatMessage(const std::string& msg) +{ + sf::Packet spac; + spac << (MessageId)NP_MSG_CHAT_MESSAGE; + spac << (PlayerId)0; // server id always 0 + spac << msg; + + m_crit.send.Enter(); + SendToClients(spac); + m_crit.send.Leave(); +} + +void NetPlayClient::SendChatMessage(const std::string& msg) +{ + sf::Packet spac; + spac << (MessageId)NP_MSG_CHAT_MESSAGE; + spac << msg; + + m_crit.send.Enter(); + m_socket.Send(spac); + m_crit.send.Leave(); +} + +NetPad::NetPad() +{ + //SPADStatus sp; + //memset(&sp, 0, sizeof(sp)); + //memset(&sp.stickX, 0x80, 4); + //*this = NetPad(&sp); + + // i'd rather do something like this + nHi = 0x00808080; + nLo = 0x80800000; +} + +NetPad::NetPad(const SPADStatus* const pad_status) +{ + nHi = (u32)((u8)pad_status->stickY); + nHi |= (u32)((u8)pad_status->stickX << 8); + nHi |= (u32)((u16)pad_status->button << 16); + nHi |= 0x00800000; + nLo = (u8)pad_status->triggerRight; + nLo |= (u32)((u8)pad_status->triggerLeft << 8); + nLo |= (u32)((u8)pad_status->substickY << 16); + nLo |= (u32)((u8)pad_status->substickX << 24); +} + +bool NetPlayServer::GetNetPads(const u8 pad_nb, const SPADStatus* const pad_status, NetPad* const netvalues) +{ + m_crit.players.Enter(); + + // in game mapping for this local pad, kinda silly method + PadMapping in_game_num = m_players[m_socket].pad_map[pad_nb]; + + // check if this local pad maps in game + if (in_game_num >= 0) + { + NetPad np(pad_status); + + // add to buffer + m_crit.buffer.Enter(); + m_pad_buffer[in_game_num].push(np); + m_crit.buffer.Leave(); + + // send to clients + sf::Packet spac; + spac << (MessageId)NP_MSG_PAD_DATA; + spac << in_game_num; // in game pad num + spac << np.nHi << np.nLo; + + m_crit.send.Enter(); + SendToClients(spac); + m_crit.send.Leave(); + } + + // get padstate from buffer and send to game + m_crit.buffer.Enter(); + while (0 == m_pad_buffer[pad_nb].size()) + { + m_crit.buffer.Leave(); + // wait for receiving thread to push some data + Common::SleepCurrentThread(10); + m_crit.buffer.Enter(); + } + *netvalues = m_pad_buffer[pad_nb].front(); + m_pad_buffer[pad_nb].pop(); + m_crit.buffer.Leave(); + + m_crit.players.Leave(); + + return true; +} + +bool NetPlayServer::SetSelectedGame(const std::string &game) +{ + // warning removal + game.size(); + + return true; +} + +bool NetPlayClient::GetNetPads(const u8 pad_nb, const SPADStatus* const pad_status, NetPad* const netvalues) +{ + m_crit.players.Enter(); + + // in game mapping for this local pad + PadMapping in_game_num = m_players[m_pid].pad_map[pad_nb]; + + // does this local pad map in game? + if (in_game_num >= 0) + { + NetPad np(pad_status); + + // add to buffer + m_crit.buffer.Enter(); + m_pad_buffer[in_game_num].push(np); + m_crit.buffer.Leave(); + + // send to server + sf::Packet spac; + spac << (MessageId)NP_MSG_PAD_DATA; + spac << (PadMapping)pad_nb; // local pad num + spac << np.nHi << np.nLo; + + m_crit.send.Enter(); + m_socket.Send(spac); + m_crit.send.Leave(); + } + + // get padstate from buffer and send to game + m_crit.buffer.Enter(); + while (0 == m_pad_buffer[pad_nb].size()) + { + m_crit.buffer.Leave(); + // wait for receiving thread to push some data + Common::SleepCurrentThread(10); + m_crit.buffer.Enter(); + } + *netvalues = m_pad_buffer[pad_nb].front(); + m_pad_buffer[pad_nb].pop(); + m_crit.buffer.Leave(); + + m_crit.players.Leave(); + return true; +} + +bool NetPlayClient::SetSelectedGame(const std::string &game) +{ + // warning removal + game.size(); + + return true; +} + +bool NetPlayServer::StartGame(const std::string &path) +{ + m_crit.other.Enter(); + + if (m_is_running) + { + PanicAlert("Game is already running!"); + return false; + } + + m_is_running = true; + ::NetClass_ptr = this; + + m_crit.buffer.Enter(); + // testing + NetPad np; + for (unsigned int i=0; iBootGame(path); + //BootManager::BootCore(path); + + m_crit.other.Leave(); + + return true; +} + +bool NetPlayClient::StartGame(const std::string &path) +{ + m_crit.other.Enter(); + + m_is_running = true; + ::NetClass_ptr = this; + + m_crit.buffer.Enter(); + // testing + NetPad np; + for (unsigned int i=0; iBootGame(path); + //BootManager::BootCore(path); + + m_crit.other.Leave(); + + return true; +} + +// Actual Core function which is called on every frame +int CSIDevice_GCController::GetNetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus) +{ + if (NetClass_ptr) + // TODO: NetClass_ptr could go null here, need a lock + return NetClass_ptr->GetNetPads(numPAD, &PadStatus, (NetPad*)PADStatus) ? 1 : 0; + else + return 2; +} + +// so all players' games get the same time +u32 CEXIIPL::GetNetGCTime() +{ + if (NetClass_ptr) + // TODO: NetClass_ptr could go null here, need a lock + return 1272737767; // watev + else + return 0; +} diff --git a/Source/Core/DolphinWX/Src/NetPlay.h b/Source/Core/DolphinWX/Src/NetPlay.h new file mode 100644 index 0000000000..32d1a83d27 --- /dev/null +++ b/Source/Core/DolphinWX/Src/NetPlay.h @@ -0,0 +1,190 @@ +#ifndef _NETPLAY_H +#define _NETPLAY_H + +#include "Common.h" +#include "CommonTypes.h" +//#define WIN32_LEAN_AND_MEAN +#include "Thread.h" + +// hax, i hope something like this isn't needed on non-windows +#define _WINSOCK2API_ +#include + +#include "pluginspecs_pad.h" +#include "svnrev.h" + +//#include + +#include +#include + +class NetPlayDiag; + +class NetPad +{ +public: + NetPad(); + NetPad(const SPADStatus* const); + + u32 nHi; + u32 nLo; +}; + +#define NETPLAY_VERSION "Dolphin NetPlay 2.0" + +#ifdef _M_X64 + #define NP_ARCH "x64" +#else + #define NP_ARCH "x86" +#endif + +#ifdef _WIN32 + #define NETPLAY_DOLPHIN_VER SVN_REV_STR" win-"NP_ARCH +#elif __APPLE__ + #define NETPLAY_DOLPHIN_VER SVN_REV_STR" osx-"NP_ARCH +#else + #define NETPLAY_DOLPHIN_VER SVN_REV_STR" nix-"NP_ARCH +#endif + +// messages +#define NP_MSG_PLAYER_JOIN 0x10 +#define NP_MSG_PLAYER_LEAVE 0x11 + +#define NP_MSG_CHAT_MESSAGE 0x30 + +#define NP_MSG_PAD_DATA 0x60 +#define NP_MSG_PAD_MAPPING 0x61 +#define NP_MSG_PAD_BUFFER 0x62 + +#define NP_MSG_START_GAME 0xA0 +#define NP_MSG_CHANGE_GAME 0xA1 + +#define NP_MSG_READY 0xD0 +#define NP_MSG_NOT_READY 0xD1 + +#define NP_MSG_PING 0xE0 +#define NP_MSG_PONG 0xE1 +// end messages + +// gui messages +#define NP_GUI_UPDATE 0x10 +// end messages + +typedef u8 MessageId; +typedef u8 PlayerId; +typedef s8 PadMapping; + +class NetPlay +{ +public: + NetPlay() : m_is_running(false), m_do_loop(true) {} + virtual ~NetPlay(); + virtual void Entry() = 0; + + bool is_connected; + + // Send and receive pads values + virtual bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues) = 0; + virtual bool SetSelectedGame(const std::string& game) = 0; + virtual void GetPlayerList(std::string& list) = 0; + virtual void SendChatMessage(const std::string& msg) = 0; + virtual bool StartGame(const std::string &path) = 0; + +protected: + //NetPlay(Common::ThreadFunc entry, void* arg) : m_thread(entry, arg) {} + + void UpdateGUI(); + + struct + { + Common::CriticalSection send, players, buffer, other; + } m_crit; + + //LockingQueue m_pad_buffer[4]; + std::queue m_pad_buffer[4]; + + NetPlayDiag* m_dialog; + sf::SocketTCP m_socket; + Common::Thread* m_thread; + sf::Selector m_selector; + + std::string m_selected_game; + bool m_is_running; + volatile bool m_do_loop; + +private: + +}; + +class NetPlayServer : public NetPlay +{ +public: + void Entry(); + + NetPlayServer(const u16 port, const std::string& name, NetPlayDiag* const npd = NULL, const std::string& game = ""); + ~NetPlayServer(); + + void GetPlayerList(std::string& list); + + // Send and receive pads values + bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues); + bool SetSelectedGame(const std::string& game); + void SendChatMessage(const std::string& msg); + bool StartGame(const std::string &path); + +private: + class Player + { + public: + Player(); + + PlayerId pid; + sf::SocketTCP socket; + std::string name; + PadMapping pad_map[4]; + std::string revision; + }; + + void SendToClients(sf::Packet& packet, const u8 skip_pid = 0); + unsigned int OnConnect(sf::SocketTCP& socket); + unsigned int OnDisconnect(sf::SocketTCP& socket); + unsigned int OnData(sf::Packet& packet, sf::SocketTCP& socket); + + std::map m_players; +}; + +class NetPlayClient : public NetPlay +{ +public: + void Entry(); + + NetPlayClient(const std::string& address, const u16 port, const std::string& name, NetPlayDiag* const npd = NULL); + ~NetPlayClient(); + + void GetPlayerList(std::string& list); + + // Send and receive pads values + bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues); + bool SetSelectedGame(const std::string& game); + void SendChatMessage(const std::string& msg); + bool StartGame(const std::string &path); + +private: + class Player + { + public: + Player(); + + PlayerId pid; + std::string name; + PadMapping pad_map[4]; + std::string revision; + }; + + unsigned int OnData(sf::Packet& packet); + + PlayerId m_pid; + std::map m_players; +}; + +#endif diff --git a/Source/Core/DolphinWX/Src/NetSockets.cpp b/Source/Core/DolphinWX/Src/NetSockets.cpp deleted file mode 100644 index 7441512ee7..0000000000 --- a/Source/Core/DolphinWX/Src/NetSockets.cpp +++ /dev/null @@ -1,607 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "NetSockets.h" -#include "NetWindow.h" - -//-------------------------------- -// GUI EVENTS -//-------------------------------- - -void NetEvent::AppendText(const wxString text) -{ - // I have the feeling SendEvent may be a bit safer/better... -#if 0 - SendEvent(ADD_TEXT, std::string(text.mb_str())); //NETPLAY: FIXME std::string(text.mb_str()) -#else - wxMutexGuiEnter(); - m_netptr->AppendText(text); - wxMutexGuiLeave(); -#endif -} - -void NetEvent::SendEvent(int EventType, const std::string text, int integer) -{ - wxCommandEvent event(wxEVT_HOST_COMMAND, wxID_ANY); - - event.SetId( EventType ); - event.SetInt( integer ); - event.SetString( wxString::FromAscii(text.c_str()) ); -#if ! wxCHECK_VERSION(2, 9, 0) - m_netptr->AddPendingEvent(event); -#endif -} - -//-------------------------------- -// SERVER SIDE THREAD -//-------------------------------- - -ServerSide::ServerSide(NetPlay* netptr, sf::SocketTCP socket, sf::SocketUDP socketUDP, int netmodel, std::string nick) - : wxThread() -{ - m_numplayers = 0; - m_data_received = false; - m_netmodel = netmodel; - m_socket = socket; - m_socketUDP = socketUDP; - m_netptr = netptr; - m_nick = nick; - Event = new NetEvent(m_netptr); -} - -char ServerSide::GetSocket(sf::SocketTCP Socket) -{ - for (int i=0; i < m_numplayers; i++) - { - if(m_client[i].socket == Socket) - return i; - } - - return 0xE; -} - -bool ServerSide::RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time) -{ - sf::SelectorUDP Selector; - sf::IPAddress Addr; - unsigned short Port; - Selector.Add(Socket); - - if (Selector.Wait(Time) > 0) - { - Socket.Receive(Data, Max, Recvd, Addr, Port); - return true; - } - else - { - return false; - } -} - -void *ServerSide::Entry() -{ - // Add listening socket - m_selector.Add(m_socket); - - while (1) - { - char nbSocketReady = m_selector.Wait(0.5); - - for (char i = 0; i < nbSocketReady; ++i) - { - m_CriticalSection.Enter(); - sf::SocketTCP Socket = m_selector.GetSocketReady(i); - if (Socket == m_socket) - { - // Incoming connection - Event->AppendText(_("*Connection Request... ")); - - sf::SocketTCP Incoming; - sf::IPAddress Address; - m_socket.Accept(Incoming, &Address); - - unsigned char sent = 0x12; - if ((m_netmodel == 0 && m_numplayers > 0) || m_numplayers == 3) - { - Incoming.Send((const char *)&sent, 1); // Tell it the server is full... - Incoming.Close(); // Then close the connection - - Event->AppendText(_(" Server is Full !\n")); - } - else - { - Event->AppendText(_(" Connection accepted\n")); - m_client[m_numplayers].socket = Incoming; - m_client[m_numplayers].address = Address; - - if (SyncValues(m_numplayers, Address)) - { - // Add it to the selector - m_selector.Add(Incoming); - Event->SendEvent(HOST_NEWPLAYER); - m_numplayers++; - } - else - { - Event->AppendText(_("ERROR : Unable to establish UDP connection !\n")); - Incoming.Close(); - } - } - } - else - { - unsigned char recv; - int socket_nb; - size_t recv_size; - sf::Socket::Status recv_status; - socket_nb = GetSocket(Socket); - - if ((recv_status = Socket.Receive((char *)&recv, 1, recv_size)) == sf::Socket::Done) - { -#ifdef NET_DEBUG - char recv_str[32]; - sprintf(recv_str, "received: 0x%02x | %c\n", recv, recv); - Event->AppendText(wxString::FromAscii(recv_str)); -#endif - OnServerData(socket_nb, recv); - } - else - { - if (recv_status == sf::Socket::Disconnected) - { - Event->SendEvent(HOST_PLAYERLEFT); - m_numplayers--; - - std::string player_left = m_client[socket_nb].nick; - Event->AppendText( wxString::FromAscii(StringFromFormat("*Player : %s left the game.\n\n", - player_left.c_str()).c_str()) ); - - // We need to adjust the struct... - for (int j = socket_nb; j < m_numplayers; j++) - { - m_client[j].socket = m_client[j+1].socket; - m_client[j].nick = m_client[j+1].nick; - m_client[j].ready = m_client[j+1].ready; - } - - // Send disconnected message to all - unsigned char send = 0x11; - unsigned int str_size = (int)player_left.size(); - - for (int j=0; j < m_numplayers ; j++) - { - m_client[j].socket.Send((const char*)&send, 1); - m_client[j].socket.Send((const char*)&str_size, 4); - m_client[j].socket.Send(player_left.c_str(), (int)str_size + 1); - } - } - else - { - // Hopefully this should never happen, the client is not - // Even warned that he is being dropped... - Event->SendEvent(HOST_ERROR, m_client[socket_nb].nick); - } - - m_selector.Remove(Socket); - Socket.Close(); - } - } - - m_CriticalSection.Leave(); - } - - if(TestDestroy()) - { - // Stop listening - m_socket.Close(); - - // Delete the Thread and close clients sockets - for (int i=0; i < m_numplayers ; i++) - m_client[i].socket.Close(); - - break; - } - } - - return NULL; -} - -bool ServerSide::SyncValues(unsigned char socketnb, sf::IPAddress Address) -{ - sf::SocketTCP Socket = m_client[socketnb].socket; - - std::string buffer_str = m_netptr->GetSelectedGame(); - char *buffer = NULL; - unsigned char init_number; - u32 buffer_size = (u32)buffer_str.size(); - size_t received; - bool errorUDP = false; - - // First, Send the number of connected clients & netmodel - Socket.Send((const char *)&m_numplayers, 1); - Socket.Send((const char *)&m_netmodel, 4); - - // Send the Game String - Socket.Send((const char *)&buffer_size, 4); - Socket.Send(buffer_str.c_str(), buffer_size + 1); - - // Send the host Nickname - buffer_size = (u32)m_nick.size(); - Socket.Send((const char *)&buffer_size, 4); - Socket.Send(m_nick.c_str(), buffer_size + 1); - - // Read client's UDP Port - Socket.Receive((char *)&m_client[m_numplayers].port, sizeof(short), received); - - // Read returned nickname - Socket.Receive((char *)&buffer_size, 4, received); - buffer = new char[buffer_size + 1]; - Socket.Receive(buffer, buffer_size + 1, received); - - m_client[socketnb].nick = std::string(buffer); - m_client[socketnb].ready = false; - - - // Test UDP Socket - - if (m_socketUDP.Send((const char*)&m_numplayers, 1, Address, m_client[m_numplayers].port) == sf::Socket::Done) - { - // Test UDP Socket Receive, 2s timeout - if (!RecvT(m_socketUDP, (char*)&init_number, 1, received, 2)) - { - ERROR_LOG(NETPLAY,"Connection to client timed out or closed"); - errorUDP = true; - } - } - else - { - ERROR_LOG(NETPLAY,"Failed to send info! closing connection!"); - errorUDP = true; - } - - // Check if the client has the game - Socket.Receive((char *)&init_number, 1, received); - - delete[] buffer; - - if (!errorUDP) - { - // Send to all connected clients - if (m_numplayers > 0) - { - unsigned char send = 0x10; - buffer_size = (int)m_client[socketnb].nick.size(); - for (int i=0; i < m_numplayers ; i++) - { - // Do not send to connecting player - if (i == socketnb) - continue; - - m_client[i].socket.Send((const char *)&send, 1); // Init new connection - m_client[i].socket.Send((const char *)&init_number, 1); // Send Game found ? - m_client[i].socket.Send((const char *)&buffer_size, 4); // Send client nickname - m_client[i].socket.Send(m_client[socketnb].nick.c_str(), buffer_size + 1); - } - } - Event->AppendText( wxString::FromAscii(StringFromFormat("*Connection established to %s (%s:%d)\n", - m_client[socketnb].nick.c_str(), Address.ToString().c_str(), m_client[m_numplayers].port).c_str())); - - if (init_number != 0x1F) // Not Found - //for (int i = 0; i < 4; i++) - //note for sl1nk3 : what is that for doing there? - Event->AppendText(_("WARNING : Game Not Found on Client Side !\n")); - - // UDP connecton successful - init_number = 0x16; - Socket.Send((const char *)&init_number, 1); - } - else // UDP Error, disconnect client - { - // UDP connecton failed - init_number = 0x17; - Socket.Send((const char *)&init_number, 1); - return false; - } - - return true; -} - -void ServerSide::Write(int socknb, const char *data, size_t size, long *ping) -{ - wxCriticalSectionLocker lock(m_CriticalSection); - - if (ping != NULL) - { - // Ask for ping - unsigned char value = 0x15; - size_t recv_size; - u32 four_bytes = 0x101A7FA6; - - Common::Timer timer; - timer.Start(); - - for (int i=0; i < m_numplayers ; i++) - { - m_client[i].socket.Send((const char*)&value, 1); - - timer.Update(); - m_client[i].socket.Send((const char*)&four_bytes, 4); - m_client[i].socket.Receive((char*)&four_bytes, 4, recv_size); - ping[i] = (long)timer.GetTimeDifference(); - } - - return; - } - - // Send the data safely, without intefering with another call - m_client[socknb].socket.Send(data, size); -} - -void ServerSide::WriteUDP(int socknb, const char *data, size_t size) -{ - wxCriticalSectionLocker lock(m_CriticalSection); - - m_socketUDP.Send(data, size, m_client[socknb].address, m_client[socknb].port); -} - -//-------------------------------- -// CLIENT SIDE THREAD -//-------------------------------- - -ClientSide::ClientSide(NetPlay* netptr, sf::SocketTCP socket, sf::SocketUDP socketUDP, std::string addr, std::string nick) - : wxThread() -{ - m_numplayers = 0; - m_data_received = false; - m_netmodel = 0; - m_socket = socket; - m_socketUDP = socketUDP; - m_port = m_socketUDP.GetPort(); - m_netptr = netptr; - m_nick = nick; - m_addr = addr; - Event = new NetEvent(m_netptr); -} - -bool ClientSide::RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time) -{ - sf::SelectorUDP Selector; - sf::IPAddress Addr; - unsigned short Port; - Selector.Add(Socket); - - if (Selector.Wait(Time) > 0) - { - Socket.Receive(Data, Max, Recvd, Addr, Port); - return true; - } - else - { - return false; - } -} - -void *ClientSide::Entry() -{ - Event->AppendText(_("*Connection Request... ")); - - // If we get here, the connection is already accepted, however the game may be full - if (SyncValues()) - { - // Tell the server if the client has the game - CheckGameFound(); - - // Check UDP connection - unsigned char value; - size_t val_sz; - m_socket.Receive((char *)&value, 1, val_sz); - if (value == 0x16) // UDP connection successful - { - Event->AppendText(_("Connection successful !\n")); - Event->AppendText( wxString::FromAscii( StringFromFormat("*Connection established to %s (%s)\n*Game is : %s\n", - m_hostnick.c_str(), m_addr.c_str(), m_selectedgame.c_str()).c_str())); - } - else - { - Event->AppendText(_("UDP Connection FAILED !\nERROR : Unable to establish UDP Connection, please Check UDP Port forwarding !\n")); - m_socket.Close(); - Event->SendEvent(HOST_ERROR); - return NULL; - } - } - else // Server is Full - { - m_socket.Close(); - Event->SendEvent(HOST_FULL); - return NULL; - } - - m_netptr->ChangeSelectedGame(m_selectedgame); - Event->SendEvent(HOST_NEWPLAYER, "NULL", m_netmodel); - Event->SendEvent(GUI_UPDATE); - - m_selector.Add(m_socket); - - while (1) - { - unsigned char recv; - size_t recv_size; - sf::Socket::Status recv_status; - - // we use a selector because of the useful timeout - if (m_selector.Wait(0.5) > 0) - { - m_CriticalSection.Enter(); - - if ((recv_status = m_socket.Receive((char *)&recv, 1, recv_size)) == sf::Socket::Done) - { -#ifdef NET_DEBUG - char recv_str[32]; - sprintf(recv_str, "received: 0x%02x | %c\n", recv, recv); - Event->AppendText(wxString::FromAscii(recv_str)); -#endif - OnClientData(recv); - } - else - { - if (recv_status == sf::Socket::Disconnected) - { - Event->SendEvent(HOST_DISCONNECTED); - } - else - { - Event->SendEvent(HOST_ERROR); - } - - m_selector.Remove(m_socket); - m_socket.Close(); - - return NULL; - } - - m_CriticalSection.Leave(); - } - - if(TestDestroy()) - { - m_socket.Close(); - - break; - } - } - - return NULL; -} - -bool ClientSide::SyncValues() -{ - unsigned int buffer_size = (int)m_nick.size(); - unsigned char byterecv; - bool errorUDP; - char *buffer = NULL; - size_t recv_size; - - unsigned short server_port; - std::string host = m_addr.substr(0, m_addr.find(':')); - TryParseInt(m_addr.substr(m_addr.find(':')+1).c_str(), (int *)&server_port); - - // First, Read the init number : nbplayers (0-2) or server full (0x12) - m_socket.Receive((char *)&m_numplayers, 1, recv_size); - if (m_numplayers == 0x12) - return false; - m_socket.Receive((char *)&m_netmodel, 4, recv_size); - - // Send client's UDP Port - // TODO : fix port sending. it sends the set port in the main window. not the actual using port - // when checked to use random this will , ofcourse , send wrong port - m_socket.Send((const char *)&m_port, sizeof(short)); - - // Send client's nickname - m_socket.Send((const char *)&buffer_size, 4); - m_socket.Send(m_nick.c_str(), buffer_size + 1); - - // Read the Game String - m_socket.Receive((char *)&buffer_size, 4, recv_size); - buffer = new char[buffer_size + 1]; - m_socket.Receive(buffer, buffer_size + 1, recv_size); - m_selectedgame = std::string(buffer); - - // Read the host Nickname - m_socket.Receive((char *)&buffer_size, 4, recv_size); - buffer = new char[buffer_size + 1]; - m_socket.Receive(buffer, buffer_size + 1, recv_size); - m_hostnick = std::string(buffer); - - - // Test UDP Socket - - if (m_socketUDP.Send((const char*)&m_numplayers, 1, host.c_str(), server_port) == sf::Socket::Done) - { - // Test UDP Socket Receive, 2s timeout - if (!RecvT(m_socketUDP, (char*)&byterecv, 1, recv_size, 2)) - { - errorUDP = true; - ERROR_LOG(NETPLAY,"Connection Timed Out or closed"); - } - } - else - errorUDP = true; - - delete[] buffer; - return true; -} - -void ClientSide::CheckGameFound() -{ - unsigned char send_value; - - // Check if the game selected by Host is in Client's Game List - m_netptr->IsGameFound(&send_value, m_selectedgame); - - if (send_value == 0x1F) // Found - { - m_socket.Send((const char *)&send_value, 1); - } - else - { - m_socket.Send((const char *)&send_value, 1); - - for (int i = 0; i < 2; i++) - { - Event->AppendText(wxT("WARNING : You do not have the Selected Game !\n")); - NOTICE_LOG(NETPLAY, "Game '%s' not found!", m_selectedgame.c_str()); - - } - } -} - -void ClientSide::Write(const char *data, size_t size, long *ping) -{ - wxCriticalSectionLocker lock(m_CriticalSection); - - if (ping != NULL) - { - // Ask for ping - unsigned char value = 0x15; - size_t recv_size; - int four_bytes = 0x101A7FA6; - - Common::Timer timer; - timer.Start(); - - m_socket.Send((const char*)&value, 1); - m_socket.Send((const char*)&four_bytes, 4); - m_socket.Receive((char*)&four_bytes, 4, recv_size); - - *ping = (long)timer.GetTimeElapsed(); - - return; - } - - m_socket.Send(data, size); -} - -void ClientSide::WriteUDP(const char *data, size_t size) -{ - wxCriticalSectionLocker lock(m_CriticalSection); - - unsigned short server_port; - std::string host = m_addr.substr(0, m_addr.find(':')); - TryParseInt(m_addr.substr(m_addr.find(':')+1).c_str(), (int *)&server_port); - - m_socketUDP.Send(data, size, host.c_str(), server_port); -} diff --git a/Source/Core/DolphinWX/Src/NetSockets.h b/Source/Core/DolphinWX/Src/NetSockets.h deleted file mode 100644 index bee5e1e0ec..0000000000 --- a/Source/Core/DolphinWX/Src/NetSockets.h +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _NETSOCKETS_H_ -#define _NETSOCKETS_H_ - -#include - -class NetPlay; - -#include "Common.h" -#include "NetStructs.h" - -#include - - -struct Clients { - std::string nick; - sf::SocketTCP socket; - unsigned short port; - sf::IPAddress address; - bool ready; -}; - -class NetEvent -{ - public: - NetEvent(NetPlay* netptr) { m_netptr = netptr; } - ~NetEvent() {}; - - void SendEvent(int EventType, std::string="NULL", int=NULL); - void AppendText(const wxString text); - - private: - NetPlay *m_netptr; -}; - -class ServerSide : public wxThread -{ - public: - ServerSide(NetPlay* netptr, sf::SocketTCP, sf::SocketUDP, int netmodel, std::string nick); - ~ServerSide() {}; - - virtual void *Entry(); - - void Write(int socknb, const char *data, size_t size, long *ping=NULL); - void WriteUDP(int socknb, const char *data, size_t size); - bool isNewPadData(u32 *netValues, bool current, int client=0); - - private: - bool SyncValues(unsigned char, sf::IPAddress); - bool RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time = 0); - char GetSocket(sf::SocketTCP Socket); - void OnServerData(int sock, unsigned char data); - void IsEveryoneReady(); - - NetPlay *m_netptr; - NetEvent *Event; - - u32 m_netvalues[3][3]; - bool m_data_received; // New Pad data received ? - - unsigned char m_numplayers; - int m_netmodel; - std::string m_nick; - - Clients m_client[3]; // Connected client objects - sf::SelectorTCP m_selector; - sf::SocketTCP m_socket; // Server 'listening' socket - sf::SocketUDP m_socketUDP; - - wxCriticalSection m_CriticalSection; -}; - -class ClientSide : public wxThread -{ - public: - ClientSide(NetPlay* netptr, sf::SocketTCP, sf::SocketUDP, std::string addr, std::string nick); - ~ClientSide() {} - - virtual void *Entry(); - - void Write(const char *data, size_t size, long *ping=NULL); - void WriteUDP(const char *data, size_t size); - bool isNewPadData(u32 *netValues, bool current, bool isVersus=true); - - private: - bool SyncValues(); - void CheckGameFound(); - void OnClientData(unsigned char data); - bool RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time=0); - - NetPlay *m_netptr; - NetEvent *Event; - - u32 m_netvalues[3][3]; - bool m_data_received; // New Pad data received ? - - unsigned char m_numplayers; - int m_netmodel; - std::string m_nick; - std::string m_hostnick; - std::string m_selectedgame; - - sf::SelectorTCP m_selector; - sf::SocketTCP m_socket; // Client I/O socket - sf::SocketUDP m_socketUDP; - unsigned short m_port; - std::string m_addr; // Contains the server addr - - wxCriticalSection m_CriticalSection; -}; - -#endif diff --git a/Source/Core/DolphinWX/Src/NetStructs.h b/Source/Core/DolphinWX/Src/NetStructs.h deleted file mode 100644 index a91bc8e55a..0000000000 --- a/Source/Core/DolphinWX/Src/NetStructs.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#ifndef _NETSTRUCTS_H -#define _NETSTRUCTS_H - -struct Netpads { - int nHi[128]; - int nLow[128]; -}; - -#endif // _NETSTRUCTS_H \ No newline at end of file diff --git a/Source/Core/DolphinWX/Src/NetWindow.cpp b/Source/Core/DolphinWX/Src/NetWindow.cpp index aa728b79f9..166f5ceb07 100644 --- a/Source/Core/DolphinWX/Src/NetWindow.cpp +++ b/Source/Core/DolphinWX/Src/NetWindow.cpp @@ -15,557 +15,373 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ -#include "NetSockets.h" +#include "NetPlay.h" #include "NetWindow.h" -#include "FileUtil.h" -// Main Frame window +#include -BEGIN_EVENT_TABLE(NetPlay, wxFrame) - EVT_BUTTON(ID_BUTTON_JOIN, NetPlay::OnJoin) - EVT_BUTTON(ID_BUTTON_HOST, NetPlay::OnHost) - EVT_BUTTON(ID_BUTTON_EXIT, NetPlay::OnDisconnect) +#define _connect_macro_( b, f, c, s ) (b)->Connect( wxID_ANY, (c), wxCommandEventHandler( f ), (wxObject*)0, (wxEvtHandler*)s ) - EVT_HOST_COMMAND(wxID_ANY, NetPlay::OnNetEvent) +#define NETPLAY_TITLEBAR "Dolphin NetPlay" - EVT_CHECKBOX(ID_READY, NetPlay::OnGUIEvent) - EVT_CHECKBOX(ID_RECORD, NetPlay::OnGUIEvent) - EVT_BUTTON(ID_CHANGEGAME, NetPlay::OnGUIEvent) - EVT_BUTTON(ID_BUTTON_GETIP, NetPlay::OnGUIEvent) - EVT_BUTTON(ID_BUTTON_GETPING, NetPlay::OnGUIEvent) - EVT_BUTTON(ID_BUTTON_CHAT, NetPlay::OnGUIEvent) - EVT_TEXT_ENTER(ID_CHAT, NetPlay::OnGUIEvent) - EVT_BUTTON(ID_BUTTON_QUIT, NetPlay::OnDisconnect) - EVT_CLOSE(NetPlay::OnQuit) +BEGIN_EVENT_TABLE(NetPlayDiag, wxFrame) + EVT_COMMAND(wxID_ANY, wxEVT_THREAD, NetPlayDiag::OnThread) END_EVENT_TABLE() -NetPlay::NetPlay(wxWindow* parent, std::string GamePaths, std::string GameNames) : - wxFrame(parent, wxID_ANY, _T("Net Play"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE & ~ wxMAXIMIZE_BOX & ~ wxCLOSE_BOX) +NetPlay* netplay_ptr = NULL; + +NetPlaySetupDiag::NetPlaySetupDiag(wxWindow* parent, const CGameListCtrl* const game_list) + : wxFrame(parent, wxID_ANY, wxT(NETPLAY_TITLEBAR), wxDefaultPosition, wxDefaultSize) + , m_game_list(game_list) { - m_selectedGame = 'a'; m_hostaddr = 'a'; - m_games = GameNames; m_paths = GamePaths; - m_isHosting = 2; m_ready = m_clients_ready = false; - m_loopframe = m_frame = m_NetModel = m_numClients = 0; + //PanicAlert("ALERT: NetPlay is not 100%% functional !!!!"); - DrawGUI(); -} + wxPanel* const panel = new wxPanel(this); -NetPlay::~NetPlay() -{ - ConfigIni.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); + // 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")); - ConfigIni.Set("Netplay", "Nickname", m_nick); - ConfigIni.Set("Netplay", "UsedPort", (int)m_port); - ConfigIni.Set("Netplay", "LastIP", m_address); + wxBoxSizer* const nick_szr = new wxBoxSizer(wxHORIZONTAL); + nick_szr->Add(nick_lbl, 0, wxCENTER); + nick_szr->Add(m_nickname_text, 0, wxALL, 5); - ConfigIni.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX)); -} -void NetPlay::OnJoin(wxCommandEvent& WXUNUSED(event)) -{ - unsigned short server_port; + // tabs + wxNotebook* const notebook = new wxNotebook(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize); + wxPanel* const connect_tab = new wxPanel(notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize); + notebook->AddPage(connect_tab, wxT("Connect")); + wxPanel* const host_tab = new wxPanel(notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize); + notebook->AddPage(host_tab, wxT("Host")); - m_address = std::string(m_ConAddr->GetValue().mb_str()); - m_nick = std::string(m_SetNick->GetValue().mb_str()); - sf::IPAddress host = m_address.substr(0, m_address.find(':')); - std::string port_str = m_address.substr(m_address.find(':') + 1); - - TryParseUInt(port_str, (u32*)&server_port); // Server port - TryParseUInt((const char *)m_SetPort->GetValue().mb_str(), (u32*)&m_port); // User port - - if (m_nick.size() > 255) - m_nick = m_nick.substr(0 , 255); - - SetTitle(wxT("Net Play : Connecting to Host...")); - - // Create the client socket - sf::SocketTCP sock_client; - sf::SocketUDP sock_client_UDP; - - if (sock_client.Connect(server_port, host, 1.5) == sf::Socket::Done) + // connect tab { - // Try to Bind the UDP Socket - if (sock_client_UDP.Bind(m_port)) - { - m_sock_client = new ClientSide(this, sock_client, sock_client_UDP, m_address, m_nick); - m_sock_client->Create(); - m_sock_client->Run(); + 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")); + 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")); - // Create the GUI - m_isHosting = false; - DrawNetWindow(); - } - else - { - SetTitle(wxT("Net Play")); - PanicAlert("Can't Bind UDP socket on the specified Port: %d ! \n" - "Make sure port is forwarded and not in use !", m_port); - } + wxButton* const connect_btn = new wxButton(connect_tab, wxID_ANY, wxT("Connect")); + //connect_button->Disable(); + _connect_macro_(connect_btn, NetPlaySetupDiag::OnJoin, wxEVT_COMMAND_BUTTON_CLICKED, this); + + wxStaticText* const alert_lbl = new wxStaticText(connect_tab, wxID_ANY + , wxT("ALERT:\n\nNetPlay will currently only work properly when using the following settings:\n") + wxT(" - Dual Core [OFF]\n - DSP LLE Plugin\n - DSPLLE on thread [OFF]\n - Manually set the exact number of controller that will be used to [Standard Controller]") + wxT("\n\nAll players should try to use the same Dolphin version and settings.") + wxT("\nDisable all memory cards or send them to all players before starting.") + wxT("\nWiimote support has not been implemented.\nWii games will likely desync for other reasons as well.") + wxT("\n\nYou must forward TCP port to host!!") + , wxDefaultPosition, wxDefaultSize); + + wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL); + top_szr->Add(ip_lbl, 0, wxCENTER | wxRIGHT, 5); + top_szr->Add(m_connect_ip_text, 3); + top_szr->Add(port_lbl, 0, wxCENTER | wxRIGHT | wxLEFT, 5); + top_szr->Add(m_connect_port_text, 1); + + wxBoxSizer* const con_szr = new wxBoxSizer(wxVERTICAL); + con_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5); + con_szr->AddStretchSpacer(1); + con_szr->Add(alert_lbl, 0, wxLEFT | wxRIGHT | wxEXPAND, 5); + con_szr->AddStretchSpacer(1); + con_szr->Add(connect_btn, 0, wxALL | wxALIGN_RIGHT, 5); + + connect_tab->SetSizerAndFit(con_szr); } - else + + // host tab { - SetTitle(wxT("Net Play")); - PanicAlert("Can't connect to the specified IP Address ! \nMake sure Hosting port is forwarded !"); - } -} + 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")); -void NetPlay::OnHost(wxCommandEvent& WXUNUSED(event)) -{ - TryParseInt(m_SetPort->GetValue().mb_str(), (int*)&m_port); + wxButton* const host_btn = new wxButton(host_tab, wxID_ANY, wxT("Host")); + //host_button->Disable(); + _connect_macro_(host_btn, NetPlaySetupDiag::OnHost, wxEVT_COMMAND_BUTTON_CLICKED, this); - m_nick = std::string(m_SetNick->GetValue().mb_str()); + m_game_lbox = new wxListBox(host_tab, wxID_ANY); + std::istringstream ss(game_list->GetGameNames()); + std::string game; + while (std::getline(ss,game)) + m_game_lbox->Append(wxString(game.c_str(), *wxConvCurrent)); - if (m_GameList->GetSelection() == wxNOT_FOUND) { - PanicAlert("No Game Selected ! Please select a Game..."); - return; - } - if (!m_SetPort->GetValue().size() || m_port < 1000 || m_port > 65535) { - PanicAlert("Bad Port entered (%d) ! Please enter a working socket port...", m_port); - return; - } - if (m_nick.size() > 255) - m_nick = m_nick.substr(0 , 255); + wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL); + top_szr->Add(port_lbl, 0, wxCENTER | wxRIGHT, 5); + top_szr->Add(m_host_port_text, 0); - m_NetModel = m_NetMode->GetSelection(); - m_selectedGame = std::string(m_GameList_str[m_GameList->GetSelection()].mb_str()); - NOTICE_LOG(NETPLAY,"Game has been set to : %s \n",m_selectedGame.c_str()); + wxBoxSizer* const host_szr = new wxBoxSizer(wxVERTICAL); + host_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5); + host_szr->Add(m_game_lbox, 1, wxLEFT | wxRIGHT | wxEXPAND, 5); + host_szr->Add(host_btn, 0, wxALL | wxALIGN_RIGHT, 5); - // Create the listening socket - sf::SocketTCP sock_server; - sf::SocketUDP sock_server_UDP; - - // Start the listening socket and bind UDP socket port - if (sock_server.Listen(m_port) && sock_server_UDP.Bind(m_port)) - { - m_sock_server = new ServerSide(this, sock_server, sock_server_UDP, m_NetModel, m_nick); - m_sock_server->Create(); - m_sock_server->Run(); - - // Create the GUI - m_isHosting = true; - DrawNetWindow(); - m_Logging->AppendText(wxString::Format(wxT("WARNING : Hosting requires port to be forwarded in firewall!\n") - wxT("*Creation Successful on port %d : Waiting for peers...\n"), m_port)); - } - else - { - PanicAlert("Could not listen at specified port !\nMake sure hosting port is not in use !"); - return; - } -} - -void NetPlay::DrawGUI() -{ - int str_end = -1; - int str_start = -1; - wxArrayString netmodes_str; - - for(int i = 0; i < (int)m_games.size(); i++) - { - str_start = str_end + 1; - str_end = (int)m_games.find('\n', str_start); - std::string buffer = m_games.substr(str_start, str_end - str_start); - - if (str_end == (int)std::string::npos || buffer.size() < 1) - break; // we reached the end of the string - - m_GameList_str.Add(wxString(buffer.c_str(), *wxConvCurrent)); + host_tab->SetSizerAndFit(host_szr); } - netmodes_str.Add(wxT("P2P Versus (2 players, faster)")); - // TODO : netmodes_str.Add(wxT("Server Mode (4 players, slower)")); + // bottom row + wxButton* const quit_btn = new wxButton(panel, wxID_ANY, wxT("Quit")); + _connect_macro_(quit_btn, NetPlaySetupDiag::OnQuit, wxEVT_COMMAND_BUTTON_CLICKED, this); - wxPanel *panel = new wxPanel(this); + // main sizer + wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); + main_szr->Add(nick_szr, 0, wxALL | wxALIGN_RIGHT, 5); + main_szr->Add(notebook, 1, wxLEFT | wxRIGHT | wxEXPAND, 5); + main_szr->Add(quit_btn, 0, wxALL | wxALIGN_RIGHT, 5); - // Tabs - m_Notebook = new wxNotebook(panel, ID_NOTEBOOK, wxDefaultPosition, wxDefaultSize); - m_Tab_Connect = new wxPanel(m_Notebook, ID_TAB_CONN, wxDefaultPosition, wxDefaultSize); - m_Notebook->AddPage(m_Tab_Connect, wxT("Connect")); - m_Tab_Host = new wxPanel(m_Notebook, ID_TAB_HOST, wxDefaultPosition, wxDefaultSize); - m_Notebook->AddPage(m_Tab_Host, wxT("Host")); + panel->SetSizerAndFit(main_szr); - // Tow window, Nickname & Port settings - m_SetNick_text = new wxStaticText(panel, wxID_ANY, wxT(" Nickname : "), wxDefaultPosition, wxDefaultSize); - m_SetNick = new wxTextCtrl(panel, ID_SETNICK, wxT("LOLWUT!"), wxDefaultPosition, wxDefaultSize); - m_SetPort_text = new wxStaticText(panel, wxID_ANY, wxT(" Port to Use : "), wxDefaultPosition, wxDefaultSize); - m_SetPort = new wxTextCtrl(panel, ID_SETPORT, wxT("12345"), wxDefaultPosition, wxDefaultSize); - - // CONNECTION TAB - m_ConAddr_text = new wxStaticText(m_Tab_Connect, wxID_ANY, wxT(" IP Address :"), wxDefaultPosition, wxDefaultSize); - m_ConAddr = new wxTextCtrl(m_Tab_Connect, ID_CONNADDR, wxT("127.0.0.1:12345"), wxDefaultPosition, wxSize(250,20), 0); - m_UseRandomPort = new wxCheckBox(m_Tab_Connect, ID_USE_RANDOMPORT, wxT("Use random client port for connection")); - m_JoinGame = new wxButton(m_Tab_Connect, ID_BUTTON_JOIN, wxT("Connect"), wxDefaultPosition, wxDefaultSize); - m_ExitWindowC = new wxButton(m_Tab_Connect, ID_BUTTON_EXIT, wxT("Quit"), wxDefaultPosition, wxDefaultSize); + //wxBoxSizer* const diag_szr = new wxBoxSizer(wxVERTICAL); + //diag_szr->Add(panel); + //SetSizerAndFit(diag_szr); - // Sizers CONNECT - wxBoxSizer* sConnectTop = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sConnectSizer = new wxBoxSizer(wxVERTICAL); - - sConnectTop->Add(m_ConAddr_text, 0, wxALL|wxALIGN_CENTER, 5); - sConnectTop->Add(m_ConAddr, 1, wxALL|wxEXPAND, 5); - sConnectTop->Add(m_JoinGame, 0, wxALL|wxALIGN_RIGHT, 5); - sConnectSizer->Add(sConnectTop, 0, wxALL|wxEXPAND, 5); - sConnectSizer->Add(m_UseRandomPort, 0, wxALL|wxALIGN_CENTER, 5); - sConnectSizer->Add(m_ExitWindowC, 0, wxALL|wxALIGN_CENTER, 5); - - m_Tab_Connect->SetSizer(sConnectSizer); - - // HOSTING TAB - m_GameList_text = new wxStaticText(m_Tab_Host, wxID_ANY, - wxT("Warning: Use a forwarded port ! Select Game and press Host :"), wxDefaultPosition, wxDefaultSize); - m_GameList = new wxListBox(m_Tab_Host, ID_GAMELIST, wxDefaultPosition, wxDefaultSize, - m_GameList_str, wxLB_SINGLE | wxLB_NEEDED_SB); - m_HostGame = new wxButton(m_Tab_Host, ID_BUTTON_HOST, wxT("Host"), wxDefaultPosition, wxDefaultSize); - m_ExitWindowH = new wxButton(m_Tab_Host, ID_BUTTON_EXIT, wxT("Quit"), wxDefaultPosition, wxDefaultSize); - m_NetMode = new wxChoice(m_Tab_Host, ID_NETMODE, wxDefaultPosition, wxDefaultSize, netmodes_str, 0, wxDefaultValidator); - m_NetMode->SetSelection(0); - - - // Sizers HOST - wxBoxSizer *sHostBox = new wxBoxSizer(wxVERTICAL); - wxBoxSizer *sHostBottom = new wxBoxSizer(wxHORIZONTAL); - - sHostBottom->Add(m_NetMode, 0, wxALL|wxALIGN_CENTER, 5); - sHostBottom->AddStretchSpacer(); - sHostBottom->Add(m_HostGame, 0, wxALL, 10); - sHostBottom->Add(m_ExitWindowH, 0, wxALL|wxALIGN_CENTER, 5); - - sHostBox->Add(m_GameList_text, 0, wxALL|wxALIGN_CENTER, 5); - sHostBox->Add(m_GameList, 1, wxALL|wxEXPAND, 6); - sHostBox->Add(sHostBottom, 0, wxALL|wxEXPAND, 1); - - - m_Tab_Host->SetSizer(sHostBox); - - // Main sizers - wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sMain_top = new wxBoxSizer(wxHORIZONTAL); - - sMain_top->Add(m_SetNick_text, 0, wxALL|wxALIGN_CENTER, 3); - sMain_top->Add(m_SetNick, 1, wxALL|wxALIGN_CENTER, 3); - sMain_top->AddStretchSpacer(); - sMain_top->Add(m_SetPort_text, 0, wxALL|wxALIGN_CENTER, 3); - sMain_top->Add(m_SetPort, 1, wxALL|wxALIGN_CENTER, 3); - - sMain->Add(sMain_top, 0, wxALL|wxEXPAND, 5); - sMain->Add(m_Notebook, 1, wxALL|wxEXPAND, 5); - - // Adjust panel to window's size, and set resizing minimum boundaries - panel->SetSizerAndFit(sMain); - sMain->SetSizeHints((wxWindow*)this); - - if (ConfigIni.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX))) - { - ConfigIni.Get("Netplay", "Nickname", &m_nick, "Unnamed"); - ConfigIni.Get("Netplay", "UsedPort", (int*)&m_port, 12345); - ConfigIni.Get("Netplay", "LastIP", &m_address, "127.0.0.1:54321"); - - m_SetNick->SetValue(wxString::FromAscii(m_nick.c_str())); - m_SetPort->SetValue(wxString::Format(wxT("%d"), m_port)); - m_ConAddr->SetValue(wxString::FromAscii(m_address.c_str())); - } - - Center(); Show(); -} - -void NetPlay::DrawNetWindow() -{ - // Remove everything from the precedent GUI :D - DestroyChildren(); - - SetTitle(wxT("Net Play : Connection Window")); - - wxPanel *panel = new wxPanel(this); - wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sTop = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* sBottom = new wxBoxSizer(wxHORIZONTAL); - - m_Game_str = new wxButton(panel, wxID_ANY, wxT(" Game : "), wxDefaultPosition, wxSize(400, 25), wxBU_LEFT); - m_Game_str->Disable(); - - m_Logging = new wxTextCtrl(panel, ID_LOGGING_TXT, wxEmptyString, - wxDefaultPosition, wxSize(400, 250), - wxTE_RICH2 | wxTE_MULTILINE | wxTE_READONLY); - - m_Chat = new wxTextCtrl(panel, ID_CHAT, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); - m_Chat_ok = new wxButton(panel, ID_BUTTON_CHAT, wxT("Send"));; - - m_Ready = new wxCheckBox(panel, ID_READY, wxT("Click here when ready"), wxDefaultPosition, wxDefaultSize, 0); - m_RecordGame = new wxCheckBox(panel, ID_RECORD, wxT("Record Game Input"), wxDefaultPosition, wxDefaultSize, 0); - // TODO: Fix the recording ? - m_RecordGame->Disable(); - - m_ConInfo_text = new wxStaticText(panel, ID_CONNINFO_TXT, wxT(" Fps : 0 | Ping : 00 ms")); - m_GetPing = new wxButton(panel, ID_BUTTON_GETPING, wxT("Ping"), wxDefaultPosition, wxDefaultSize); - m_Disconnect = new wxButton(panel, ID_BUTTON_QUIT, wxT("Disconnect"), wxDefaultPosition, wxDefaultSize); - - wxBoxSizer* sChat = new wxBoxSizer(wxHORIZONTAL); - - sTop->Add(m_Game_str, 0, wxALL|wxEXPAND, 1); - sTop->Add(m_Logging, 1, wxALL|wxEXPAND, 5); - sChat->Add(m_Chat, 1, wxALL|wxEXPAND, 2); - sChat->Add(m_Chat_ok, 0, wxALL, 2); - sTop->Add(sChat, 0, wxALL|wxEXPAND, 2); - - wxBoxSizer* sBottom0 = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sBottom1 = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sBottomM = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sBottom2 = new wxBoxSizer(wxVERTICAL); - - sBottom0->Add(m_Ready, 0, wxALL, 5); - sBottom0->Add(m_RecordGame, 0, wxALL, 5); - sBottomM->Add(m_ConInfo_text, 0, wxALL, 5); - sBottom1->Add(m_Disconnect, 0, wxALL|wxALIGN_LEFT, 5); - sBottom1->AddStretchSpacer(1); - sBottom1->Add(m_GetPing, 0, wxALL|wxALIGN_RIGHT, 5); - - sBottom2->Add(sBottom0, 0, wxALL, 0); - sBottom2->Add(sBottomM, 0, wxALL | wxALIGN_LEFT, 0); - sBottom2->Add(sBottom1, 0, wxALL | wxEXPAND, 5); - - sBottom->Add(sBottom2, 2, wxALL | wxEXPAND | wxALIGN_CENTER, 0); - - if (m_isHosting) - { - m_wtfismyip = new wxButton(panel, ID_BUTTON_GETIP, wxT("What is my IP")); - m_ChangeGame = new wxButton(panel, ID_CHANGEGAME, wxT("Change Game")); - - wxStaticBoxSizer* sBottom3 = new wxStaticBoxSizer(wxVERTICAL, panel, wxT("Host")); - - sBottom3->Add(m_ChangeGame, 0, wxALL | wxEXPAND, 5); - sBottom3->Add(m_wtfismyip, 0, wxALL | wxEXPAND, 5); - sBottom->Add(sBottom3, 1, wxALL | wxEXPAND, 0); - - UpdateNetWindow(false); - } - - sMain->Add(sTop, 1, wxALL | wxEXPAND, 5); - sMain->Add(sBottom, 0, wxALL | wxEXPAND | wxALIGN_CENTER, 2); - - panel->SetSizerAndFit(sMain); - sMain->SetSizeHints((wxWindow*)this); + main_szr->SetSizeHints(this); + Center(); Show(); } -// String of the type : FPSxPINGxFRAME_DELAY -void NetPlay::UpdateNetWindow(bool update_infos, wxString infos) +void NetPlaySetupDiag::OnHost(wxCommandEvent& event) { - std::vector str_arr; + // warning removal + event.GetId(); - if (update_infos) + if (::netplay_ptr) { - SplitString(std::string(infos.mb_str()), "x", str_arr); + PanicAlert("A NetPlay window is already open!!"); + return; + } - m_ConInfo_text->SetLabel - (wxString::FromAscii(StringFromFormat(" Fps : %s | Ping : %s | Frame Delay : %s", - str_arr[0].c_str(), str_arr[1].c_str(), - str_arr[2].c_str()).c_str()) ); + if (-1 == m_game_lbox->GetSelection()) + { + PanicAlert("You must choose a game!!"); + return; + } + + std::string game(m_game_lbox->GetStringSelection().mb_str()); + + NetPlayDiag* const npd = new NetPlayDiag(m_parent, m_game_list, game, true); + unsigned long port = 0; + m_host_port_text->GetValue().ToULong(&port); + ::netplay_ptr = new NetPlayServer(u16(port) + , std::string(m_nickname_text->GetValue().mb_str()), npd, game); + if (::netplay_ptr->is_connected) + { + //NetPlayServerDiag* const npsd = + npd->Show(); + Destroy(); } else { - m_critical.Enter(); - //m_Game_str->SetLabel(wxString::Format(wxT(" Game : %s"), m_selectedGame.c_str())); - m_Game_str->SetLabel(wxString::FromAscii(std::string("Game " + m_selectedGame).c_str())); - m_critical.Leave(); + PanicAlert("Failed to Listen!!"); + npd->Destroy(); + // dialog will delete netplay + //delete ::netplay_ptr; } } -void NetPlay::OnGUIEvent(wxCommandEvent& event) +void NetPlaySetupDiag::OnJoin(wxCommandEvent& event) { - unsigned char value;; - switch (event.GetId()) + // warning removal + event.GetId(); + + if (::netplay_ptr) { - case ID_READY: - { - std::string buffer; - value = 0x40; - - if (!m_ready) - buffer = ">> "+m_nick+" is now ready !\n"; - else - buffer = ">> "+m_nick+" is now Unready !\n"; - - m_ready = !m_ready; - m_Disconnect->Enable(!(m_ready)); - - if (m_isHosting == 1) - { - m_ChangeGame->Enable(!(m_ready)); - - if (m_numClients > 0) - { - int buffer_size = (int)buffer.size(); - for (int i=0; i < m_numClients ; i++) - { - m_sock_server->Write(i, (const char*)&value, 1); - - m_sock_server->Write(i, (const char*)&buffer_size, 4); - m_sock_server->Write(i, buffer.c_str(), buffer_size + 1); - } - } - - m_Logging->AppendText(wxString::FromAscii(buffer.c_str())); - - // Everyone is ready - if (m_ready && m_clients_ready) - LoadGame(); - } - else { - if (m_numClients > 0) - m_sock_client->Write((const char*)&value, 1); // 0x40 -> Ready - } - break; - } - case ID_BUTTON_GETIP: - { - if (m_numClients == 0) // Get IP Address from the Internet - { - // simple IP address caching - if (m_hostaddr.at(0) != 'a') - { - m_Logging->AppendText(wxString::FromAscii(m_hostaddr.c_str())); - return; - } - - char buffer[8]; - sprintf(buffer, "%d", m_port); - - m_hostaddr = "> Your IP is : " + sf::IPAddress::GetPublicAddress().ToString() + - ':' + std::string(buffer) + '\n'; - m_Logging->AppendText(wxString::FromAscii(m_hostaddr.c_str())); - } - else // Ask client to send server IP - { - value = 0x20; - m_sock_server->Write(0, (const char*)&value, 1); - } - break; - } - case ID_BUTTON_GETPING: - { - if (m_numClients == 0) - return; - - long ping[3] = {0}; - float fping; - - if (m_isHosting == 1) { - m_sock_server->Write(0, 0, 0, ping); - fping = (ping[0]+ping[1]+ping[2])/(float)m_numClients; - } - else { - m_sock_client->Write(0, 0, ping); - fping = ping[0]; - } - - UpdateNetWindow( true, wxString::Format(wxT("000x%fx%d"), fping, (int)ceil(fping/(1000.0/60.0))) ); - break; - } - case ID_BUTTON_CHAT: - case ID_CHAT: - { - value = 0x30; - // TODO : there seems to be a random bug here that i can't reproduce... looked like a loop bug :/ - wxString chat_str = wxString::Format(wxT("> %s : %s\n"), wxString(m_nick.c_str(), wxConvUTF8).c_str() , m_Chat->GetValue().c_str() ); - int chat_size = (int)chat_str.size(); - if(chat_size-m_nick.size()-6 > 0) - { - m_Chat->Clear(); - - // If there's no distant connection, we write but we don't send - if (m_numClients == 0) { - m_Logging->AppendText(chat_str); - return; - } - // Max size that we handle is 1024, there's no need for more - if ((chat_str.size()+1) * sizeof(char) > 1024) { - m_Logging->AppendText(wxT("ERROR : Packet too large !\n")); - return; - } - - // Send to all - if (m_isHosting == 1) - { - for (int i=0; i < m_numClients ; i++) { - // Send Chat command - m_sock_server->Write(i, (const char*)&value, 1); // 0x30 -> Chat - - // Send Chat string - m_sock_server->Write(i, (const char*)&chat_size, 4); - m_sock_server->Write(i, chat_str.mb_str(), chat_size + 1); - } - } - else { - m_sock_client->Write((const char*)&value, 1); - m_sock_client->Write((const char*)&chat_size, 4); - m_sock_client->Write(chat_str.mb_str(), chat_size + 1); - } - - // Do not wait for the server, just write as soon as sent - m_Logging->AppendText(chat_str); - } - - break; - } - case ID_RECORD: - // TODO : - // Record raw pad data - break; - case ID_CHANGEGAME: - { - GameListPopup PopUp(this, m_GameList_str); - PopUp.ShowModal(); - break; - } + PanicAlert("A NetPlay window is already open!!"); + return; } -} - -// GameList popup window - -BEGIN_EVENT_TABLE(GameListPopup, wxDialog) - EVT_BUTTON(wxID_OK, GameListPopup::OnButtons) - EVT_BUTTON(wxID_CANCEL, GameListPopup::OnButtons) -END_EVENT_TABLE() - -GameListPopup::GameListPopup(NetPlay *parent, wxArrayString GameNames) : - wxDialog(parent, wxID_ANY, _T("Choose a Game :"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) -{ - m_netParent = parent; - m_GameList_str = GameNames; - m_GameList = new wxListBox(this, ID_GAMELIST, wxDefaultPosition, wxSize(300, 250), - GameNames, wxLB_SINGLE | wxLB_SORT | wxLB_NEEDED_SB); - m_Cancel = new wxButton(this, wxID_CANCEL, wxT("Cancel"), wxDefaultPosition, wxDefaultSize); - m_Accept = new wxButton(this, wxID_OK, wxT("Apply"), wxDefaultPosition, wxDefaultSize); - - wxBoxSizer* sButtons = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL); - - sButtons->Add(m_Cancel, 0, wxALL, 0); - sButtons->AddStretchSpacer(1); - sButtons->Add(m_Accept, 0, wxALL | wxALIGN_RIGHT, 0); - - sMain->Add(m_GameList, 0, wxALL | wxEXPAND, 2); - sMain->Add(sButtons, 0, wxALL | wxEXPAND, 5); - - SetSizerAndFit(sMain); - Center(); Layout(); Show(); -} - -void GameListPopup::OnButtons(wxCommandEvent& event) -{ - switch (event.GetId()) + NetPlayDiag* const npd = new NetPlayDiag(m_parent, m_game_list, ""); + unsigned long port = 0; + m_connect_port_text->GetValue().ToULong(&port); + ::netplay_ptr = new NetPlayClient(std::string(m_connect_ip_text->GetValue().mb_str()) + , (u16)port, std::string(m_nickname_text->GetValue().mb_str()), npd); + if (::netplay_ptr->is_connected) { - case wxID_OK: - if (m_GameList->GetSelection() != wxNOT_FOUND) - m_netParent->ChangeSelectedGame(std::string(m_GameList_str[m_GameList->GetSelection()].mb_str())); + //NetPlayServerDiag* const npsd = + npd->Show(); Destroy(); - break; - case wxID_CANCEL: - Destroy(); - break; + } + else + { + //PanicAlert("Failed to Connect!!"); + npd->Destroy(); + // dialog will delete netplay + //delete ::netplay_ptr; } } +void NetPlaySetupDiag::OnQuit(wxCommandEvent& event) +{ + // warning removal + event.GetId(); + + Destroy(); +} + +NetPlayDiag::NetPlayDiag(wxWindow* parent, const CGameListCtrl* const game_list + , const std::string& game, const bool is_hosting) + : wxFrame(parent, wxID_ANY, wxT(NETPLAY_TITLEBAR), wxDefaultPosition, wxDefaultSize) + , m_game_list(game_list) + , m_selected_game(game) +{ + wxPanel* const panel = new wxPanel(this); + + // top crap + m_game_btn = new wxButton(panel, wxID_ANY + , wxString(m_selected_game.c_str(), *wxConvCurrent).Prepend(wxT(" Game : ")), wxDefaultPosition, wxDefaultSize, wxBU_LEFT); + m_game_btn->Disable(); + + // middle crap + + // chat + m_chat_text = new wxTextCtrl(panel, wxID_ANY, wxEmptyString + , wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxTE_MULTILINE); + + m_chat_msg_text = new wxTextCtrl(panel, wxID_ANY, wxEmptyString + , wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); + _connect_macro_(m_chat_msg_text, NetPlayDiag::OnChat, wxEVT_COMMAND_TEXT_ENTER, this); + + wxButton* const chat_msg_btn = new wxButton(panel, wxID_ANY, wxT("Send")); + _connect_macro_(chat_msg_btn, NetPlayDiag::OnChat, wxEVT_COMMAND_BUTTON_CLICKED, this); + + wxBoxSizer* const chat_msg_szr = new wxBoxSizer(wxHORIZONTAL); + chat_msg_szr->Add(m_chat_msg_text, 1); + chat_msg_szr->Add(chat_msg_btn, 0); + + wxStaticBoxSizer* const chat_szr = new wxStaticBoxSizer(wxVERTICAL, panel, wxT("Chat")); + chat_szr->Add(m_chat_text, 1, wxEXPAND); + chat_szr->Add(chat_msg_szr, 0, wxEXPAND | wxTOP, 5); + + m_player_lbox = new wxListBox(panel, wxID_ANY, wxDefaultPosition, wxSize(192,-1)); + + wxStaticBoxSizer* const player_szr = new wxStaticBoxSizer(wxVERTICAL, panel, wxT("Players")); + player_szr->Add(m_player_lbox, 1, wxEXPAND); + // player list + if (is_hosting) + { + wxButton* const player_config_btn = new wxButton(panel, wxID_ANY, wxT("Configure Pads [not implemented]")); + player_config_btn->Disable(); + player_szr->Add(player_config_btn, 0, wxEXPAND | wxTOP, 5); + } + + wxBoxSizer* const mid_szr = new wxBoxSizer(wxHORIZONTAL); + mid_szr->Add(chat_szr, 1, wxEXPAND | wxRIGHT, 5); + mid_szr->Add(player_szr, 0, wxEXPAND); + + // bottom crap + wxButton* const quit_btn = new wxButton(panel, wxID_ANY, wxT("Quit")); + _connect_macro_(quit_btn, NetPlayDiag::OnQuit, wxEVT_COMMAND_BUTTON_CLICKED, this); + + wxBoxSizer* const bottom_szr = new wxBoxSizer(wxHORIZONTAL); + if (is_hosting) + { + wxButton* const start_btn = new wxButton(panel, wxID_ANY, wxT("Start")); + _connect_macro_(start_btn, NetPlayDiag::OnStart, wxEVT_COMMAND_BUTTON_CLICKED, this); + bottom_szr->Add(start_btn); + } + + bottom_szr->AddStretchSpacer(1); + bottom_szr->Add(quit_btn); + + // main sizer + wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL); + main_szr->Add(m_game_btn, 0, wxEXPAND | wxALL, 5); + main_szr->Add(mid_szr, 1, wxEXPAND | wxLEFT | wxRIGHT, 5); + main_szr->Add(bottom_szr, 0, wxEXPAND | wxALL, 5); + + panel->SetSizerAndFit(main_szr); + + main_szr->SetSizeHints(this); + SetSize(512, 512-128); + + Center(); +} + +NetPlayDiag::~NetPlayDiag() +{ + if (::netplay_ptr) + { + delete netplay_ptr; + ::netplay_ptr = NULL; + } +} + +void NetPlayDiag::OnChat(wxCommandEvent& event) +{ + // warning removal + event.GetId(); + + wxString s = m_chat_msg_text->GetValue(); + + if (s.Length()) + { + ::netplay_ptr->SendChatMessage(std::string(s.mb_str())); + m_chat_text->AppendText(s.Prepend(wxT(" >> ")).Append(wxT('\n'))); + m_chat_msg_text->Clear(); + } +} + +void NetPlayDiag::OnStart(wxCommandEvent& event) +{ + // warning removal + event.GetId(); + + // find path for selected game + std::string ntmp, ptmp, path; + std::istringstream nss(m_game_list->GetGameNames()), pss(m_game_list->GetGamePaths()); + + while(std::getline(nss,ntmp)) + { + std::getline(pss,ptmp); + if (m_selected_game == ntmp) + { + path = ptmp; + break; + } + } + + if (path.length()) + ::netplay_ptr->StartGame(path); + else + PanicAlert("Game not found!!"); +} + +void NetPlayDiag::OnQuit(wxCommandEvent& event) +{ + // warning removal + event.GetId(); + + Destroy(); +} + +// update gui +void NetPlayDiag::OnThread(wxCommandEvent& event) +{ + // warning removal + event.GetId(); + + // player list + std::string tmps; + ::netplay_ptr->GetPlayerList(tmps); + + m_player_lbox->Clear(); + std::istringstream ss(tmps); + while (std::getline(ss, tmps)) + m_player_lbox->Append(wxString(tmps.c_str(), *wxConvCurrent)); + + // update selected game :/ + if (45 == event.GetId()) + { + m_selected_game.assign(event.GetString().mb_str()); + m_game_btn->SetLabel(event.GetString().Prepend(wxT(" Game : "))); + } + + // chat messages + while (chat_msgs.Size()) + { + std::string s; + chat_msgs.Pop(s); + //PanicAlert("message: %s", s.c_str()); + m_chat_text->AppendText(wxString(s.c_str(), *wxConvCurrent).Append(wxT('\n'))); + } +} diff --git a/Source/Core/DolphinWX/Src/NetWindow.h b/Source/Core/DolphinWX/Src/NetWindow.h index a9758f5fce..202be15f51 100644 --- a/Source/Core/DolphinWX/Src/NetWindow.h +++ b/Source/Core/DolphinWX/Src/NetWindow.h @@ -18,202 +18,87 @@ #ifndef _NETWINDOW_H_ #define _NETWINDOW_H_ +#include "CommonTypes.h" + +#include #include + #include #include #include #include #include #include +//#include -#include +#include "GameListCtrl.h" -#include "Globals.h" -#include "BootManager.h" -#include "Common.h" -#include "NetStructs.h" -#include "Core.h" -#include "pluginspecs_pad.h" -#include "HW/SI.h" -#include "HW/SI_Device.h" -#include "HW/SI_DeviceGCController.h" -#include "Timer.h" +// just leaving these here so i can find something later if i need it +//#include "Frame.h" +//#include "Globals.h" +//#include "BootManager.h" +//#include "Common.h" +//#include "NetStructs.h" +//#include "Core.h" +//#include "pluginspecs_pad.h" +//#include "HW/SI.h" +//#include "HW/SI_Device.h" +//#include "HW/SI_DeviceGCController.h" +//#include "Timer.h" -#ifdef _DEBUG - #define NET_DEBUG -#endif +#include "LockingQueue.h" -// Use TCP instead of UDP to send pad data @ 60fps. Suitable and better for LAN netplay, -// Unrealistic for Internet netplay, unless you have an uberfast connexion (<10ms ping) -// #define USE_TCP - -class ServerSide; -class ClientSide; - -class NetPlay : public wxFrame +class NetPlaySetupDiag : public wxFrame { - public: - NetPlay(wxWindow* parent, std::string GamePath = "", std::string GameName = ""); - ~NetPlay(); +public: + NetPlaySetupDiag(wxWindow* parent, const CGameListCtrl* const game_list); - void UpdateNetWindow(bool update_infos, wxString=wxT("NULL")); - void AppendText(const wxString text) { m_Logging->AppendText(text); } +private: + void OnJoin(wxCommandEvent& event); + void OnHost(wxCommandEvent& event); + void OnQuit(wxCommandEvent& event); - // Send and receive pads values - bool GetNetPads(u8 pad_nb, SPADStatus, u32 *netvalues); - void ChangeSelectedGame(std::string game); - void IsGameFound(unsigned char*, std::string); - std::string GetSelectedGame() { wxCriticalSectionLocker lock(m_critical); return m_selectedGame; } + wxTextCtrl *m_nickname_text, + *m_host_port_text, + *m_connect_port_text, + *m_connect_ip_text; - void LoadGame(); + wxListBox* m_game_lbox; - protected: - // Protects our vars from being fuxored by threads - wxCriticalSection m_critical; - - // this draws the GUI, ya rly - void DrawGUI(); - void DrawNetWindow(); - - // event handlers - void OnGUIEvent(wxCommandEvent& event); - void OnDisconnect(wxCommandEvent& event); - void OnNetEvent(wxCommandEvent& event); - void OnQuit(wxCloseEvent& event); - - void OnJoin(wxCommandEvent& event); - void OnHost(wxCommandEvent& event); - - // Net play vars (used ingame) - int m_frame; - int m_lastframe; - Common::Timer m_timer; - int m_loopframe; - int m_frameDelay; - bool m_data_received;// True if first frame data received - - // Basic vars - std::string m_paths; // Game paths list - std::string m_games; // Game names list - - std::string m_selectedGame;// Selected game's string - std::string m_hostaddr; // Used with OnGetIP to cache it - bool m_ready, m_clients_ready; - std::string m_nick; - - int m_NetModel; // Using P2P model (0) or Server model (1) - int m_isHosting; // 0 = false ; 1 = true ; 2 = Not set - unsigned char m_numClients; // starting from 0, 4 players max thus 3 clients - std::string m_address; // The address entered into connection box - unsigned short m_port; - - Netpads m_pads[4]; // this struct is used to save synced pad values - IniFile ConfigIni; - - // Sockets objects - ServerSide *m_sock_server; - ClientSide *m_sock_client; - - // ----------- - // GUI objects - // ----------- - wxNotebook *m_Notebook; - wxPanel *m_Tab_Connect; - wxPanel *m_Tab_Host; - wxStaticText *m_SetNick_text; - wxTextCtrl *m_SetNick; - wxChoice *m_NetMode; - - // Host tab : - wxArrayString m_GameList_str; - wxStaticText *m_GameList_text; - wxListBox *m_GameList; - wxStaticText *m_SetPort_text; - wxTextCtrl *m_SetPort; - wxButton *m_HostGame; - wxButton *m_ExitWindowH; - - // Connect tab : - wxTextCtrl *m_ConAddr; - wxStaticText *m_ConAddr_text; - wxButton *m_JoinGame; - wxButton *m_ExitWindowC; - wxCheckBox *m_UseRandomPort; - - // Connection window - wxButton *m_Game_str; - wxTextCtrl *m_Logging; - wxTextCtrl *m_Chat; - wxButton *m_Chat_ok; - // Right part - wxButton *m_wtfismyip; - wxButton *m_ChangeGame; - // Left Part - wxButton *m_Disconnect; - wxStaticText *m_ConInfo_text; - wxButton *m_GetPing; - wxCheckBox *m_Ready; - wxCheckBox *m_RecordGame; - - // wxWidgets event table - DECLARE_EVENT_TABLE() + const CGameListCtrl* const m_game_list; }; -class GameListPopup : public wxDialog +class NetPlayDiag : public wxFrame { - public: - GameListPopup(NetPlay *net_ptr, wxArrayString GameNames); - ~GameListPopup() {} - protected: - void OnButtons(wxCommandEvent& event); - wxArrayString m_GameList_str; - NetPlay* m_netParent; - wxListBox *m_GameList; - wxButton *m_Accept; - wxButton *m_Cancel; - DECLARE_EVENT_TABLE() +public: + NetPlayDiag(wxWindow* parent, const CGameListCtrl* const game_list + , const std::string& game, const bool is_hosting = false); + ~NetPlayDiag(); + + LockingQueue chat_msgs; + //std::string chat_msg; + + void OnStart(wxCommandEvent& event); + +private: + DECLARE_EVENT_TABLE() + + void OnChat(wxCommandEvent& event); + void OnQuit(wxCommandEvent& event); + void OnThread(wxCommandEvent& event); + + wxListBox* m_player_lbox; + wxTextCtrl* m_chat_text; + wxTextCtrl* m_chat_msg_text; + + std::string m_selected_game; + wxButton* m_game_btn; + + const CGameListCtrl* const m_game_list; + //NetPlay* const m_netplay; }; -enum -{ - ID_NOTEBOOK, - ID_TAB_HOST, - ID_TAB_CONN, - ID_BUTTON_HOST, - ID_BUTTON_JOIN, - ID_BUTTON_EXIT, - ID_NETMODE, - ID_GAMELIST, - ID_LOGGING_TXT, - ID_CHAT, - ID_SETNICK, - ID_SETPORT, - ID_CONNADDR, - ID_CONNINFO_TXT, - ID_USE_RANDOMPORT, - ID_BUTTON_GETPING, - ID_BUTTON_GETIP, - ID_CHANGEGAME, - ID_BUTTON_QUIT, - ID_BUTTON_CHAT, - ID_READY, - ID_RECORD, - - ID_SOCKET, - ID_SERVER, - - HOST_FULL = 200, // ... - HOST_ERROR, // Sent on socket error - HOST_DISCONNECTED, - HOST_NEWPLAYER, - HOST_PLAYERLEFT, - CLIENTS_READY, - CLIENTS_NOTREADY, - GUI_UPDATE, // Refresh the shown selectedgame on GUI - ADD_TEXT, // Add text to m_Logging (string) - ADD_INFO, // Sent when updating net infos (string) - NET_EVENT -}; +DECLARE_EVENT_TYPE(wxEVT_THREAD, -1) #endif // _NETWINDOW_H_ diff --git a/Source/Core/DolphinWX/Src/SConscript b/Source/Core/DolphinWX/Src/SConscript index 7251bb9be7..9bc5b03d32 100644 --- a/Source/Core/DolphinWX/Src/SConscript +++ b/Source/Core/DolphinWX/Src/SConscript @@ -37,9 +37,7 @@ if wxenv['HAVE_WX']: 'stdafx.cpp', 'WxUtils.cpp', 'MemoryCards/WiiSaveCrypted.cpp', - 'NetEvent.cpp', - 'NetFunctions.cpp', - 'NetSockets.cpp', + 'NetPlay.cpp', 'NetWindow.cpp', ]