mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Introducing Netplay, currently not extremely polished, and not yet fully tested..
Thanks to shuffle2 for fixing the linux build on an earlier version, still pending other linux fixes :P git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3220 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
+11
-2
@@ -20,6 +20,7 @@
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
// ** ALTERED SOURCE : replaced GetPublicAddress() **
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -210,16 +211,24 @@ IPAddress IPAddress::GetPublicAddress()
|
||||
// (not very hard : the web page contains only our IP address)
|
||||
|
||||
IPAddress PublicAddress;
|
||||
std::string PageBody;
|
||||
|
||||
// Connect to the web server and get its index page
|
||||
Http Server("www.whatismyip.org");
|
||||
// www.whatismyip.org is so slow that it time outs after ~60s
|
||||
// better use this one instead, it is must faster... here :P
|
||||
Http Server("www.monip.org");
|
||||
Http::Request Request(Http::Request::Get, "/");
|
||||
Http::Response Page = Server.SendRequest(Request);
|
||||
|
||||
// If the request was successful, we can extract
|
||||
// the address from the body of the web page
|
||||
if (Page.GetStatus() == Http::Response::Ok)
|
||||
PublicAddress = Page.GetBody();
|
||||
PageBody = Page.GetBody();
|
||||
|
||||
size_t str_start = PageBody.find("IP : ", 0) + 5;
|
||||
size_t str_end = PageBody.find('<', str_start);
|
||||
|
||||
PublicAddress = PageBody.substr(str_start, str_end - str_start);
|
||||
|
||||
return PublicAddress;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
#include "SI_Device.h"
|
||||
#include "SI_DeviceGCController.h"
|
||||
#include "../PluginManager.h"
|
||||
|
||||
#include "EXI_Device.h"
|
||||
#include "EXI_DeviceMic.h"
|
||||
@@ -124,14 +123,28 @@ bool
|
||||
CSIDevice_GCController::GetData(u32& _Hi, u32& _Low)
|
||||
{
|
||||
SPADStatus PadStatus;
|
||||
memset(&PadStatus, 0 ,sizeof(PadStatus));
|
||||
u32 netValues[2] = {0};
|
||||
memset(&PadStatus, 0, sizeof(PadStatus));
|
||||
Common::PluginPAD* pad = CPluginManager::GetInstance().GetPad(ISIDevice::m_iDeviceNumber);
|
||||
pad->PAD_GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus);
|
||||
int NetPlay = GetNetInput(ISIDevice::m_iDeviceNumber, PadStatus, netValues);
|
||||
|
||||
if (NetPlay != 2)
|
||||
{
|
||||
if (NetPlay == 1)
|
||||
{
|
||||
_Hi = netValues[0]; // first 4 bytes
|
||||
_Low = netValues[1]; // last 4 bytes
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
_Hi = (u32)((u8)PadStatus.stickY);
|
||||
_Hi |= (u32)((u8)PadStatus.stickX << 8);
|
||||
_Hi |= (u32)((u16)PadStatus.button << 16);
|
||||
_Hi |= 0x00800000; // F|RES: means that the pad must be "combined" with the origin to math the "final" OSPad-Struct
|
||||
_Hi |= 0x00800000; // F|RES: means that the pad must be "combined" with the origin to match the "final" OSPad-Struct
|
||||
//_Hi |= 0x20000000; // ?
|
||||
|
||||
_Low = (u8)PadStatus.triggerRight;
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#ifndef _SI_DEVICEGCCONTROLLER_H
|
||||
#define _SI_DEVICEGCCONTROLLER_H
|
||||
|
||||
#include "../PluginManager.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// standard gamecube controller
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -80,6 +82,9 @@ public:
|
||||
// Run the SI Buffer
|
||||
virtual int RunBuffer(u8* _pBuffer, int _iLength);
|
||||
|
||||
// Send and Receive pad input from network
|
||||
static int GetNetInput(u8 numPAD, SPADStatus, u32 *PADStatus);
|
||||
|
||||
// Return true on new data
|
||||
virtual bool GetData(u32& _Hi, u32& _Low);
|
||||
|
||||
|
||||
+1360
-1339
File diff suppressed because it is too large
Load Diff
@@ -256,6 +256,7 @@ EVT_MENU(IDM_CONFIG_DSP_PLUGIN, CFrame::OnPluginDSP)
|
||||
EVT_MENU(IDM_CONFIG_PAD_PLUGIN, CFrame::OnPluginPAD)
|
||||
EVT_MENU(IDM_CONFIG_WIIMOTE_PLUGIN, CFrame::OnPluginWiimote)
|
||||
|
||||
EVT_MENU(IDM_NETPLAY, CFrame::OnNetPlay)
|
||||
EVT_MENU(IDM_BROWSE, CFrame::OnBrowse)
|
||||
EVT_MENU(IDM_MEMCARD, CFrame::OnMemcard)
|
||||
EVT_MENU(IDM_CHEATS, CFrame::OnShow_CheatsWindow)
|
||||
|
||||
@@ -195,6 +195,8 @@ class CFrame : public wxFrame
|
||||
|
||||
void OnMemcard(wxCommandEvent& event); // Misc
|
||||
|
||||
void OnNetPlay(wxCommandEvent& event);
|
||||
|
||||
void OnShow_CheatsWindow(wxCommandEvent& event);
|
||||
void OnShow_InfoWindow(wxCommandEvent& event);
|
||||
void OnLoadWiiMenu(wxCommandEvent& event);
|
||||
|
||||
@@ -34,6 +34,8 @@ be accessed from Core::GetWindowHandle().
|
||||
// Includes
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "NetWindow.h"
|
||||
|
||||
#include "Globals.h" // Local
|
||||
#include "Frame.h"
|
||||
#include "ConfigMain.h"
|
||||
@@ -158,6 +160,9 @@ void CFrame::CreateMenu()
|
||||
toolsMenu->Append(IDM_MEMCARD, _T("&Memcard Manager"));
|
||||
toolsMenu->Append(IDM_CHEATS, _T("Action &Replay Manager"));
|
||||
toolsMenu->Append(IDM_INFO, _T("System Information"));
|
||||
|
||||
toolsMenu->Append(IDM_NETPLAY, _T("Start &NetPlay"));
|
||||
|
||||
// toolsMenu->Append(IDM_SDCARD, _T("Mount &SDCard")); // Disable for now
|
||||
|
||||
if (DiscIO::CNANDContentManager::Access().GetNANDLoader(FULL_WII_MENU_DIR).IsValid())
|
||||
@@ -646,6 +651,12 @@ void CFrame::OnHelp(wxCommandEvent& event)
|
||||
}
|
||||
}
|
||||
|
||||
// NetPlay stuff
|
||||
void CFrame::OnNetPlay(wxCommandEvent& WXUNUSED (event))
|
||||
{
|
||||
new NetPlay(this, m_GameListCtrl->GetGamePaths(), m_GameListCtrl->GetGameNames());
|
||||
}
|
||||
|
||||
// Miscellaneous menu
|
||||
void CFrame::OnMemcard(wxCommandEvent& WXUNUSED (event))
|
||||
{
|
||||
|
||||
@@ -60,6 +60,7 @@ enum
|
||||
|
||||
IDM_MEMCARD, // Misc menu
|
||||
IDM_CHEATS,
|
||||
IDM_NETPLAY,
|
||||
IDM_INFO,
|
||||
IDM_CHANGEDISC,
|
||||
IDM_PROPERTIES,
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
// Copyright (C) 2003-2009 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 "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::Format(wxT("*Player : %s is now connected to Host...\n"), buffer));
|
||||
|
||||
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::Format(wxT("*Player : %s left the game\n\n"), buffer));
|
||||
|
||||
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::Format(wxT("*Host changed Game to : %s\n"), buffer));
|
||||
|
||||
// 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
|
||||
Event->SendEvent(CLIENTS_READY, "NULL", 1);
|
||||
|
||||
break;
|
||||
}
|
||||
case 0xA1: // Received pad data from host in versus mode
|
||||
{
|
||||
m_socket.Receive((char*)m_netvalues[0], 8, recv_size);
|
||||
m_data_received = true;
|
||||
#ifdef NET_DEBUG
|
||||
char sent[64];
|
||||
sprintf(sent, "Received Values: 0x%08x : 0x%08x \n", m_netvalues[0][0], m_netvalues[0][1]);
|
||||
Event->AppendText(wxString::FromAscii(sent));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
void ServerSide::OnServerData(char 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::Format(wxT("> Your IP is : %s\n"), buffer));
|
||||
|
||||
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 (char 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::Format(
|
||||
wxT("WARNING : Player %s does Not have this Game !\n"), m_client[sock].nick.c_str());
|
||||
four_bytes = error_str.size();
|
||||
|
||||
for (char i=0; i < 2; i++)
|
||||
Event->AppendText(error_str);
|
||||
|
||||
// Send to all
|
||||
for (char 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 (char 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
|
||||
{
|
||||
m_client[sock].socket.Receive((char*)m_netvalues[sock], 8, recv_size);
|
||||
m_data_received = true;
|
||||
|
||||
#ifdef NET_DEBUG
|
||||
char sent[64];
|
||||
sprintf(sent, "Received Values: 0x%08x : 0x%08x \n", m_netvalues[sock][0], m_netvalues[sock][1]);
|
||||
Event->AppendText(wxString::FromAscii(sent));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,426 @@
|
||||
// Copyright (C) 2003-2009 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 "NetWindow.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"
|
||||
"*Player : %s has been dropped from the game.\n\n"),
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case HOST_PLAYERLEFT:
|
||||
{
|
||||
m_numClients--;
|
||||
}
|
||||
break;
|
||||
case HOST_NEWPLAYER:
|
||||
{
|
||||
m_numClients++;
|
||||
}
|
||||
break;
|
||||
case CLIENTS_READY:
|
||||
{
|
||||
m_clients_ready = true;
|
||||
if (m_ready || event.GetInt())
|
||||
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
|
||||
|
||||
m_Logging->AppendText(_("** Everyone is ready... Loading Game ! **\n"));
|
||||
|
||||
// Tell clients everyone is ready...
|
||||
if (m_isHosting == 1)
|
||||
{
|
||||
unsigned char value = 0x50;
|
||||
|
||||
for (int i=0; i < m_numClients ; i++)
|
||||
m_sock_server->Write(i, (const char*)&value, 1);
|
||||
}
|
||||
|
||||
// TODO : Throttle should be on by default, to avoid stuttering
|
||||
//soundStream->GetMixer()->SetThrottle(true);
|
||||
|
||||
int line_p = 0;
|
||||
int line_n = 0;
|
||||
|
||||
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();
|
||||
|
||||
// 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)
|
||||
{
|
||||
// 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);
|
||||
|
||||
// TODO : actually show this on the GUI :p
|
||||
// Update the timer and increment total frame number
|
||||
m_frame++;
|
||||
m_timer.Update();
|
||||
|
||||
// We make sure everyone's pad is enabled
|
||||
for (char i = 0; i < m_numClients; i++)
|
||||
SerialInterface::ChangeDevice(SI_GC_CONTROLLER, (int)i);
|
||||
|
||||
// Better disable unused ports
|
||||
for (char i = m_numClients; i < 3; i++)
|
||||
SerialInterface::ChangeDevice(SI_DUMMY, (int)i);
|
||||
|
||||
if (m_NetModel == 0 && m_numClients == 1) // Use P2P Model
|
||||
{
|
||||
if (padnb == 0)
|
||||
{
|
||||
#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 init_value = 0xA1;
|
||||
unsigned char recv_value = 0;
|
||||
unsigned char player = 0;
|
||||
|
||||
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);
|
||||
player = 0; // Host is player 1
|
||||
}
|
||||
else {
|
||||
// Send pads values
|
||||
m_sock_client->Write((const char*)&init_value, 1);
|
||||
m_sock_client->Write((const char*)netValues, 8);
|
||||
player = 1; // Client is player 2
|
||||
}
|
||||
|
||||
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, m_data_received);
|
||||
else
|
||||
m_data_received = m_sock_client->isNewPadData(0, m_data_received);
|
||||
|
||||
if (m_data_received)
|
||||
{
|
||||
// First Data has been received !
|
||||
m_Logging->AppendText(_("** Data received from Peer. Starting Sync !"));
|
||||
|
||||
// Set our practical frame delay
|
||||
if (recv_value == 0xA1) // init number
|
||||
{
|
||||
m_frameDelay = m_loopframe;
|
||||
m_loopframe = 0;
|
||||
m_Logging->AppendText(wxString::Format(wxT(" Frame Delay : %d **\n"), m_frameDelay));
|
||||
}
|
||||
}
|
||||
else {
|
||||
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);
|
||||
|
||||
m_pads[player].nHi[saveslot] = netValues[0];
|
||||
m_pads[player].nLow[saveslot] = netValues[1];
|
||||
|
||||
// Read the socket for pad values
|
||||
if (m_isHosting == 1)
|
||||
while (!m_sock_server->isNewPadData(netValues, 1)) { /* Wait Data */ }
|
||||
else
|
||||
while (!m_sock_client->isNewPadData(netValues, 1)) { }
|
||||
|
||||
if (player == 0)
|
||||
{
|
||||
// Store received peer values
|
||||
m_pads[1].nHi[m_loopframe] = netValues[0];
|
||||
m_pads[1].nLow[m_loopframe] = netValues[1];
|
||||
// Apply synced pad values
|
||||
netValues[0] = m_pads[0].nHi[m_loopframe];
|
||||
netValues[1] = m_pads[0].nLow[m_loopframe];
|
||||
}
|
||||
}
|
||||
|
||||
#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 = 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, m_selectedGame.c_str(), game_size + 1);
|
||||
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\n"), game.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
void NetPlay::OnQuit(wxCloseEvent& WXUNUSED(event))
|
||||
{
|
||||
NetClass_ptr = NULL;
|
||||
|
||||
// We Kill the threads
|
||||
if (m_isHosting == 0)
|
||||
m_sock_client->Delete();
|
||||
else if (m_isHosting == 1) {
|
||||
m_sock_server->Delete();
|
||||
// Stop listening, we're doing it here cause Doing it in the thread
|
||||
// Cause SFML to crash when built in release build, odd ? :(
|
||||
m_listensocket.Close();
|
||||
}
|
||||
|
||||
// Destroy the Frame
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void NetPlay::OnDisconnect(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
wxCloseEvent close;
|
||||
OnQuit(close);
|
||||
}
|
||||
|
||||
bool ClientSide::isNewPadData(u32 *netValues, bool current, bool isVersus)
|
||||
{
|
||||
// TODO : adapt it to more than 2 players
|
||||
wxCriticalSectionLocker lock(m_CriticalSection);
|
||||
|
||||
if (current)
|
||||
{
|
||||
if (m_data_received)
|
||||
{
|
||||
if (isVersus) {
|
||||
netValues[0] = m_netvalues[0][0];
|
||||
netValues[1] = m_netvalues[0][1];
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_data_received;
|
||||
}
|
||||
|
||||
bool ServerSide::isNewPadData(u32 *netValues, bool current, char client)
|
||||
{
|
||||
wxCriticalSectionLocker lock(m_CriticalSection);
|
||||
|
||||
if (current)
|
||||
{
|
||||
if (m_data_received)
|
||||
{
|
||||
netValues[0] = m_netvalues[client][0];
|
||||
netValues[1] = m_netvalues[client][1];
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_data_received;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,462 @@
|
||||
// Copyright (C) 2003-2009 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 "NetWindow.h"
|
||||
|
||||
//--------------------------------
|
||||
// GUI EVENTS
|
||||
//--------------------------------
|
||||
|
||||
void NetEvent::AppendText(const wxString text)
|
||||
{
|
||||
// I have the feeling SendEvent may be a bit better...
|
||||
#if 0
|
||||
SendEvent(ADD_TEXT, 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()) );
|
||||
|
||||
m_netptr->AddPendingEvent(event);
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
// SERVER SIDE THREAD
|
||||
//--------------------------------
|
||||
|
||||
ServerSide::ServerSide(NetPlay* netptr, sf::SocketTCP socket, int netmodel, std::string nick)
|
||||
: wxThread()
|
||||
{
|
||||
m_numplayers = 0;
|
||||
m_data_received = false;
|
||||
m_netmodel = netmodel;
|
||||
m_socket = socket;
|
||||
m_netptr = netptr;
|
||||
m_nick = nick;
|
||||
Event = new NetEvent(m_netptr);
|
||||
}
|
||||
|
||||
char ServerSide::GetSocket(sf::SocketTCP Socket)
|
||||
{
|
||||
for (char i=0; i < m_numplayers; i++)
|
||||
{
|
||||
if(m_client[i].socket == Socket)
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0xE;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
SyncValues(m_numplayers, Address);
|
||||
}
|
||||
|
||||
// Add it to the selector
|
||||
m_selector.Add(Incoming);
|
||||
Event->SendEvent(HOST_NEWPLAYER);
|
||||
|
||||
m_numplayers++;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char recv;
|
||||
char socket_nb;
|
||||
size_t recv_size;
|
||||
sf::Socket::Status recv_status;
|
||||
|
||||
if ((socket_nb = GetSocket(Socket)) == 0xE)
|
||||
PanicAlert("ERROR: How did you get there ?! Is that even possible ?!");
|
||||
|
||||
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::Format(wxT("*Player : %s left the game.\n\n"),
|
||||
player_left.c_str()) );
|
||||
|
||||
// We need to adjust the struct...
|
||||
for (char i = socket_nb; i < m_numplayers; i++)
|
||||
{
|
||||
m_client[i].socket = m_client[i+1].socket;
|
||||
m_client[i].nick = m_client[i+1].nick;
|
||||
m_client[i].ready = m_client[i+1].ready;
|
||||
}
|
||||
|
||||
// Send disconnected message to all
|
||||
unsigned char send = 0x11;
|
||||
unsigned int str_size = player_left.size();
|
||||
|
||||
for (int i=0; i < m_numplayers ; i++)
|
||||
{
|
||||
m_client[i].socket.Send((const char*)&send, 1);
|
||||
m_client[i].socket.Send((const char*)&str_size, 4);
|
||||
m_client[i].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())
|
||||
{
|
||||
// Delete the Thread and close clients sockets
|
||||
for (char i=0; i < m_numplayers ; i++)
|
||||
m_client[i].socket.Close();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void 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;
|
||||
|
||||
// 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 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;
|
||||
|
||||
// Check if the client has the game
|
||||
Socket.Receive((char *)&init_number, 1, received);
|
||||
|
||||
// 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::Format(wxT("*Connection established to %s (%s)\n"),
|
||||
m_client[socketnb].nick.c_str(), Address.ToString().c_str()) );
|
||||
|
||||
if (init_number != 0x1F) // Not Found
|
||||
for (int i = 0; i < 4; i++)
|
||||
Event->AppendText(_("WARNING : Game Not Found on Client Side !\n"));
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
void ServerSide::Write(char 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;
|
||||
int 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);
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
// CLIENT SIDE THREAD
|
||||
//--------------------------------
|
||||
|
||||
ClientSide::ClientSide(NetPlay* netptr, sf::SocketTCP socket, std::string addr, std::string nick)
|
||||
: wxThread()
|
||||
{
|
||||
m_numplayers = 0;
|
||||
m_data_received = false;
|
||||
m_netmodel = 0;
|
||||
m_socket = socket;
|
||||
m_netptr = netptr;
|
||||
m_nick = nick;
|
||||
m_addr = addr;
|
||||
Event = new NetEvent(m_netptr);
|
||||
}
|
||||
|
||||
void *ClientSide::Entry()
|
||||
{
|
||||
Event->AppendText(_("*Connection Request... "));
|
||||
|
||||
// If we get here, the connection is already accepted, however the game may be full
|
||||
if (SyncValues())
|
||||
{
|
||||
Event->AppendText(_("Connection successful !\n"));
|
||||
Event->AppendText( wxString::Format(wxT("*Connection established to %s (%s)\n*Game is : %s\n"),
|
||||
m_hostnick.c_str(), m_addr.c_str(), m_selectedgame.c_str() ) );
|
||||
|
||||
// Tell the server if the client has the game
|
||||
CheckGameFound();
|
||||
}
|
||||
else {
|
||||
// Post ServerFull event to GUI
|
||||
m_socket.Close();
|
||||
Event->SendEvent(HOST_FULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m_netptr->ChangeSelectedGame(m_selectedgame);
|
||||
Event->SendEvent(HOST_NEWPLAYER);
|
||||
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 = m_nick.size();
|
||||
char *buffer = NULL;
|
||||
size_t recv_size;
|
||||
|
||||
// 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 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);
|
||||
|
||||
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(_("WARNING : You do not have the Selected Game !\n"));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,307 @@
|
||||
// Copyright (C) 2003-2009 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 _NETWINDOW_H_
|
||||
#define _NETWINDOW_H_
|
||||
|
||||
#include <SFML/Network.hpp>
|
||||
#include <string>
|
||||
#include <wx/wx.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/notebook.h>
|
||||
#include <wx/gbsizer.h>
|
||||
#include <wx/listbox.h>
|
||||
|
||||
#include <wx/thread.h>
|
||||
|
||||
#include "Globals.h"
|
||||
#include "BootManager.h"
|
||||
#include "Common.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
|
||||
|
||||
class NetPlay;
|
||||
|
||||
struct Netpads {
|
||||
int nHi[128];
|
||||
int nLow[128];
|
||||
};
|
||||
|
||||
struct Clients {
|
||||
std::string nick;
|
||||
sf::SocketTCP socket;
|
||||
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 socket, int netmodel, std::string nick);
|
||||
~ServerSide() {};
|
||||
|
||||
virtual void *Entry();
|
||||
|
||||
void Write(char socknb, const char *data, size_t size, long *ping=NULL);
|
||||
bool isNewPadData(u32 *netValues, bool current, char client=0);
|
||||
|
||||
private:
|
||||
void SyncValues(unsigned char, sf::IPAddress);
|
||||
char GetSocket(sf::SocketTCP Socket);
|
||||
void OnServerData(char sock, unsigned char data);
|
||||
void IsEveryoneReady();
|
||||
|
||||
NetPlay *m_netptr;
|
||||
NetEvent *Event;
|
||||
|
||||
u32 m_netvalues[3][2];
|
||||
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
|
||||
|
||||
wxCriticalSection m_CriticalSection;
|
||||
};
|
||||
|
||||
class ClientSide : public wxThread
|
||||
{
|
||||
public:
|
||||
ClientSide(NetPlay* netptr, sf::SocketTCP socket, std::string addr, std::string nick);
|
||||
~ClientSide() {}
|
||||
|
||||
virtual void *Entry();
|
||||
|
||||
void Write(const char *data, size_t size, long *ping=NULL);
|
||||
bool isNewPadData(u32 *netValues, bool current, bool isVersus=true);
|
||||
|
||||
private:
|
||||
bool SyncValues();
|
||||
void CheckGameFound();
|
||||
void OnClientData(unsigned char data);
|
||||
|
||||
NetPlay *m_netptr;
|
||||
NetEvent *Event;
|
||||
|
||||
u32 m_netvalues[3][2];
|
||||
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
|
||||
std::string m_addr; // Contains the server addr
|
||||
|
||||
wxCriticalSection m_CriticalSection;
|
||||
};
|
||||
|
||||
class NetPlay : public wxDialog
|
||||
{
|
||||
public:
|
||||
NetPlay(wxWindow* parent, std::string GamePath = "", std::string GameName = "");
|
||||
~NetPlay() {}
|
||||
|
||||
void UpdateNetWindow(bool update_infos, wxString="NULL");
|
||||
void AppendText(const wxString text) { m_Logging->AppendText(text); }
|
||||
|
||||
// Send and receive pads values
|
||||
bool GetNetPads(u8 pad_nb, SPADStatus, u32 *netvalues);
|
||||
void ChangeSelectedGame(std::string game);
|
||||
void IsGameFound(unsigned char*, std::string);
|
||||
bool IsReady() { wxCriticalSectionLocker lock(m_critical); return m_ready; }
|
||||
std::string GetSelectedGame() { wxCriticalSectionLocker lock(m_critical); return m_selectedGame; }
|
||||
|
||||
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);
|
||||
|
||||
void LoadGame();
|
||||
|
||||
// Net play vars (used ingame)
|
||||
int m_frame;
|
||||
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
|
||||
unsigned short m_port;
|
||||
|
||||
Netpads m_pads[4]; // this struct is used to save synced pad values
|
||||
|
||||
// Sockets objects
|
||||
sf::SocketTCP m_listensocket;
|
||||
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;
|
||||
|
||||
// Connect tab :
|
||||
wxTextCtrl *m_ConAddr;
|
||||
wxStaticText *m_ConAddr_text;
|
||||
wxButton *m_JoinGame;
|
||||
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()
|
||||
};
|
||||
|
||||
class GameListPopup : public wxDialog
|
||||
{
|
||||
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()
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ID_NOTEBOOK,
|
||||
ID_TAB_HOST,
|
||||
ID_TAB_CONN,
|
||||
ID_BUTTON_HOST,
|
||||
ID_BUTTON_JOIN,
|
||||
ID_NETMODE,
|
||||
ID_GAMELIST,
|
||||
ID_GAMELIST_TXT,
|
||||
ID_LOGGING_TXT,
|
||||
ID_CHAT,
|
||||
ID_SETNICK_TXT,
|
||||
ID_SETNICK,
|
||||
ID_SETPORT,
|
||||
ID_SETPORT_TXT,
|
||||
ID_CONNADDR,
|
||||
ID_CONNADDR_TXT,
|
||||
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
|
||||
};
|
||||
|
||||
#endif // _NETWINDOW_H_
|
||||
|
||||
@@ -59,6 +59,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Dolphin", "Core\DolphinWX\D
|
||||
{33546D62-7F34-4EA6-A88E-D538B36E16BF} = {33546D62-7F34-4EA6-A88E-D538B36E16BF}
|
||||
{11F55366-12EC-4C44-A8CB-1D4E315D61ED} = {11F55366-12EC-4C44-A8CB-1D4E315D61ED}
|
||||
{3E03C179-8251-46E4-81F4-466F114BAC63} = {3E03C179-8251-46E4-81F4-466F114BAC63}
|
||||
{823DDC98-42D5-4A38-88CF-9DC06C788AE4} = {823DDC98-42D5-4A38-88CF-9DC06C788AE4}
|
||||
{0E231FB1-F3C9-4724-ACCB-DE8BCB3C089E} = {0E231FB1-F3C9-4724-ACCB-DE8BCB3C089E}
|
||||
{521498BE-6089-4780-8223-E67C22F4E068} = {521498BE-6089-4780-8223-E67C22F4E068}
|
||||
{E5D1F0C0-AA07-4841-A4EB-4CF4DAA6B0FA} = {E5D1F0C0-AA07-4841-A4EB-4CF4DAA6B0FA}
|
||||
|
||||
Reference in New Issue
Block a user