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