NetPlay: completely redone - should be somewhat usable when using Single Core and DSP LLE Plugin.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5425 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
1796cbc917
commit
a6d6d27328
|
@ -86,6 +86,7 @@
|
||||||
#define HAVE_OPENAL 1
|
#define HAVE_OPENAL 1
|
||||||
#define HAVE_ALSA 0
|
#define HAVE_ALSA 0
|
||||||
#define HAVE_PORTAUDIO 0
|
#define HAVE_PORTAUDIO 0
|
||||||
|
#define HAVE_SFML 1
|
||||||
|
|
||||||
// it is VERY DANGEROUS to mix _SECURE_SCL=0 and _SECURE_SCL=1 compiled libraries.
|
// 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.
|
// You will get bizarre crash bugs whenever you use STL.
|
||||||
|
|
|
@ -415,7 +415,12 @@ u32 CEXIIPL::GetGCTime()
|
||||||
u64 ltime = Common::Timer::GetTimeSinceJan1970();
|
u64 ltime = Common::Timer::GetTimeSinceJan1970();
|
||||||
return ((u32)ltime - cJanuary2000 - Bias);
|
return ((u32)ltime - cJanuary2000 - Bias);
|
||||||
#else
|
#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)
|
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
|
||||||
return ((u32)ltime - cJanuary2000 - cWiiBias/* + 32434790*/);
|
return ((u32)ltime - cJanuary2000 - cWiiBias/* + 32434790*/);
|
||||||
else
|
else
|
||||||
|
|
|
@ -32,6 +32,8 @@ public:
|
||||||
void DoState(PointerWrap &p);
|
void DoState(PointerWrap &p);
|
||||||
|
|
||||||
static u32 GetGCTime();
|
static u32 GetGCTime();
|
||||||
|
static u32 GetNetGCTime();
|
||||||
|
|
||||||
static void Descrambler(u8* data, u32 size);
|
static void Descrambler(u8* data, u32 size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -923,185 +923,15 @@
|
||||||
Name="NetPlay"
|
Name="NetPlay"
|
||||||
>
|
>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\Src\NetEvent.cpp"
|
RelativePath=".\Src\LockingQueue.h"
|
||||||
>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
ForcedIncludeFiles="$(NOINHERIT)"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|x64"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
ForcedIncludeFiles="$(NOINHERIT)"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
ForcedIncludeFiles="$(NOINHERIT)"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|x64"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
ForcedIncludeFiles="$(NOINHERIT)"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="DebugFast|Win32"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
ForcedIncludeFiles="$(NOINHERIT)"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="DebugFast|x64"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
ForcedIncludeFiles="$(NOINHERIT)"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\NetFunctions.cpp"
|
|
||||||
>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
ForcedIncludeFiles="$(NOINHERIT)"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|x64"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
ForcedIncludeFiles="$(NOINHERIT)"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
ForcedIncludeFiles="$(NOINHERIT)"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|x64"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
ForcedIncludeFiles="$(NOINHERIT)"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="DebugFast|Win32"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
ForcedIncludeFiles="$(NOINHERIT)"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="DebugFast|x64"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
ForcedIncludeFiles="$(NOINHERIT)"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\NetSockets.cpp"
|
|
||||||
>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
ForcedIncludeFiles="$(NOINHERIT)"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|x64"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
ForcedIncludeFiles="$(NOINHERIT)"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
ForcedIncludeFiles="$(NOINHERIT)"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|x64"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
ForcedIncludeFiles="$(NOINHERIT)"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="DebugFast|Win32"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
ForcedIncludeFiles="$(NOINHERIT)"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="DebugFast|x64"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
UsePrecompiledHeader="0"
|
|
||||||
ForcedIncludeFiles="$(NOINHERIT)"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\Src\NetSockets.h"
|
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\Src\NetStructs.h"
|
RelativePath=".\Src\NetPlay.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\Src\NetPlay.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
|
|
|
@ -187,8 +187,7 @@ void CFrame::CreateMenu()
|
||||||
toolsMenu->Append(IDM_CHEATS, _T("Action &Replay Manager"));
|
toolsMenu->Append(IDM_CHEATS, _T("Action &Replay Manager"));
|
||||||
|
|
||||||
#if defined(HAVE_SFML) && HAVE_SFML
|
#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
|
#endif
|
||||||
|
|
||||||
if (DiscIO::CNANDContentManager::Access().GetNANDLoader(std::string (File::GetUserPath(D_WIIMENU_IDX))).IsValid())
|
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))
|
void CFrame::OnNetPlay(wxCommandEvent& WXUNUSED (event))
|
||||||
{
|
{
|
||||||
#if defined(HAVE_SFML) && HAVE_SFML
|
#if defined(HAVE_SFML) && HAVE_SFML
|
||||||
new NetPlay(this, m_GameListCtrl->GetGamePaths(), m_GameListCtrl->GetGameNames());
|
new NetPlaySetupDiag(this, m_GameListCtrl);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef _LOCKINGQUEUE_H_
|
||||||
|
#define _LOCKINGQUEUE_H_
|
||||||
|
|
||||||
|
#include "Thread.h"
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
// i should make one of those single reader/ single writer queues
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
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<T> m_queue;
|
||||||
|
Common::CriticalSection m_crit;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
|
@ -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 <sstream>
|
||||||
|
|
||||||
|
// 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<num; ++i)
|
||||||
|
{
|
||||||
|
sf::SocketTCP ready_socket = m_selector.GetSocketReady(i);
|
||||||
|
|
||||||
|
// listening socket
|
||||||
|
if (ready_socket == m_socket)
|
||||||
|
{
|
||||||
|
sf::SocketTCP accept_socket;
|
||||||
|
m_socket.Accept(accept_socket);
|
||||||
|
|
||||||
|
m_crit.other.Enter();
|
||||||
|
unsigned int error = OnConnect(accept_socket);
|
||||||
|
m_crit.other.Leave();
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
sf::Packet spac;
|
||||||
|
spac << (MessageId)error;
|
||||||
|
// don't need to lock, this client isn't in the client map
|
||||||
|
accept_socket.Send(spac);
|
||||||
|
|
||||||
|
// TODO: not sure if client gets the message if i close right away
|
||||||
|
accept_socket.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// client socket
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sf::Packet rpac;
|
||||||
|
switch (ready_socket.Receive(rpac))
|
||||||
|
{
|
||||||
|
case sf::Socket::Done :
|
||||||
|
// if a bad packet is recieved, disconnect the client
|
||||||
|
if (0 == OnData(rpac, ready_socket))
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sf::Socket::Disconnected :
|
||||||
|
m_crit.other.Enter();
|
||||||
|
OnDisconnect(ready_socket);
|
||||||
|
m_crit.other.Leave();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// close listening socket and client sockets
|
||||||
|
{
|
||||||
|
std::map<sf::SocketTCP, Player>::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<sf::SocketTCP, Player>::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<sf::SocketTCP, Player>::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 <typename P>
|
||||||
|
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<u8, Player>::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<sf::SocketTCP, Player>::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; i<TEMP_FIXED_BUFFER; ++i)
|
||||||
|
for (unsigned int p=0; p<4; ++p)
|
||||||
|
m_pad_buffer[p].push(np);
|
||||||
|
m_crit.buffer.Leave();
|
||||||
|
|
||||||
|
// tell clients to start game
|
||||||
|
sf::Packet spac;
|
||||||
|
spac << (MessageId)NP_MSG_START_GAME;
|
||||||
|
|
||||||
|
m_crit.send.Enter();
|
||||||
|
SendToClients(spac);
|
||||||
|
m_crit.send.Leave();
|
||||||
|
|
||||||
|
// boot game
|
||||||
|
::main_frame->BootGame(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; i<TEMP_FIXED_BUFFER; ++i)
|
||||||
|
for (unsigned int p=0; p<4; ++p)
|
||||||
|
m_pad_buffer[p].push(np);
|
||||||
|
m_crit.buffer.Leave();
|
||||||
|
|
||||||
|
// boot game
|
||||||
|
::main_frame->BootGame(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;
|
||||||
|
}
|
|
@ -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 <SFML/Network.hpp>
|
||||||
|
|
||||||
|
#include "pluginspecs_pad.h"
|
||||||
|
#include "svnrev.h"
|
||||||
|
|
||||||
|
//#include <wx/wx.h>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
class NetPlayDiag;
|
||||||
|
|
||||||
|
class NetPad
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NetPad();
|
||||||
|
NetPad(const SPADStatus* const);
|
||||||
|
|
||||||
|
u32 nHi;
|
||||||
|
u32 nLo;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NETPLAY_VERSION "Dolphin NetPlay 2.0"
|
||||||
|
|
||||||
|
#ifdef _M_X64
|
||||||
|
#define NP_ARCH "x64"
|
||||||
|
#else
|
||||||
|
#define NP_ARCH "x86"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define NETPLAY_DOLPHIN_VER SVN_REV_STR" win-"NP_ARCH
|
||||||
|
#elif __APPLE__
|
||||||
|
#define NETPLAY_DOLPHIN_VER SVN_REV_STR" osx-"NP_ARCH
|
||||||
|
#else
|
||||||
|
#define NETPLAY_DOLPHIN_VER SVN_REV_STR" nix-"NP_ARCH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// messages
|
||||||
|
#define NP_MSG_PLAYER_JOIN 0x10
|
||||||
|
#define NP_MSG_PLAYER_LEAVE 0x11
|
||||||
|
|
||||||
|
#define NP_MSG_CHAT_MESSAGE 0x30
|
||||||
|
|
||||||
|
#define NP_MSG_PAD_DATA 0x60
|
||||||
|
#define NP_MSG_PAD_MAPPING 0x61
|
||||||
|
#define NP_MSG_PAD_BUFFER 0x62
|
||||||
|
|
||||||
|
#define NP_MSG_START_GAME 0xA0
|
||||||
|
#define NP_MSG_CHANGE_GAME 0xA1
|
||||||
|
|
||||||
|
#define NP_MSG_READY 0xD0
|
||||||
|
#define NP_MSG_NOT_READY 0xD1
|
||||||
|
|
||||||
|
#define NP_MSG_PING 0xE0
|
||||||
|
#define NP_MSG_PONG 0xE1
|
||||||
|
// end messages
|
||||||
|
|
||||||
|
// gui messages
|
||||||
|
#define NP_GUI_UPDATE 0x10
|
||||||
|
// end messages
|
||||||
|
|
||||||
|
typedef u8 MessageId;
|
||||||
|
typedef u8 PlayerId;
|
||||||
|
typedef s8 PadMapping;
|
||||||
|
|
||||||
|
class NetPlay
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NetPlay() : m_is_running(false), m_do_loop(true) {}
|
||||||
|
virtual ~NetPlay();
|
||||||
|
virtual void Entry() = 0;
|
||||||
|
|
||||||
|
bool is_connected;
|
||||||
|
|
||||||
|
// Send and receive pads values
|
||||||
|
virtual bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues) = 0;
|
||||||
|
virtual bool SetSelectedGame(const std::string& game) = 0;
|
||||||
|
virtual void GetPlayerList(std::string& list) = 0;
|
||||||
|
virtual void SendChatMessage(const std::string& msg) = 0;
|
||||||
|
virtual bool StartGame(const std::string &path) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//NetPlay(Common::ThreadFunc entry, void* arg) : m_thread(entry, arg) {}
|
||||||
|
|
||||||
|
void UpdateGUI();
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
Common::CriticalSection send, players, buffer, other;
|
||||||
|
} m_crit;
|
||||||
|
|
||||||
|
//LockingQueue<NetPad> m_pad_buffer[4];
|
||||||
|
std::queue<NetPad> m_pad_buffer[4];
|
||||||
|
|
||||||
|
NetPlayDiag* m_dialog;
|
||||||
|
sf::SocketTCP m_socket;
|
||||||
|
Common::Thread* m_thread;
|
||||||
|
sf::Selector<sf::SocketTCP> m_selector;
|
||||||
|
|
||||||
|
std::string m_selected_game;
|
||||||
|
bool m_is_running;
|
||||||
|
volatile bool m_do_loop;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class NetPlayServer : public NetPlay
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Entry();
|
||||||
|
|
||||||
|
NetPlayServer(const u16 port, const std::string& name, NetPlayDiag* const npd = NULL, const std::string& game = "");
|
||||||
|
~NetPlayServer();
|
||||||
|
|
||||||
|
void GetPlayerList(std::string& list);
|
||||||
|
|
||||||
|
// Send and receive pads values
|
||||||
|
bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues);
|
||||||
|
bool SetSelectedGame(const std::string& game);
|
||||||
|
void SendChatMessage(const std::string& msg);
|
||||||
|
bool StartGame(const std::string &path);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Player
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Player();
|
||||||
|
|
||||||
|
PlayerId pid;
|
||||||
|
sf::SocketTCP socket;
|
||||||
|
std::string name;
|
||||||
|
PadMapping pad_map[4];
|
||||||
|
std::string revision;
|
||||||
|
};
|
||||||
|
|
||||||
|
void SendToClients(sf::Packet& packet, const u8 skip_pid = 0);
|
||||||
|
unsigned int OnConnect(sf::SocketTCP& socket);
|
||||||
|
unsigned int OnDisconnect(sf::SocketTCP& socket);
|
||||||
|
unsigned int OnData(sf::Packet& packet, sf::SocketTCP& socket);
|
||||||
|
|
||||||
|
std::map<sf::SocketTCP, Player> m_players;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NetPlayClient : public NetPlay
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Entry();
|
||||||
|
|
||||||
|
NetPlayClient(const std::string& address, const u16 port, const std::string& name, NetPlayDiag* const npd = NULL);
|
||||||
|
~NetPlayClient();
|
||||||
|
|
||||||
|
void GetPlayerList(std::string& list);
|
||||||
|
|
||||||
|
// Send and receive pads values
|
||||||
|
bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues);
|
||||||
|
bool SetSelectedGame(const std::string& game);
|
||||||
|
void SendChatMessage(const std::string& msg);
|
||||||
|
bool StartGame(const std::string &path);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Player
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Player();
|
||||||
|
|
||||||
|
PlayerId pid;
|
||||||
|
std::string name;
|
||||||
|
PadMapping pad_map[4];
|
||||||
|
std::string revision;
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned int OnData(sf::Packet& packet);
|
||||||
|
|
||||||
|
PlayerId m_pid;
|
||||||
|
std::map<u8, Player> m_players;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,607 +0,0 @@
|
||||||
// Copyright (C) 2003 Dolphin Project.
|
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, version 2.0.
|
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License 2.0 for more details.
|
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
|
||||||
// If not, see http://www.gnu.org/licenses/
|
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
|
||||||
// http://code.google.com/p/dolphin-emu/
|
|
||||||
|
|
||||||
#include "NetSockets.h"
|
|
||||||
#include "NetWindow.h"
|
|
||||||
|
|
||||||
//--------------------------------
|
|
||||||
// GUI EVENTS
|
|
||||||
//--------------------------------
|
|
||||||
|
|
||||||
void NetEvent::AppendText(const wxString text)
|
|
||||||
{
|
|
||||||
// I have the feeling SendEvent may be a bit safer/better...
|
|
||||||
#if 0
|
|
||||||
SendEvent(ADD_TEXT, std::string(text.mb_str())); //NETPLAY: FIXME std::string(text.mb_str())
|
|
||||||
#else
|
|
||||||
wxMutexGuiEnter();
|
|
||||||
m_netptr->AppendText(text);
|
|
||||||
wxMutexGuiLeave();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void NetEvent::SendEvent(int EventType, const std::string text, int integer)
|
|
||||||
{
|
|
||||||
wxCommandEvent event(wxEVT_HOST_COMMAND, wxID_ANY);
|
|
||||||
|
|
||||||
event.SetId( EventType );
|
|
||||||
event.SetInt( integer );
|
|
||||||
event.SetString( wxString::FromAscii(text.c_str()) );
|
|
||||||
#if ! wxCHECK_VERSION(2, 9, 0)
|
|
||||||
m_netptr->AddPendingEvent(event);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------
|
|
||||||
// SERVER SIDE THREAD
|
|
||||||
//--------------------------------
|
|
||||||
|
|
||||||
ServerSide::ServerSide(NetPlay* netptr, sf::SocketTCP socket, sf::SocketUDP socketUDP, int netmodel, std::string nick)
|
|
||||||
: wxThread()
|
|
||||||
{
|
|
||||||
m_numplayers = 0;
|
|
||||||
m_data_received = false;
|
|
||||||
m_netmodel = netmodel;
|
|
||||||
m_socket = socket;
|
|
||||||
m_socketUDP = socketUDP;
|
|
||||||
m_netptr = netptr;
|
|
||||||
m_nick = nick;
|
|
||||||
Event = new NetEvent(m_netptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
char ServerSide::GetSocket(sf::SocketTCP Socket)
|
|
||||||
{
|
|
||||||
for (int i=0; i < m_numplayers; i++)
|
|
||||||
{
|
|
||||||
if(m_client[i].socket == Socket)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0xE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ServerSide::RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time)
|
|
||||||
{
|
|
||||||
sf::SelectorUDP Selector;
|
|
||||||
sf::IPAddress Addr;
|
|
||||||
unsigned short Port;
|
|
||||||
Selector.Add(Socket);
|
|
||||||
|
|
||||||
if (Selector.Wait(Time) > 0)
|
|
||||||
{
|
|
||||||
Socket.Receive(Data, Max, Recvd, Addr, Port);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void *ServerSide::Entry()
|
|
||||||
{
|
|
||||||
// Add listening socket
|
|
||||||
m_selector.Add(m_socket);
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
char nbSocketReady = m_selector.Wait(0.5);
|
|
||||||
|
|
||||||
for (char i = 0; i < nbSocketReady; ++i)
|
|
||||||
{
|
|
||||||
m_CriticalSection.Enter();
|
|
||||||
sf::SocketTCP Socket = m_selector.GetSocketReady(i);
|
|
||||||
if (Socket == m_socket)
|
|
||||||
{
|
|
||||||
// Incoming connection
|
|
||||||
Event->AppendText(_("*Connection Request... "));
|
|
||||||
|
|
||||||
sf::SocketTCP Incoming;
|
|
||||||
sf::IPAddress Address;
|
|
||||||
m_socket.Accept(Incoming, &Address);
|
|
||||||
|
|
||||||
unsigned char sent = 0x12;
|
|
||||||
if ((m_netmodel == 0 && m_numplayers > 0) || m_numplayers == 3)
|
|
||||||
{
|
|
||||||
Incoming.Send((const char *)&sent, 1); // Tell it the server is full...
|
|
||||||
Incoming.Close(); // Then close the connection
|
|
||||||
|
|
||||||
Event->AppendText(_(" Server is Full !\n"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Event->AppendText(_(" Connection accepted\n"));
|
|
||||||
m_client[m_numplayers].socket = Incoming;
|
|
||||||
m_client[m_numplayers].address = Address;
|
|
||||||
|
|
||||||
if (SyncValues(m_numplayers, Address))
|
|
||||||
{
|
|
||||||
// Add it to the selector
|
|
||||||
m_selector.Add(Incoming);
|
|
||||||
Event->SendEvent(HOST_NEWPLAYER);
|
|
||||||
m_numplayers++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Event->AppendText(_("ERROR : Unable to establish UDP connection !\n"));
|
|
||||||
Incoming.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
unsigned char recv;
|
|
||||||
int socket_nb;
|
|
||||||
size_t recv_size;
|
|
||||||
sf::Socket::Status recv_status;
|
|
||||||
socket_nb = GetSocket(Socket);
|
|
||||||
|
|
||||||
if ((recv_status = Socket.Receive((char *)&recv, 1, recv_size)) == sf::Socket::Done)
|
|
||||||
{
|
|
||||||
#ifdef NET_DEBUG
|
|
||||||
char recv_str[32];
|
|
||||||
sprintf(recv_str, "received: 0x%02x | %c\n", recv, recv);
|
|
||||||
Event->AppendText(wxString::FromAscii(recv_str));
|
|
||||||
#endif
|
|
||||||
OnServerData(socket_nb, recv);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (recv_status == sf::Socket::Disconnected)
|
|
||||||
{
|
|
||||||
Event->SendEvent(HOST_PLAYERLEFT);
|
|
||||||
m_numplayers--;
|
|
||||||
|
|
||||||
std::string player_left = m_client[socket_nb].nick;
|
|
||||||
Event->AppendText( wxString::FromAscii(StringFromFormat("*Player : %s left the game.\n\n",
|
|
||||||
player_left.c_str()).c_str()) );
|
|
||||||
|
|
||||||
// We need to adjust the struct...
|
|
||||||
for (int j = socket_nb; j < m_numplayers; j++)
|
|
||||||
{
|
|
||||||
m_client[j].socket = m_client[j+1].socket;
|
|
||||||
m_client[j].nick = m_client[j+1].nick;
|
|
||||||
m_client[j].ready = m_client[j+1].ready;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send disconnected message to all
|
|
||||||
unsigned char send = 0x11;
|
|
||||||
unsigned int str_size = (int)player_left.size();
|
|
||||||
|
|
||||||
for (int j=0; j < m_numplayers ; j++)
|
|
||||||
{
|
|
||||||
m_client[j].socket.Send((const char*)&send, 1);
|
|
||||||
m_client[j].socket.Send((const char*)&str_size, 4);
|
|
||||||
m_client[j].socket.Send(player_left.c_str(), (int)str_size + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Hopefully this should never happen, the client is not
|
|
||||||
// Even warned that he is being dropped...
|
|
||||||
Event->SendEvent(HOST_ERROR, m_client[socket_nb].nick);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_selector.Remove(Socket);
|
|
||||||
Socket.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_CriticalSection.Leave();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(TestDestroy())
|
|
||||||
{
|
|
||||||
// Stop listening
|
|
||||||
m_socket.Close();
|
|
||||||
|
|
||||||
// Delete the Thread and close clients sockets
|
|
||||||
for (int i=0; i < m_numplayers ; i++)
|
|
||||||
m_client[i].socket.Close();
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ServerSide::SyncValues(unsigned char socketnb, sf::IPAddress Address)
|
|
||||||
{
|
|
||||||
sf::SocketTCP Socket = m_client[socketnb].socket;
|
|
||||||
|
|
||||||
std::string buffer_str = m_netptr->GetSelectedGame();
|
|
||||||
char *buffer = NULL;
|
|
||||||
unsigned char init_number;
|
|
||||||
u32 buffer_size = (u32)buffer_str.size();
|
|
||||||
size_t received;
|
|
||||||
bool errorUDP = false;
|
|
||||||
|
|
||||||
// First, Send the number of connected clients & netmodel
|
|
||||||
Socket.Send((const char *)&m_numplayers, 1);
|
|
||||||
Socket.Send((const char *)&m_netmodel, 4);
|
|
||||||
|
|
||||||
// Send the Game String
|
|
||||||
Socket.Send((const char *)&buffer_size, 4);
|
|
||||||
Socket.Send(buffer_str.c_str(), buffer_size + 1);
|
|
||||||
|
|
||||||
// Send the host Nickname
|
|
||||||
buffer_size = (u32)m_nick.size();
|
|
||||||
Socket.Send((const char *)&buffer_size, 4);
|
|
||||||
Socket.Send(m_nick.c_str(), buffer_size + 1);
|
|
||||||
|
|
||||||
// Read client's UDP Port
|
|
||||||
Socket.Receive((char *)&m_client[m_numplayers].port, sizeof(short), received);
|
|
||||||
|
|
||||||
// Read returned nickname
|
|
||||||
Socket.Receive((char *)&buffer_size, 4, received);
|
|
||||||
buffer = new char[buffer_size + 1];
|
|
||||||
Socket.Receive(buffer, buffer_size + 1, received);
|
|
||||||
|
|
||||||
m_client[socketnb].nick = std::string(buffer);
|
|
||||||
m_client[socketnb].ready = false;
|
|
||||||
|
|
||||||
|
|
||||||
// Test UDP Socket
|
|
||||||
|
|
||||||
if (m_socketUDP.Send((const char*)&m_numplayers, 1, Address, m_client[m_numplayers].port) == sf::Socket::Done)
|
|
||||||
{
|
|
||||||
// Test UDP Socket Receive, 2s timeout
|
|
||||||
if (!RecvT(m_socketUDP, (char*)&init_number, 1, received, 2))
|
|
||||||
{
|
|
||||||
ERROR_LOG(NETPLAY,"Connection to client timed out or closed");
|
|
||||||
errorUDP = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ERROR_LOG(NETPLAY,"Failed to send info! closing connection!");
|
|
||||||
errorUDP = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the client has the game
|
|
||||||
Socket.Receive((char *)&init_number, 1, received);
|
|
||||||
|
|
||||||
delete[] buffer;
|
|
||||||
|
|
||||||
if (!errorUDP)
|
|
||||||
{
|
|
||||||
// Send to all connected clients
|
|
||||||
if (m_numplayers > 0)
|
|
||||||
{
|
|
||||||
unsigned char send = 0x10;
|
|
||||||
buffer_size = (int)m_client[socketnb].nick.size();
|
|
||||||
for (int i=0; i < m_numplayers ; i++)
|
|
||||||
{
|
|
||||||
// Do not send to connecting player
|
|
||||||
if (i == socketnb)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
m_client[i].socket.Send((const char *)&send, 1); // Init new connection
|
|
||||||
m_client[i].socket.Send((const char *)&init_number, 1); // Send Game found ?
|
|
||||||
m_client[i].socket.Send((const char *)&buffer_size, 4); // Send client nickname
|
|
||||||
m_client[i].socket.Send(m_client[socketnb].nick.c_str(), buffer_size + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Event->AppendText( wxString::FromAscii(StringFromFormat("*Connection established to %s (%s:%d)\n",
|
|
||||||
m_client[socketnb].nick.c_str(), Address.ToString().c_str(), m_client[m_numplayers].port).c_str()));
|
|
||||||
|
|
||||||
if (init_number != 0x1F) // Not Found
|
|
||||||
//for (int i = 0; i < 4; i++)
|
|
||||||
//note for sl1nk3 : what is that for doing there?
|
|
||||||
Event->AppendText(_("WARNING : Game Not Found on Client Side !\n"));
|
|
||||||
|
|
||||||
// UDP connecton successful
|
|
||||||
init_number = 0x16;
|
|
||||||
Socket.Send((const char *)&init_number, 1);
|
|
||||||
}
|
|
||||||
else // UDP Error, disconnect client
|
|
||||||
{
|
|
||||||
// UDP connecton failed
|
|
||||||
init_number = 0x17;
|
|
||||||
Socket.Send((const char *)&init_number, 1);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerSide::Write(int socknb, const char *data, size_t size, long *ping)
|
|
||||||
{
|
|
||||||
wxCriticalSectionLocker lock(m_CriticalSection);
|
|
||||||
|
|
||||||
if (ping != NULL)
|
|
||||||
{
|
|
||||||
// Ask for ping
|
|
||||||
unsigned char value = 0x15;
|
|
||||||
size_t recv_size;
|
|
||||||
u32 four_bytes = 0x101A7FA6;
|
|
||||||
|
|
||||||
Common::Timer timer;
|
|
||||||
timer.Start();
|
|
||||||
|
|
||||||
for (int i=0; i < m_numplayers ; i++)
|
|
||||||
{
|
|
||||||
m_client[i].socket.Send((const char*)&value, 1);
|
|
||||||
|
|
||||||
timer.Update();
|
|
||||||
m_client[i].socket.Send((const char*)&four_bytes, 4);
|
|
||||||
m_client[i].socket.Receive((char*)&four_bytes, 4, recv_size);
|
|
||||||
ping[i] = (long)timer.GetTimeDifference();
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send the data safely, without intefering with another call
|
|
||||||
m_client[socknb].socket.Send(data, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerSide::WriteUDP(int socknb, const char *data, size_t size)
|
|
||||||
{
|
|
||||||
wxCriticalSectionLocker lock(m_CriticalSection);
|
|
||||||
|
|
||||||
m_socketUDP.Send(data, size, m_client[socknb].address, m_client[socknb].port);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------
|
|
||||||
// CLIENT SIDE THREAD
|
|
||||||
//--------------------------------
|
|
||||||
|
|
||||||
ClientSide::ClientSide(NetPlay* netptr, sf::SocketTCP socket, sf::SocketUDP socketUDP, std::string addr, std::string nick)
|
|
||||||
: wxThread()
|
|
||||||
{
|
|
||||||
m_numplayers = 0;
|
|
||||||
m_data_received = false;
|
|
||||||
m_netmodel = 0;
|
|
||||||
m_socket = socket;
|
|
||||||
m_socketUDP = socketUDP;
|
|
||||||
m_port = m_socketUDP.GetPort();
|
|
||||||
m_netptr = netptr;
|
|
||||||
m_nick = nick;
|
|
||||||
m_addr = addr;
|
|
||||||
Event = new NetEvent(m_netptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClientSide::RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time)
|
|
||||||
{
|
|
||||||
sf::SelectorUDP Selector;
|
|
||||||
sf::IPAddress Addr;
|
|
||||||
unsigned short Port;
|
|
||||||
Selector.Add(Socket);
|
|
||||||
|
|
||||||
if (Selector.Wait(Time) > 0)
|
|
||||||
{
|
|
||||||
Socket.Receive(Data, Max, Recvd, Addr, Port);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void *ClientSide::Entry()
|
|
||||||
{
|
|
||||||
Event->AppendText(_("*Connection Request... "));
|
|
||||||
|
|
||||||
// If we get here, the connection is already accepted, however the game may be full
|
|
||||||
if (SyncValues())
|
|
||||||
{
|
|
||||||
// Tell the server if the client has the game
|
|
||||||
CheckGameFound();
|
|
||||||
|
|
||||||
// Check UDP connection
|
|
||||||
unsigned char value;
|
|
||||||
size_t val_sz;
|
|
||||||
m_socket.Receive((char *)&value, 1, val_sz);
|
|
||||||
if (value == 0x16) // UDP connection successful
|
|
||||||
{
|
|
||||||
Event->AppendText(_("Connection successful !\n"));
|
|
||||||
Event->AppendText( wxString::FromAscii( StringFromFormat("*Connection established to %s (%s)\n*Game is : %s\n",
|
|
||||||
m_hostnick.c_str(), m_addr.c_str(), m_selectedgame.c_str()).c_str()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Event->AppendText(_("UDP Connection FAILED !\nERROR : Unable to establish UDP Connection, please Check UDP Port forwarding !\n"));
|
|
||||||
m_socket.Close();
|
|
||||||
Event->SendEvent(HOST_ERROR);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // Server is Full
|
|
||||||
{
|
|
||||||
m_socket.Close();
|
|
||||||
Event->SendEvent(HOST_FULL);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_netptr->ChangeSelectedGame(m_selectedgame);
|
|
||||||
Event->SendEvent(HOST_NEWPLAYER, "NULL", m_netmodel);
|
|
||||||
Event->SendEvent(GUI_UPDATE);
|
|
||||||
|
|
||||||
m_selector.Add(m_socket);
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
unsigned char recv;
|
|
||||||
size_t recv_size;
|
|
||||||
sf::Socket::Status recv_status;
|
|
||||||
|
|
||||||
// we use a selector because of the useful timeout
|
|
||||||
if (m_selector.Wait(0.5) > 0)
|
|
||||||
{
|
|
||||||
m_CriticalSection.Enter();
|
|
||||||
|
|
||||||
if ((recv_status = m_socket.Receive((char *)&recv, 1, recv_size)) == sf::Socket::Done)
|
|
||||||
{
|
|
||||||
#ifdef NET_DEBUG
|
|
||||||
char recv_str[32];
|
|
||||||
sprintf(recv_str, "received: 0x%02x | %c\n", recv, recv);
|
|
||||||
Event->AppendText(wxString::FromAscii(recv_str));
|
|
||||||
#endif
|
|
||||||
OnClientData(recv);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (recv_status == sf::Socket::Disconnected)
|
|
||||||
{
|
|
||||||
Event->SendEvent(HOST_DISCONNECTED);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Event->SendEvent(HOST_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_selector.Remove(m_socket);
|
|
||||||
m_socket.Close();
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_CriticalSection.Leave();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(TestDestroy())
|
|
||||||
{
|
|
||||||
m_socket.Close();
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClientSide::SyncValues()
|
|
||||||
{
|
|
||||||
unsigned int buffer_size = (int)m_nick.size();
|
|
||||||
unsigned char byterecv;
|
|
||||||
bool errorUDP;
|
|
||||||
char *buffer = NULL;
|
|
||||||
size_t recv_size;
|
|
||||||
|
|
||||||
unsigned short server_port;
|
|
||||||
std::string host = m_addr.substr(0, m_addr.find(':'));
|
|
||||||
TryParseInt(m_addr.substr(m_addr.find(':')+1).c_str(), (int *)&server_port);
|
|
||||||
|
|
||||||
// First, Read the init number : nbplayers (0-2) or server full (0x12)
|
|
||||||
m_socket.Receive((char *)&m_numplayers, 1, recv_size);
|
|
||||||
if (m_numplayers == 0x12)
|
|
||||||
return false;
|
|
||||||
m_socket.Receive((char *)&m_netmodel, 4, recv_size);
|
|
||||||
|
|
||||||
// Send client's UDP Port
|
|
||||||
// TODO : fix port sending. it sends the set port in the main window. not the actual using port
|
|
||||||
// when checked to use random this will , ofcourse , send wrong port
|
|
||||||
m_socket.Send((const char *)&m_port, sizeof(short));
|
|
||||||
|
|
||||||
// Send client's nickname
|
|
||||||
m_socket.Send((const char *)&buffer_size, 4);
|
|
||||||
m_socket.Send(m_nick.c_str(), buffer_size + 1);
|
|
||||||
|
|
||||||
// Read the Game String
|
|
||||||
m_socket.Receive((char *)&buffer_size, 4, recv_size);
|
|
||||||
buffer = new char[buffer_size + 1];
|
|
||||||
m_socket.Receive(buffer, buffer_size + 1, recv_size);
|
|
||||||
m_selectedgame = std::string(buffer);
|
|
||||||
|
|
||||||
// Read the host Nickname
|
|
||||||
m_socket.Receive((char *)&buffer_size, 4, recv_size);
|
|
||||||
buffer = new char[buffer_size + 1];
|
|
||||||
m_socket.Receive(buffer, buffer_size + 1, recv_size);
|
|
||||||
m_hostnick = std::string(buffer);
|
|
||||||
|
|
||||||
|
|
||||||
// Test UDP Socket
|
|
||||||
|
|
||||||
if (m_socketUDP.Send((const char*)&m_numplayers, 1, host.c_str(), server_port) == sf::Socket::Done)
|
|
||||||
{
|
|
||||||
// Test UDP Socket Receive, 2s timeout
|
|
||||||
if (!RecvT(m_socketUDP, (char*)&byterecv, 1, recv_size, 2))
|
|
||||||
{
|
|
||||||
errorUDP = true;
|
|
||||||
ERROR_LOG(NETPLAY,"Connection Timed Out or closed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
errorUDP = true;
|
|
||||||
|
|
||||||
delete[] buffer;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClientSide::CheckGameFound()
|
|
||||||
{
|
|
||||||
unsigned char send_value;
|
|
||||||
|
|
||||||
// Check if the game selected by Host is in Client's Game List
|
|
||||||
m_netptr->IsGameFound(&send_value, m_selectedgame);
|
|
||||||
|
|
||||||
if (send_value == 0x1F) // Found
|
|
||||||
{
|
|
||||||
m_socket.Send((const char *)&send_value, 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_socket.Send((const char *)&send_value, 1);
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
Event->AppendText(wxT("WARNING : You do not have the Selected Game !\n"));
|
|
||||||
NOTICE_LOG(NETPLAY, "Game '%s' not found!", m_selectedgame.c_str());
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClientSide::Write(const char *data, size_t size, long *ping)
|
|
||||||
{
|
|
||||||
wxCriticalSectionLocker lock(m_CriticalSection);
|
|
||||||
|
|
||||||
if (ping != NULL)
|
|
||||||
{
|
|
||||||
// Ask for ping
|
|
||||||
unsigned char value = 0x15;
|
|
||||||
size_t recv_size;
|
|
||||||
int four_bytes = 0x101A7FA6;
|
|
||||||
|
|
||||||
Common::Timer timer;
|
|
||||||
timer.Start();
|
|
||||||
|
|
||||||
m_socket.Send((const char*)&value, 1);
|
|
||||||
m_socket.Send((const char*)&four_bytes, 4);
|
|
||||||
m_socket.Receive((char*)&four_bytes, 4, recv_size);
|
|
||||||
|
|
||||||
*ping = (long)timer.GetTimeElapsed();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_socket.Send(data, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClientSide::WriteUDP(const char *data, size_t size)
|
|
||||||
{
|
|
||||||
wxCriticalSectionLocker lock(m_CriticalSection);
|
|
||||||
|
|
||||||
unsigned short server_port;
|
|
||||||
std::string host = m_addr.substr(0, m_addr.find(':'));
|
|
||||||
TryParseInt(m_addr.substr(m_addr.find(':')+1).c_str(), (int *)&server_port);
|
|
||||||
|
|
||||||
m_socketUDP.Send(data, size, host.c_str(), server_port);
|
|
||||||
}
|
|
|
@ -1,128 +0,0 @@
|
||||||
// Copyright (C) 2003 Dolphin Project.
|
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, version 2.0.
|
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License 2.0 for more details.
|
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
|
||||||
// If not, see http://www.gnu.org/licenses/
|
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
|
||||||
// http://code.google.com/p/dolphin-emu/
|
|
||||||
|
|
||||||
#ifndef _NETSOCKETS_H_
|
|
||||||
#define _NETSOCKETS_H_
|
|
||||||
|
|
||||||
#include <SFML/Network.hpp>
|
|
||||||
|
|
||||||
class NetPlay;
|
|
||||||
|
|
||||||
#include "Common.h"
|
|
||||||
#include "NetStructs.h"
|
|
||||||
|
|
||||||
#include <wx/wx.h>
|
|
||||||
|
|
||||||
|
|
||||||
struct Clients {
|
|
||||||
std::string nick;
|
|
||||||
sf::SocketTCP socket;
|
|
||||||
unsigned short port;
|
|
||||||
sf::IPAddress address;
|
|
||||||
bool ready;
|
|
||||||
};
|
|
||||||
|
|
||||||
class NetEvent
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NetEvent(NetPlay* netptr) { m_netptr = netptr; }
|
|
||||||
~NetEvent() {};
|
|
||||||
|
|
||||||
void SendEvent(int EventType, std::string="NULL", int=NULL);
|
|
||||||
void AppendText(const wxString text);
|
|
||||||
|
|
||||||
private:
|
|
||||||
NetPlay *m_netptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ServerSide : public wxThread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ServerSide(NetPlay* netptr, sf::SocketTCP, sf::SocketUDP, int netmodel, std::string nick);
|
|
||||||
~ServerSide() {};
|
|
||||||
|
|
||||||
virtual void *Entry();
|
|
||||||
|
|
||||||
void Write(int socknb, const char *data, size_t size, long *ping=NULL);
|
|
||||||
void WriteUDP(int socknb, const char *data, size_t size);
|
|
||||||
bool isNewPadData(u32 *netValues, bool current, int client=0);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool SyncValues(unsigned char, sf::IPAddress);
|
|
||||||
bool RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time = 0);
|
|
||||||
char GetSocket(sf::SocketTCP Socket);
|
|
||||||
void OnServerData(int sock, unsigned char data);
|
|
||||||
void IsEveryoneReady();
|
|
||||||
|
|
||||||
NetPlay *m_netptr;
|
|
||||||
NetEvent *Event;
|
|
||||||
|
|
||||||
u32 m_netvalues[3][3];
|
|
||||||
bool m_data_received; // New Pad data received ?
|
|
||||||
|
|
||||||
unsigned char m_numplayers;
|
|
||||||
int m_netmodel;
|
|
||||||
std::string m_nick;
|
|
||||||
|
|
||||||
Clients m_client[3]; // Connected client objects
|
|
||||||
sf::SelectorTCP m_selector;
|
|
||||||
sf::SocketTCP m_socket; // Server 'listening' socket
|
|
||||||
sf::SocketUDP m_socketUDP;
|
|
||||||
|
|
||||||
wxCriticalSection m_CriticalSection;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ClientSide : public wxThread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ClientSide(NetPlay* netptr, sf::SocketTCP, sf::SocketUDP, std::string addr, std::string nick);
|
|
||||||
~ClientSide() {}
|
|
||||||
|
|
||||||
virtual void *Entry();
|
|
||||||
|
|
||||||
void Write(const char *data, size_t size, long *ping=NULL);
|
|
||||||
void WriteUDP(const char *data, size_t size);
|
|
||||||
bool isNewPadData(u32 *netValues, bool current, bool isVersus=true);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool SyncValues();
|
|
||||||
void CheckGameFound();
|
|
||||||
void OnClientData(unsigned char data);
|
|
||||||
bool RecvT(sf::SocketUDP Socket, char * Data, size_t Max, size_t& Recvd, float Time=0);
|
|
||||||
|
|
||||||
NetPlay *m_netptr;
|
|
||||||
NetEvent *Event;
|
|
||||||
|
|
||||||
u32 m_netvalues[3][3];
|
|
||||||
bool m_data_received; // New Pad data received ?
|
|
||||||
|
|
||||||
unsigned char m_numplayers;
|
|
||||||
int m_netmodel;
|
|
||||||
std::string m_nick;
|
|
||||||
std::string m_hostnick;
|
|
||||||
std::string m_selectedgame;
|
|
||||||
|
|
||||||
sf::SelectorTCP m_selector;
|
|
||||||
sf::SocketTCP m_socket; // Client I/O socket
|
|
||||||
sf::SocketUDP m_socketUDP;
|
|
||||||
unsigned short m_port;
|
|
||||||
std::string m_addr; // Contains the server addr
|
|
||||||
|
|
||||||
wxCriticalSection m_CriticalSection;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,26 +0,0 @@
|
||||||
// Copyright (C) 2003 Dolphin Project.
|
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, version 2.0.
|
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License 2.0 for more details.
|
|
||||||
|
|
||||||
// A copy of the GPL 2.0 should have been included with the program.
|
|
||||||
// If not, see http://www.gnu.org/licenses/
|
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
|
||||||
// http://code.google.com/p/dolphin-emu/
|
|
||||||
|
|
||||||
#ifndef _NETSTRUCTS_H
|
|
||||||
#define _NETSTRUCTS_H
|
|
||||||
|
|
||||||
struct Netpads {
|
|
||||||
int nHi[128];
|
|
||||||
int nLow[128];
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // _NETSTRUCTS_H
|
|
|
@ -15,557 +15,373 @@
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "NetSockets.h"
|
#include "NetPlay.h"
|
||||||
#include "NetWindow.h"
|
#include "NetWindow.h"
|
||||||
#include "FileUtil.h"
|
|
||||||
|
|
||||||
// Main Frame window
|
#include <sstream>
|
||||||
|
|
||||||
BEGIN_EVENT_TABLE(NetPlay, wxFrame)
|
#define _connect_macro_( b, f, c, s ) (b)->Connect( wxID_ANY, (c), wxCommandEventHandler( f ), (wxObject*)0, (wxEvtHandler*)s )
|
||||||
EVT_BUTTON(ID_BUTTON_JOIN, NetPlay::OnJoin)
|
|
||||||
EVT_BUTTON(ID_BUTTON_HOST, NetPlay::OnHost)
|
|
||||||
EVT_BUTTON(ID_BUTTON_EXIT, NetPlay::OnDisconnect)
|
|
||||||
|
|
||||||
EVT_HOST_COMMAND(wxID_ANY, NetPlay::OnNetEvent)
|
#define NETPLAY_TITLEBAR "Dolphin NetPlay"
|
||||||
|
|
||||||
EVT_CHECKBOX(ID_READY, NetPlay::OnGUIEvent)
|
BEGIN_EVENT_TABLE(NetPlayDiag, wxFrame)
|
||||||
EVT_CHECKBOX(ID_RECORD, NetPlay::OnGUIEvent)
|
EVT_COMMAND(wxID_ANY, wxEVT_THREAD, NetPlayDiag::OnThread)
|
||||||
EVT_BUTTON(ID_CHANGEGAME, NetPlay::OnGUIEvent)
|
|
||||||
EVT_BUTTON(ID_BUTTON_GETIP, NetPlay::OnGUIEvent)
|
|
||||||
EVT_BUTTON(ID_BUTTON_GETPING, NetPlay::OnGUIEvent)
|
|
||||||
EVT_BUTTON(ID_BUTTON_CHAT, NetPlay::OnGUIEvent)
|
|
||||||
EVT_TEXT_ENTER(ID_CHAT, NetPlay::OnGUIEvent)
|
|
||||||
EVT_BUTTON(ID_BUTTON_QUIT, NetPlay::OnDisconnect)
|
|
||||||
EVT_CLOSE(NetPlay::OnQuit)
|
|
||||||
END_EVENT_TABLE()
|
END_EVENT_TABLE()
|
||||||
|
|
||||||
NetPlay::NetPlay(wxWindow* parent, std::string GamePaths, std::string GameNames) :
|
NetPlay* netplay_ptr = NULL;
|
||||||
wxFrame(parent, wxID_ANY, _T("Net Play"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE & ~ wxMAXIMIZE_BOX & ~ wxCLOSE_BOX)
|
|
||||||
|
NetPlaySetupDiag::NetPlaySetupDiag(wxWindow* parent, const CGameListCtrl* const game_list)
|
||||||
|
: wxFrame(parent, wxID_ANY, wxT(NETPLAY_TITLEBAR), wxDefaultPosition, wxDefaultSize)
|
||||||
|
, m_game_list(game_list)
|
||||||
{
|
{
|
||||||
m_selectedGame = 'a'; m_hostaddr = 'a';
|
//PanicAlert("ALERT: NetPlay is not 100%% functional !!!!");
|
||||||
m_games = GameNames; m_paths = GamePaths;
|
|
||||||
m_isHosting = 2; m_ready = m_clients_ready = false;
|
|
||||||
m_loopframe = m_frame = m_NetModel = m_numClients = 0;
|
|
||||||
|
|
||||||
DrawGUI();
|
wxPanel* const panel = new wxPanel(this);
|
||||||
}
|
|
||||||
|
|
||||||
NetPlay::~NetPlay()
|
// top row
|
||||||
{
|
wxStaticText* const nick_lbl = new wxStaticText(panel, wxID_ANY, wxT("Nickname :"), wxDefaultPosition, wxDefaultSize);
|
||||||
ConfigIni.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX));
|
m_nickname_text = new wxTextCtrl(panel, wxID_ANY, wxT("Player"));
|
||||||
|
|
||||||
ConfigIni.Set("Netplay", "Nickname", m_nick);
|
wxBoxSizer* const nick_szr = new wxBoxSizer(wxHORIZONTAL);
|
||||||
ConfigIni.Set("Netplay", "UsedPort", (int)m_port);
|
nick_szr->Add(nick_lbl, 0, wxCENTER);
|
||||||
ConfigIni.Set("Netplay", "LastIP", m_address);
|
nick_szr->Add(m_nickname_text, 0, wxALL, 5);
|
||||||
|
|
||||||
ConfigIni.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX));
|
|
||||||
}
|
|
||||||
|
|
||||||
void NetPlay::OnJoin(wxCommandEvent& WXUNUSED(event))
|
// tabs
|
||||||
{
|
wxNotebook* const notebook = new wxNotebook(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize);
|
||||||
unsigned short server_port;
|
wxPanel* const connect_tab = new wxPanel(notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize);
|
||||||
|
notebook->AddPage(connect_tab, wxT("Connect"));
|
||||||
|
wxPanel* const host_tab = new wxPanel(notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize);
|
||||||
|
notebook->AddPage(host_tab, wxT("Host"));
|
||||||
|
|
||||||
m_address = std::string(m_ConAddr->GetValue().mb_str());
|
|
||||||
m_nick = std::string(m_SetNick->GetValue().mb_str());
|
|
||||||
|
|
||||||
sf::IPAddress host = m_address.substr(0, m_address.find(':'));
|
// connect tab
|
||||||
std::string port_str = m_address.substr(m_address.find(':') + 1);
|
|
||||||
|
|
||||||
TryParseUInt(port_str, (u32*)&server_port); // Server port
|
|
||||||
TryParseUInt((const char *)m_SetPort->GetValue().mb_str(), (u32*)&m_port); // User port
|
|
||||||
|
|
||||||
if (m_nick.size() > 255)
|
|
||||||
m_nick = m_nick.substr(0 , 255);
|
|
||||||
|
|
||||||
SetTitle(wxT("Net Play : Connecting to Host..."));
|
|
||||||
|
|
||||||
// Create the client socket
|
|
||||||
sf::SocketTCP sock_client;
|
|
||||||
sf::SocketUDP sock_client_UDP;
|
|
||||||
|
|
||||||
if (sock_client.Connect(server_port, host, 1.5) == sf::Socket::Done)
|
|
||||||
{
|
{
|
||||||
// Try to Bind the UDP Socket
|
wxStaticText* const ip_lbl = new wxStaticText(connect_tab, wxID_ANY, wxT("Address :"), wxDefaultPosition, wxDefaultSize);
|
||||||
if (sock_client_UDP.Bind(m_port))
|
m_connect_ip_text = new wxTextCtrl(connect_tab, wxID_ANY, wxT("localhost"));
|
||||||
{
|
wxStaticText* const port_lbl = new wxStaticText(connect_tab, wxID_ANY, wxT("Port :"), wxDefaultPosition, wxDefaultSize);
|
||||||
m_sock_client = new ClientSide(this, sock_client, sock_client_UDP, m_address, m_nick);
|
m_connect_port_text = new wxTextCtrl(connect_tab, wxID_ANY, wxT("2626"));
|
||||||
m_sock_client->Create();
|
|
||||||
m_sock_client->Run();
|
|
||||||
|
|
||||||
// Create the GUI
|
wxButton* const connect_btn = new wxButton(connect_tab, wxID_ANY, wxT("Connect"));
|
||||||
m_isHosting = false;
|
//connect_button->Disable();
|
||||||
DrawNetWindow();
|
_connect_macro_(connect_btn, NetPlaySetupDiag::OnJoin, wxEVT_COMMAND_BUTTON_CLICKED, this);
|
||||||
}
|
|
||||||
else
|
wxStaticText* const alert_lbl = new wxStaticText(connect_tab, wxID_ANY
|
||||||
{
|
, wxT("ALERT:\n\nNetPlay will currently only work properly when using the following settings:\n")
|
||||||
SetTitle(wxT("Net Play"));
|
wxT(" - Dual Core [OFF]\n - DSP LLE Plugin\n - DSPLLE on thread [OFF]\n - Manually set the exact number of controller that will be used to [Standard Controller]")
|
||||||
PanicAlert("Can't Bind UDP socket on the specified Port: %d ! \n"
|
wxT("\n\nAll players should try to use the same Dolphin version and settings.")
|
||||||
"Make sure port is forwarded and not in use !", m_port);
|
wxT("\nDisable all memory cards or send them to all players before starting.")
|
||||||
}
|
wxT("\nWiimote support has not been implemented.\nWii games will likely desync for other reasons as well.")
|
||||||
|
wxT("\n\nYou must forward TCP port to host!!")
|
||||||
|
, wxDefaultPosition, wxDefaultSize);
|
||||||
|
|
||||||
|
wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
top_szr->Add(ip_lbl, 0, wxCENTER | wxRIGHT, 5);
|
||||||
|
top_szr->Add(m_connect_ip_text, 3);
|
||||||
|
top_szr->Add(port_lbl, 0, wxCENTER | wxRIGHT | wxLEFT, 5);
|
||||||
|
top_szr->Add(m_connect_port_text, 1);
|
||||||
|
|
||||||
|
wxBoxSizer* const con_szr = new wxBoxSizer(wxVERTICAL);
|
||||||
|
con_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5);
|
||||||
|
con_szr->AddStretchSpacer(1);
|
||||||
|
con_szr->Add(alert_lbl, 0, wxLEFT | wxRIGHT | wxEXPAND, 5);
|
||||||
|
con_szr->AddStretchSpacer(1);
|
||||||
|
con_szr->Add(connect_btn, 0, wxALL | wxALIGN_RIGHT, 5);
|
||||||
|
|
||||||
|
connect_tab->SetSizerAndFit(con_szr);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// host tab
|
||||||
{
|
{
|
||||||
SetTitle(wxT("Net Play"));
|
wxStaticText* const port_lbl = new wxStaticText(host_tab, wxID_ANY, wxT("Port :"), wxDefaultPosition, wxDefaultSize);
|
||||||
PanicAlert("Can't connect to the specified IP Address ! \nMake sure Hosting port is forwarded !");
|
m_host_port_text = new wxTextCtrl(host_tab, wxID_ANY, wxT("2626"));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NetPlay::OnHost(wxCommandEvent& WXUNUSED(event))
|
wxButton* const host_btn = new wxButton(host_tab, wxID_ANY, wxT("Host"));
|
||||||
{
|
//host_button->Disable();
|
||||||
TryParseInt(m_SetPort->GetValue().mb_str(), (int*)&m_port);
|
_connect_macro_(host_btn, NetPlaySetupDiag::OnHost, wxEVT_COMMAND_BUTTON_CLICKED, this);
|
||||||
|
|
||||||
m_nick = std::string(m_SetNick->GetValue().mb_str());
|
m_game_lbox = new wxListBox(host_tab, wxID_ANY);
|
||||||
|
std::istringstream ss(game_list->GetGameNames());
|
||||||
|
std::string game;
|
||||||
|
while (std::getline(ss,game))
|
||||||
|
m_game_lbox->Append(wxString(game.c_str(), *wxConvCurrent));
|
||||||
|
|
||||||
if (m_GameList->GetSelection() == wxNOT_FOUND) {
|
wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL);
|
||||||
PanicAlert("No Game Selected ! Please select a Game...");
|
top_szr->Add(port_lbl, 0, wxCENTER | wxRIGHT, 5);
|
||||||
return;
|
top_szr->Add(m_host_port_text, 0);
|
||||||
}
|
|
||||||
if (!m_SetPort->GetValue().size() || m_port < 1000 || m_port > 65535) {
|
|
||||||
PanicAlert("Bad Port entered (%d) ! Please enter a working socket port...", m_port);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (m_nick.size() > 255)
|
|
||||||
m_nick = m_nick.substr(0 , 255);
|
|
||||||
|
|
||||||
m_NetModel = m_NetMode->GetSelection();
|
wxBoxSizer* const host_szr = new wxBoxSizer(wxVERTICAL);
|
||||||
m_selectedGame = std::string(m_GameList_str[m_GameList->GetSelection()].mb_str());
|
host_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5);
|
||||||
NOTICE_LOG(NETPLAY,"Game has been set to : %s \n",m_selectedGame.c_str());
|
host_szr->Add(m_game_lbox, 1, wxLEFT | wxRIGHT | wxEXPAND, 5);
|
||||||
|
host_szr->Add(host_btn, 0, wxALL | wxALIGN_RIGHT, 5);
|
||||||
|
|
||||||
// Create the listening socket
|
host_tab->SetSizerAndFit(host_szr);
|
||||||
sf::SocketTCP sock_server;
|
|
||||||
sf::SocketUDP sock_server_UDP;
|
|
||||||
|
|
||||||
// Start the listening socket and bind UDP socket port
|
|
||||||
if (sock_server.Listen(m_port) && sock_server_UDP.Bind(m_port))
|
|
||||||
{
|
|
||||||
m_sock_server = new ServerSide(this, sock_server, sock_server_UDP, m_NetModel, m_nick);
|
|
||||||
m_sock_server->Create();
|
|
||||||
m_sock_server->Run();
|
|
||||||
|
|
||||||
// Create the GUI
|
|
||||||
m_isHosting = true;
|
|
||||||
DrawNetWindow();
|
|
||||||
m_Logging->AppendText(wxString::Format(wxT("WARNING : Hosting requires port to be forwarded in firewall!\n")
|
|
||||||
wxT("*Creation Successful on port %d : Waiting for peers...\n"), m_port));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PanicAlert("Could not listen at specified port !\nMake sure hosting port is not in use !");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NetPlay::DrawGUI()
|
|
||||||
{
|
|
||||||
int str_end = -1;
|
|
||||||
int str_start = -1;
|
|
||||||
wxArrayString netmodes_str;
|
|
||||||
|
|
||||||
for(int i = 0; i < (int)m_games.size(); i++)
|
|
||||||
{
|
|
||||||
str_start = str_end + 1;
|
|
||||||
str_end = (int)m_games.find('\n', str_start);
|
|
||||||
std::string buffer = m_games.substr(str_start, str_end - str_start);
|
|
||||||
|
|
||||||
if (str_end == (int)std::string::npos || buffer.size() < 1)
|
|
||||||
break; // we reached the end of the string
|
|
||||||
|
|
||||||
m_GameList_str.Add(wxString(buffer.c_str(), *wxConvCurrent));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
netmodes_str.Add(wxT("P2P Versus (2 players, faster)"));
|
// bottom row
|
||||||
// TODO : netmodes_str.Add(wxT("Server Mode (4 players, slower)"));
|
wxButton* const quit_btn = new wxButton(panel, wxID_ANY, wxT("Quit"));
|
||||||
|
_connect_macro_(quit_btn, NetPlaySetupDiag::OnQuit, wxEVT_COMMAND_BUTTON_CLICKED, this);
|
||||||
|
|
||||||
wxPanel *panel = new wxPanel(this);
|
// main sizer
|
||||||
|
wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL);
|
||||||
|
main_szr->Add(nick_szr, 0, wxALL | wxALIGN_RIGHT, 5);
|
||||||
|
main_szr->Add(notebook, 1, wxLEFT | wxRIGHT | wxEXPAND, 5);
|
||||||
|
main_szr->Add(quit_btn, 0, wxALL | wxALIGN_RIGHT, 5);
|
||||||
|
|
||||||
// Tabs
|
panel->SetSizerAndFit(main_szr);
|
||||||
m_Notebook = new wxNotebook(panel, ID_NOTEBOOK, wxDefaultPosition, wxDefaultSize);
|
|
||||||
m_Tab_Connect = new wxPanel(m_Notebook, ID_TAB_CONN, wxDefaultPosition, wxDefaultSize);
|
|
||||||
m_Notebook->AddPage(m_Tab_Connect, wxT("Connect"));
|
|
||||||
m_Tab_Host = new wxPanel(m_Notebook, ID_TAB_HOST, wxDefaultPosition, wxDefaultSize);
|
|
||||||
m_Notebook->AddPage(m_Tab_Host, wxT("Host"));
|
|
||||||
|
|
||||||
// Tow window, Nickname & Port settings
|
//wxBoxSizer* const diag_szr = new wxBoxSizer(wxVERTICAL);
|
||||||
m_SetNick_text = new wxStaticText(panel, wxID_ANY, wxT(" Nickname : "), wxDefaultPosition, wxDefaultSize);
|
//diag_szr->Add(panel);
|
||||||
m_SetNick = new wxTextCtrl(panel, ID_SETNICK, wxT("LOLWUT!"), wxDefaultPosition, wxDefaultSize);
|
//SetSizerAndFit(diag_szr);
|
||||||
m_SetPort_text = new wxStaticText(panel, wxID_ANY, wxT(" Port to Use : "), wxDefaultPosition, wxDefaultSize);
|
|
||||||
m_SetPort = new wxTextCtrl(panel, ID_SETPORT, wxT("12345"), wxDefaultPosition, wxDefaultSize);
|
|
||||||
|
|
||||||
// CONNECTION TAB
|
|
||||||
m_ConAddr_text = new wxStaticText(m_Tab_Connect, wxID_ANY, wxT(" IP Address :"), wxDefaultPosition, wxDefaultSize);
|
|
||||||
m_ConAddr = new wxTextCtrl(m_Tab_Connect, ID_CONNADDR, wxT("127.0.0.1:12345"), wxDefaultPosition, wxSize(250,20), 0);
|
|
||||||
m_UseRandomPort = new wxCheckBox(m_Tab_Connect, ID_USE_RANDOMPORT, wxT("Use random client port for connection"));
|
|
||||||
m_JoinGame = new wxButton(m_Tab_Connect, ID_BUTTON_JOIN, wxT("Connect"), wxDefaultPosition, wxDefaultSize);
|
|
||||||
m_ExitWindowC = new wxButton(m_Tab_Connect, ID_BUTTON_EXIT, wxT("Quit"), wxDefaultPosition, wxDefaultSize);
|
|
||||||
|
|
||||||
// Sizers CONNECT
|
main_szr->SetSizeHints(this);
|
||||||
wxBoxSizer* sConnectTop = new wxBoxSizer(wxHORIZONTAL);
|
|
||||||
wxBoxSizer* sConnectSizer = new wxBoxSizer(wxVERTICAL);
|
|
||||||
|
|
||||||
sConnectTop->Add(m_ConAddr_text, 0, wxALL|wxALIGN_CENTER, 5);
|
|
||||||
sConnectTop->Add(m_ConAddr, 1, wxALL|wxEXPAND, 5);
|
|
||||||
sConnectTop->Add(m_JoinGame, 0, wxALL|wxALIGN_RIGHT, 5);
|
|
||||||
sConnectSizer->Add(sConnectTop, 0, wxALL|wxEXPAND, 5);
|
|
||||||
sConnectSizer->Add(m_UseRandomPort, 0, wxALL|wxALIGN_CENTER, 5);
|
|
||||||
sConnectSizer->Add(m_ExitWindowC, 0, wxALL|wxALIGN_CENTER, 5);
|
|
||||||
|
|
||||||
m_Tab_Connect->SetSizer(sConnectSizer);
|
|
||||||
|
|
||||||
// HOSTING TAB
|
|
||||||
m_GameList_text = new wxStaticText(m_Tab_Host, wxID_ANY,
|
|
||||||
wxT("Warning: Use a forwarded port ! Select Game and press Host :"), wxDefaultPosition, wxDefaultSize);
|
|
||||||
m_GameList = new wxListBox(m_Tab_Host, ID_GAMELIST, wxDefaultPosition, wxDefaultSize,
|
|
||||||
m_GameList_str, wxLB_SINGLE | wxLB_NEEDED_SB);
|
|
||||||
m_HostGame = new wxButton(m_Tab_Host, ID_BUTTON_HOST, wxT("Host"), wxDefaultPosition, wxDefaultSize);
|
|
||||||
m_ExitWindowH = new wxButton(m_Tab_Host, ID_BUTTON_EXIT, wxT("Quit"), wxDefaultPosition, wxDefaultSize);
|
|
||||||
m_NetMode = new wxChoice(m_Tab_Host, ID_NETMODE, wxDefaultPosition, wxDefaultSize, netmodes_str, 0, wxDefaultValidator);
|
|
||||||
m_NetMode->SetSelection(0);
|
|
||||||
|
|
||||||
|
|
||||||
// Sizers HOST
|
|
||||||
wxBoxSizer *sHostBox = new wxBoxSizer(wxVERTICAL);
|
|
||||||
wxBoxSizer *sHostBottom = new wxBoxSizer(wxHORIZONTAL);
|
|
||||||
|
|
||||||
sHostBottom->Add(m_NetMode, 0, wxALL|wxALIGN_CENTER, 5);
|
|
||||||
sHostBottom->AddStretchSpacer();
|
|
||||||
sHostBottom->Add(m_HostGame, 0, wxALL, 10);
|
|
||||||
sHostBottom->Add(m_ExitWindowH, 0, wxALL|wxALIGN_CENTER, 5);
|
|
||||||
|
|
||||||
sHostBox->Add(m_GameList_text, 0, wxALL|wxALIGN_CENTER, 5);
|
|
||||||
sHostBox->Add(m_GameList, 1, wxALL|wxEXPAND, 6);
|
|
||||||
sHostBox->Add(sHostBottom, 0, wxALL|wxEXPAND, 1);
|
|
||||||
|
|
||||||
|
|
||||||
m_Tab_Host->SetSizer(sHostBox);
|
|
||||||
|
|
||||||
// Main sizers
|
|
||||||
wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
|
|
||||||
wxBoxSizer* sMain_top = new wxBoxSizer(wxHORIZONTAL);
|
|
||||||
|
|
||||||
sMain_top->Add(m_SetNick_text, 0, wxALL|wxALIGN_CENTER, 3);
|
|
||||||
sMain_top->Add(m_SetNick, 1, wxALL|wxALIGN_CENTER, 3);
|
|
||||||
sMain_top->AddStretchSpacer();
|
|
||||||
sMain_top->Add(m_SetPort_text, 0, wxALL|wxALIGN_CENTER, 3);
|
|
||||||
sMain_top->Add(m_SetPort, 1, wxALL|wxALIGN_CENTER, 3);
|
|
||||||
|
|
||||||
sMain->Add(sMain_top, 0, wxALL|wxEXPAND, 5);
|
|
||||||
sMain->Add(m_Notebook, 1, wxALL|wxEXPAND, 5);
|
|
||||||
|
|
||||||
// Adjust panel to window's size, and set resizing minimum boundaries
|
|
||||||
panel->SetSizerAndFit(sMain);
|
|
||||||
sMain->SetSizeHints((wxWindow*)this);
|
|
||||||
|
|
||||||
if (ConfigIni.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)))
|
|
||||||
{
|
|
||||||
ConfigIni.Get("Netplay", "Nickname", &m_nick, "Unnamed");
|
|
||||||
ConfigIni.Get("Netplay", "UsedPort", (int*)&m_port, 12345);
|
|
||||||
ConfigIni.Get("Netplay", "LastIP", &m_address, "127.0.0.1:54321");
|
|
||||||
|
|
||||||
m_SetNick->SetValue(wxString::FromAscii(m_nick.c_str()));
|
|
||||||
m_SetPort->SetValue(wxString::Format(wxT("%d"), m_port));
|
|
||||||
m_ConAddr->SetValue(wxString::FromAscii(m_address.c_str()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Center(); Show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NetPlay::DrawNetWindow()
|
|
||||||
{
|
|
||||||
// Remove everything from the precedent GUI :D
|
|
||||||
DestroyChildren();
|
|
||||||
|
|
||||||
SetTitle(wxT("Net Play : Connection Window"));
|
|
||||||
|
|
||||||
wxPanel *panel = new wxPanel(this);
|
|
||||||
wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
|
|
||||||
wxBoxSizer* sTop = new wxBoxSizer(wxVERTICAL);
|
|
||||||
wxBoxSizer* sBottom = new wxBoxSizer(wxHORIZONTAL);
|
|
||||||
|
|
||||||
m_Game_str = new wxButton(panel, wxID_ANY, wxT(" Game : "), wxDefaultPosition, wxSize(400, 25), wxBU_LEFT);
|
|
||||||
m_Game_str->Disable();
|
|
||||||
|
|
||||||
m_Logging = new wxTextCtrl(panel, ID_LOGGING_TXT, wxEmptyString,
|
|
||||||
wxDefaultPosition, wxSize(400, 250),
|
|
||||||
wxTE_RICH2 | wxTE_MULTILINE | wxTE_READONLY);
|
|
||||||
|
|
||||||
m_Chat = new wxTextCtrl(panel, ID_CHAT, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
|
|
||||||
m_Chat_ok = new wxButton(panel, ID_BUTTON_CHAT, wxT("Send"));;
|
|
||||||
|
|
||||||
m_Ready = new wxCheckBox(panel, ID_READY, wxT("Click here when ready"), wxDefaultPosition, wxDefaultSize, 0);
|
|
||||||
m_RecordGame = new wxCheckBox(panel, ID_RECORD, wxT("Record Game Input"), wxDefaultPosition, wxDefaultSize, 0);
|
|
||||||
// TODO: Fix the recording ?
|
|
||||||
m_RecordGame->Disable();
|
|
||||||
|
|
||||||
m_ConInfo_text = new wxStaticText(panel, ID_CONNINFO_TXT, wxT(" Fps : 0 | Ping : 00 ms"));
|
|
||||||
m_GetPing = new wxButton(panel, ID_BUTTON_GETPING, wxT("Ping"), wxDefaultPosition, wxDefaultSize);
|
|
||||||
m_Disconnect = new wxButton(panel, ID_BUTTON_QUIT, wxT("Disconnect"), wxDefaultPosition, wxDefaultSize);
|
|
||||||
|
|
||||||
wxBoxSizer* sChat = new wxBoxSizer(wxHORIZONTAL);
|
|
||||||
|
|
||||||
sTop->Add(m_Game_str, 0, wxALL|wxEXPAND, 1);
|
|
||||||
sTop->Add(m_Logging, 1, wxALL|wxEXPAND, 5);
|
|
||||||
sChat->Add(m_Chat, 1, wxALL|wxEXPAND, 2);
|
|
||||||
sChat->Add(m_Chat_ok, 0, wxALL, 2);
|
|
||||||
sTop->Add(sChat, 0, wxALL|wxEXPAND, 2);
|
|
||||||
|
|
||||||
wxBoxSizer* sBottom0 = new wxBoxSizer(wxHORIZONTAL);
|
|
||||||
wxBoxSizer* sBottom1 = new wxBoxSizer(wxHORIZONTAL);
|
|
||||||
wxBoxSizer* sBottomM = new wxBoxSizer(wxHORIZONTAL);
|
|
||||||
wxBoxSizer* sBottom2 = new wxBoxSizer(wxVERTICAL);
|
|
||||||
|
|
||||||
sBottom0->Add(m_Ready, 0, wxALL, 5);
|
|
||||||
sBottom0->Add(m_RecordGame, 0, wxALL, 5);
|
|
||||||
sBottomM->Add(m_ConInfo_text, 0, wxALL, 5);
|
|
||||||
sBottom1->Add(m_Disconnect, 0, wxALL|wxALIGN_LEFT, 5);
|
|
||||||
sBottom1->AddStretchSpacer(1);
|
|
||||||
sBottom1->Add(m_GetPing, 0, wxALL|wxALIGN_RIGHT, 5);
|
|
||||||
|
|
||||||
sBottom2->Add(sBottom0, 0, wxALL, 0);
|
|
||||||
sBottom2->Add(sBottomM, 0, wxALL | wxALIGN_LEFT, 0);
|
|
||||||
sBottom2->Add(sBottom1, 0, wxALL | wxEXPAND, 5);
|
|
||||||
|
|
||||||
sBottom->Add(sBottom2, 2, wxALL | wxEXPAND | wxALIGN_CENTER, 0);
|
|
||||||
|
|
||||||
if (m_isHosting)
|
|
||||||
{
|
|
||||||
m_wtfismyip = new wxButton(panel, ID_BUTTON_GETIP, wxT("What is my IP"));
|
|
||||||
m_ChangeGame = new wxButton(panel, ID_CHANGEGAME, wxT("Change Game"));
|
|
||||||
|
|
||||||
wxStaticBoxSizer* sBottom3 = new wxStaticBoxSizer(wxVERTICAL, panel, wxT("Host"));
|
|
||||||
|
|
||||||
sBottom3->Add(m_ChangeGame, 0, wxALL | wxEXPAND, 5);
|
|
||||||
sBottom3->Add(m_wtfismyip, 0, wxALL | wxEXPAND, 5);
|
|
||||||
sBottom->Add(sBottom3, 1, wxALL | wxEXPAND, 0);
|
|
||||||
|
|
||||||
UpdateNetWindow(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
sMain->Add(sTop, 1, wxALL | wxEXPAND, 5);
|
|
||||||
sMain->Add(sBottom, 0, wxALL | wxEXPAND | wxALIGN_CENTER, 2);
|
|
||||||
|
|
||||||
panel->SetSizerAndFit(sMain);
|
|
||||||
sMain->SetSizeHints((wxWindow*)this);
|
|
||||||
|
|
||||||
|
Center();
|
||||||
Show();
|
Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
// String of the type : FPSxPINGxFRAME_DELAY
|
void NetPlaySetupDiag::OnHost(wxCommandEvent& event)
|
||||||
void NetPlay::UpdateNetWindow(bool update_infos, wxString infos)
|
|
||||||
{
|
{
|
||||||
std::vector<std::string> str_arr;
|
// warning removal
|
||||||
|
event.GetId();
|
||||||
|
|
||||||
if (update_infos)
|
if (::netplay_ptr)
|
||||||
{
|
{
|
||||||
SplitString(std::string(infos.mb_str()), "x", str_arr);
|
PanicAlert("A NetPlay window is already open!!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_ConInfo_text->SetLabel
|
if (-1 == m_game_lbox->GetSelection())
|
||||||
(wxString::FromAscii(StringFromFormat(" Fps : %s | Ping : %s | Frame Delay : %s",
|
{
|
||||||
str_arr[0].c_str(), str_arr[1].c_str(),
|
PanicAlert("You must choose a game!!");
|
||||||
str_arr[2].c_str()).c_str()) );
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string game(m_game_lbox->GetStringSelection().mb_str());
|
||||||
|
|
||||||
|
NetPlayDiag* const npd = new NetPlayDiag(m_parent, m_game_list, game, true);
|
||||||
|
unsigned long port = 0;
|
||||||
|
m_host_port_text->GetValue().ToULong(&port);
|
||||||
|
::netplay_ptr = new NetPlayServer(u16(port)
|
||||||
|
, std::string(m_nickname_text->GetValue().mb_str()), npd, game);
|
||||||
|
if (::netplay_ptr->is_connected)
|
||||||
|
{
|
||||||
|
//NetPlayServerDiag* const npsd =
|
||||||
|
npd->Show();
|
||||||
|
Destroy();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_critical.Enter();
|
PanicAlert("Failed to Listen!!");
|
||||||
//m_Game_str->SetLabel(wxString::Format(wxT(" Game : %s"), m_selectedGame.c_str()));
|
npd->Destroy();
|
||||||
m_Game_str->SetLabel(wxString::FromAscii(std::string("Game " + m_selectedGame).c_str()));
|
// dialog will delete netplay
|
||||||
m_critical.Leave();
|
//delete ::netplay_ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetPlay::OnGUIEvent(wxCommandEvent& event)
|
void NetPlaySetupDiag::OnJoin(wxCommandEvent& event)
|
||||||
{
|
{
|
||||||
unsigned char value;;
|
// warning removal
|
||||||
switch (event.GetId())
|
event.GetId();
|
||||||
|
|
||||||
|
if (::netplay_ptr)
|
||||||
{
|
{
|
||||||
case ID_READY:
|
PanicAlert("A NetPlay window is already open!!");
|
||||||
{
|
return;
|
||||||
std::string buffer;
|
|
||||||
value = 0x40;
|
|
||||||
|
|
||||||
if (!m_ready)
|
|
||||||
buffer = ">> "+m_nick+" is now ready !\n";
|
|
||||||
else
|
|
||||||
buffer = ">> "+m_nick+" is now Unready !\n";
|
|
||||||
|
|
||||||
m_ready = !m_ready;
|
|
||||||
m_Disconnect->Enable(!(m_ready));
|
|
||||||
|
|
||||||
if (m_isHosting == 1)
|
|
||||||
{
|
|
||||||
m_ChangeGame->Enable(!(m_ready));
|
|
||||||
|
|
||||||
if (m_numClients > 0)
|
|
||||||
{
|
|
||||||
int buffer_size = (int)buffer.size();
|
|
||||||
for (int i=0; i < m_numClients ; i++)
|
|
||||||
{
|
|
||||||
m_sock_server->Write(i, (const char*)&value, 1);
|
|
||||||
|
|
||||||
m_sock_server->Write(i, (const char*)&buffer_size, 4);
|
|
||||||
m_sock_server->Write(i, buffer.c_str(), buffer_size + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Logging->AppendText(wxString::FromAscii(buffer.c_str()));
|
|
||||||
|
|
||||||
// Everyone is ready
|
|
||||||
if (m_ready && m_clients_ready)
|
|
||||||
LoadGame();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (m_numClients > 0)
|
|
||||||
m_sock_client->Write((const char*)&value, 1); // 0x40 -> Ready
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ID_BUTTON_GETIP:
|
|
||||||
{
|
|
||||||
if (m_numClients == 0) // Get IP Address from the Internet
|
|
||||||
{
|
|
||||||
// simple IP address caching
|
|
||||||
if (m_hostaddr.at(0) != 'a')
|
|
||||||
{
|
|
||||||
m_Logging->AppendText(wxString::FromAscii(m_hostaddr.c_str()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buffer[8];
|
|
||||||
sprintf(buffer, "%d", m_port);
|
|
||||||
|
|
||||||
m_hostaddr = "> Your IP is : " + sf::IPAddress::GetPublicAddress().ToString() +
|
|
||||||
':' + std::string(buffer) + '\n';
|
|
||||||
m_Logging->AppendText(wxString::FromAscii(m_hostaddr.c_str()));
|
|
||||||
}
|
|
||||||
else // Ask client to send server IP
|
|
||||||
{
|
|
||||||
value = 0x20;
|
|
||||||
m_sock_server->Write(0, (const char*)&value, 1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ID_BUTTON_GETPING:
|
|
||||||
{
|
|
||||||
if (m_numClients == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
long ping[3] = {0};
|
|
||||||
float fping;
|
|
||||||
|
|
||||||
if (m_isHosting == 1) {
|
|
||||||
m_sock_server->Write(0, 0, 0, ping);
|
|
||||||
fping = (ping[0]+ping[1]+ping[2])/(float)m_numClients;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_sock_client->Write(0, 0, ping);
|
|
||||||
fping = ping[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateNetWindow( true, wxString::Format(wxT("000x%fx%d"), fping, (int)ceil(fping/(1000.0/60.0))) );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ID_BUTTON_CHAT:
|
|
||||||
case ID_CHAT:
|
|
||||||
{
|
|
||||||
value = 0x30;
|
|
||||||
// TODO : there seems to be a random bug here that i can't reproduce... looked like a loop bug :/
|
|
||||||
wxString chat_str = wxString::Format(wxT("> %s : %s\n"), wxString(m_nick.c_str(), wxConvUTF8).c_str() , m_Chat->GetValue().c_str() );
|
|
||||||
int chat_size = (int)chat_str.size();
|
|
||||||
if(chat_size-m_nick.size()-6 > 0)
|
|
||||||
{
|
|
||||||
m_Chat->Clear();
|
|
||||||
|
|
||||||
// If there's no distant connection, we write but we don't send
|
|
||||||
if (m_numClients == 0) {
|
|
||||||
m_Logging->AppendText(chat_str);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Max size that we handle is 1024, there's no need for more
|
|
||||||
if ((chat_str.size()+1) * sizeof(char) > 1024) {
|
|
||||||
m_Logging->AppendText(wxT("ERROR : Packet too large !\n"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send to all
|
|
||||||
if (m_isHosting == 1)
|
|
||||||
{
|
|
||||||
for (int i=0; i < m_numClients ; i++) {
|
|
||||||
// Send Chat command
|
|
||||||
m_sock_server->Write(i, (const char*)&value, 1); // 0x30 -> Chat
|
|
||||||
|
|
||||||
// Send Chat string
|
|
||||||
m_sock_server->Write(i, (const char*)&chat_size, 4);
|
|
||||||
m_sock_server->Write(i, chat_str.mb_str(), chat_size + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_sock_client->Write((const char*)&value, 1);
|
|
||||||
m_sock_client->Write((const char*)&chat_size, 4);
|
|
||||||
m_sock_client->Write(chat_str.mb_str(), chat_size + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not wait for the server, just write as soon as sent
|
|
||||||
m_Logging->AppendText(chat_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ID_RECORD:
|
|
||||||
// TODO :
|
|
||||||
// Record raw pad data
|
|
||||||
break;
|
|
||||||
case ID_CHANGEGAME:
|
|
||||||
{
|
|
||||||
GameListPopup PopUp(this, m_GameList_str);
|
|
||||||
PopUp.ShowModal();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
NetPlayDiag* const npd = new NetPlayDiag(m_parent, m_game_list, "");
|
||||||
// GameList popup window
|
unsigned long port = 0;
|
||||||
|
m_connect_port_text->GetValue().ToULong(&port);
|
||||||
BEGIN_EVENT_TABLE(GameListPopup, wxDialog)
|
::netplay_ptr = new NetPlayClient(std::string(m_connect_ip_text->GetValue().mb_str())
|
||||||
EVT_BUTTON(wxID_OK, GameListPopup::OnButtons)
|
, (u16)port, std::string(m_nickname_text->GetValue().mb_str()), npd);
|
||||||
EVT_BUTTON(wxID_CANCEL, GameListPopup::OnButtons)
|
if (::netplay_ptr->is_connected)
|
||||||
END_EVENT_TABLE()
|
|
||||||
|
|
||||||
GameListPopup::GameListPopup(NetPlay *parent, wxArrayString GameNames) :
|
|
||||||
wxDialog(parent, wxID_ANY, _T("Choose a Game :"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
|
|
||||||
{
|
|
||||||
m_netParent = parent;
|
|
||||||
m_GameList_str = GameNames;
|
|
||||||
m_GameList = new wxListBox(this, ID_GAMELIST, wxDefaultPosition, wxSize(300, 250),
|
|
||||||
GameNames, wxLB_SINGLE | wxLB_SORT | wxLB_NEEDED_SB);
|
|
||||||
m_Cancel = new wxButton(this, wxID_CANCEL, wxT("Cancel"), wxDefaultPosition, wxDefaultSize);
|
|
||||||
m_Accept = new wxButton(this, wxID_OK, wxT("Apply"), wxDefaultPosition, wxDefaultSize);
|
|
||||||
|
|
||||||
wxBoxSizer* sButtons = new wxBoxSizer(wxHORIZONTAL);
|
|
||||||
wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
|
|
||||||
|
|
||||||
sButtons->Add(m_Cancel, 0, wxALL, 0);
|
|
||||||
sButtons->AddStretchSpacer(1);
|
|
||||||
sButtons->Add(m_Accept, 0, wxALL | wxALIGN_RIGHT, 0);
|
|
||||||
|
|
||||||
sMain->Add(m_GameList, 0, wxALL | wxEXPAND, 2);
|
|
||||||
sMain->Add(sButtons, 0, wxALL | wxEXPAND, 5);
|
|
||||||
|
|
||||||
SetSizerAndFit(sMain);
|
|
||||||
Center(); Layout(); Show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameListPopup::OnButtons(wxCommandEvent& event)
|
|
||||||
{
|
|
||||||
switch (event.GetId())
|
|
||||||
{
|
{
|
||||||
case wxID_OK:
|
//NetPlayServerDiag* const npsd =
|
||||||
if (m_GameList->GetSelection() != wxNOT_FOUND)
|
npd->Show();
|
||||||
m_netParent->ChangeSelectedGame(std::string(m_GameList_str[m_GameList->GetSelection()].mb_str()));
|
|
||||||
Destroy();
|
Destroy();
|
||||||
break;
|
}
|
||||||
case wxID_CANCEL:
|
else
|
||||||
Destroy();
|
{
|
||||||
break;
|
//PanicAlert("Failed to Connect!!");
|
||||||
|
npd->Destroy();
|
||||||
|
// dialog will delete netplay
|
||||||
|
//delete ::netplay_ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetPlaySetupDiag::OnQuit(wxCommandEvent& event)
|
||||||
|
{
|
||||||
|
// warning removal
|
||||||
|
event.GetId();
|
||||||
|
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
NetPlayDiag::NetPlayDiag(wxWindow* parent, const CGameListCtrl* const game_list
|
||||||
|
, const std::string& game, const bool is_hosting)
|
||||||
|
: wxFrame(parent, wxID_ANY, wxT(NETPLAY_TITLEBAR), wxDefaultPosition, wxDefaultSize)
|
||||||
|
, m_game_list(game_list)
|
||||||
|
, m_selected_game(game)
|
||||||
|
{
|
||||||
|
wxPanel* const panel = new wxPanel(this);
|
||||||
|
|
||||||
|
// top crap
|
||||||
|
m_game_btn = new wxButton(panel, wxID_ANY
|
||||||
|
, wxString(m_selected_game.c_str(), *wxConvCurrent).Prepend(wxT(" Game : ")), wxDefaultPosition, wxDefaultSize, wxBU_LEFT);
|
||||||
|
m_game_btn->Disable();
|
||||||
|
|
||||||
|
// middle crap
|
||||||
|
|
||||||
|
// chat
|
||||||
|
m_chat_text = new wxTextCtrl(panel, wxID_ANY, wxEmptyString
|
||||||
|
, wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxTE_MULTILINE);
|
||||||
|
|
||||||
|
m_chat_msg_text = new wxTextCtrl(panel, wxID_ANY, wxEmptyString
|
||||||
|
, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
|
||||||
|
_connect_macro_(m_chat_msg_text, NetPlayDiag::OnChat, wxEVT_COMMAND_TEXT_ENTER, this);
|
||||||
|
|
||||||
|
wxButton* const chat_msg_btn = new wxButton(panel, wxID_ANY, wxT("Send"));
|
||||||
|
_connect_macro_(chat_msg_btn, NetPlayDiag::OnChat, wxEVT_COMMAND_BUTTON_CLICKED, this);
|
||||||
|
|
||||||
|
wxBoxSizer* const chat_msg_szr = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
chat_msg_szr->Add(m_chat_msg_text, 1);
|
||||||
|
chat_msg_szr->Add(chat_msg_btn, 0);
|
||||||
|
|
||||||
|
wxStaticBoxSizer* const chat_szr = new wxStaticBoxSizer(wxVERTICAL, panel, wxT("Chat"));
|
||||||
|
chat_szr->Add(m_chat_text, 1, wxEXPAND);
|
||||||
|
chat_szr->Add(chat_msg_szr, 0, wxEXPAND | wxTOP, 5);
|
||||||
|
|
||||||
|
m_player_lbox = new wxListBox(panel, wxID_ANY, wxDefaultPosition, wxSize(192,-1));
|
||||||
|
|
||||||
|
wxStaticBoxSizer* const player_szr = new wxStaticBoxSizer(wxVERTICAL, panel, wxT("Players"));
|
||||||
|
player_szr->Add(m_player_lbox, 1, wxEXPAND);
|
||||||
|
// player list
|
||||||
|
if (is_hosting)
|
||||||
|
{
|
||||||
|
wxButton* const player_config_btn = new wxButton(panel, wxID_ANY, wxT("Configure Pads [not implemented]"));
|
||||||
|
player_config_btn->Disable();
|
||||||
|
player_szr->Add(player_config_btn, 0, wxEXPAND | wxTOP, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
wxBoxSizer* const mid_szr = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
mid_szr->Add(chat_szr, 1, wxEXPAND | wxRIGHT, 5);
|
||||||
|
mid_szr->Add(player_szr, 0, wxEXPAND);
|
||||||
|
|
||||||
|
// bottom crap
|
||||||
|
wxButton* const quit_btn = new wxButton(panel, wxID_ANY, wxT("Quit"));
|
||||||
|
_connect_macro_(quit_btn, NetPlayDiag::OnQuit, wxEVT_COMMAND_BUTTON_CLICKED, this);
|
||||||
|
|
||||||
|
wxBoxSizer* const bottom_szr = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
if (is_hosting)
|
||||||
|
{
|
||||||
|
wxButton* const start_btn = new wxButton(panel, wxID_ANY, wxT("Start"));
|
||||||
|
_connect_macro_(start_btn, NetPlayDiag::OnStart, wxEVT_COMMAND_BUTTON_CLICKED, this);
|
||||||
|
bottom_szr->Add(start_btn);
|
||||||
|
}
|
||||||
|
|
||||||
|
bottom_szr->AddStretchSpacer(1);
|
||||||
|
bottom_szr->Add(quit_btn);
|
||||||
|
|
||||||
|
// main sizer
|
||||||
|
wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL);
|
||||||
|
main_szr->Add(m_game_btn, 0, wxEXPAND | wxALL, 5);
|
||||||
|
main_szr->Add(mid_szr, 1, wxEXPAND | wxLEFT | wxRIGHT, 5);
|
||||||
|
main_szr->Add(bottom_szr, 0, wxEXPAND | wxALL, 5);
|
||||||
|
|
||||||
|
panel->SetSizerAndFit(main_szr);
|
||||||
|
|
||||||
|
main_szr->SetSizeHints(this);
|
||||||
|
SetSize(512, 512-128);
|
||||||
|
|
||||||
|
Center();
|
||||||
|
}
|
||||||
|
|
||||||
|
NetPlayDiag::~NetPlayDiag()
|
||||||
|
{
|
||||||
|
if (::netplay_ptr)
|
||||||
|
{
|
||||||
|
delete netplay_ptr;
|
||||||
|
::netplay_ptr = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetPlayDiag::OnChat(wxCommandEvent& event)
|
||||||
|
{
|
||||||
|
// warning removal
|
||||||
|
event.GetId();
|
||||||
|
|
||||||
|
wxString s = m_chat_msg_text->GetValue();
|
||||||
|
|
||||||
|
if (s.Length())
|
||||||
|
{
|
||||||
|
::netplay_ptr->SendChatMessage(std::string(s.mb_str()));
|
||||||
|
m_chat_text->AppendText(s.Prepend(wxT(" >> ")).Append(wxT('\n')));
|
||||||
|
m_chat_msg_text->Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetPlayDiag::OnStart(wxCommandEvent& event)
|
||||||
|
{
|
||||||
|
// warning removal
|
||||||
|
event.GetId();
|
||||||
|
|
||||||
|
// find path for selected game
|
||||||
|
std::string ntmp, ptmp, path;
|
||||||
|
std::istringstream nss(m_game_list->GetGameNames()), pss(m_game_list->GetGamePaths());
|
||||||
|
|
||||||
|
while(std::getline(nss,ntmp))
|
||||||
|
{
|
||||||
|
std::getline(pss,ptmp);
|
||||||
|
if (m_selected_game == ntmp)
|
||||||
|
{
|
||||||
|
path = ptmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.length())
|
||||||
|
::netplay_ptr->StartGame(path);
|
||||||
|
else
|
||||||
|
PanicAlert("Game not found!!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetPlayDiag::OnQuit(wxCommandEvent& event)
|
||||||
|
{
|
||||||
|
// warning removal
|
||||||
|
event.GetId();
|
||||||
|
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
// update gui
|
||||||
|
void NetPlayDiag::OnThread(wxCommandEvent& event)
|
||||||
|
{
|
||||||
|
// warning removal
|
||||||
|
event.GetId();
|
||||||
|
|
||||||
|
// player list
|
||||||
|
std::string tmps;
|
||||||
|
::netplay_ptr->GetPlayerList(tmps);
|
||||||
|
|
||||||
|
m_player_lbox->Clear();
|
||||||
|
std::istringstream ss(tmps);
|
||||||
|
while (std::getline(ss, tmps))
|
||||||
|
m_player_lbox->Append(wxString(tmps.c_str(), *wxConvCurrent));
|
||||||
|
|
||||||
|
// update selected game :/
|
||||||
|
if (45 == event.GetId())
|
||||||
|
{
|
||||||
|
m_selected_game.assign(event.GetString().mb_str());
|
||||||
|
m_game_btn->SetLabel(event.GetString().Prepend(wxT(" Game : ")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// chat messages
|
||||||
|
while (chat_msgs.Size())
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
chat_msgs.Pop(s);
|
||||||
|
//PanicAlert("message: %s", s.c_str());
|
||||||
|
m_chat_text->AppendText(wxString(s.c_str(), *wxConvCurrent).Append(wxT('\n')));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -18,202 +18,87 @@
|
||||||
#ifndef _NETWINDOW_H_
|
#ifndef _NETWINDOW_H_
|
||||||
#define _NETWINDOW_H_
|
#define _NETWINDOW_H_
|
||||||
|
|
||||||
|
#include "CommonTypes.h"
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <wx/wx.h>
|
#include <wx/wx.h>
|
||||||
#include <wx/sizer.h>
|
#include <wx/sizer.h>
|
||||||
#include <wx/dialog.h>
|
#include <wx/dialog.h>
|
||||||
#include <wx/notebook.h>
|
#include <wx/notebook.h>
|
||||||
#include <wx/gbsizer.h>
|
#include <wx/gbsizer.h>
|
||||||
#include <wx/listbox.h>
|
#include <wx/listbox.h>
|
||||||
|
//#include <wx/thread.h>
|
||||||
|
|
||||||
#include <wx/thread.h>
|
#include "GameListCtrl.h"
|
||||||
|
|
||||||
#include "Globals.h"
|
// just leaving these here so i can find something later if i need it
|
||||||
#include "BootManager.h"
|
//#include "Frame.h"
|
||||||
#include "Common.h"
|
//#include "Globals.h"
|
||||||
#include "NetStructs.h"
|
//#include "BootManager.h"
|
||||||
#include "Core.h"
|
//#include "Common.h"
|
||||||
#include "pluginspecs_pad.h"
|
//#include "NetStructs.h"
|
||||||
#include "HW/SI.h"
|
//#include "Core.h"
|
||||||
#include "HW/SI_Device.h"
|
//#include "pluginspecs_pad.h"
|
||||||
#include "HW/SI_DeviceGCController.h"
|
//#include "HW/SI.h"
|
||||||
#include "Timer.h"
|
//#include "HW/SI_Device.h"
|
||||||
|
//#include "HW/SI_DeviceGCController.h"
|
||||||
|
//#include "Timer.h"
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#include "LockingQueue.h"
|
||||||
#define NET_DEBUG
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Use TCP instead of UDP to send pad data @ 60fps. Suitable and better for LAN netplay,
|
class NetPlaySetupDiag : public wxFrame
|
||||||
// Unrealistic for Internet netplay, unless you have an uberfast connexion (<10ms ping)
|
|
||||||
// #define USE_TCP
|
|
||||||
|
|
||||||
class ServerSide;
|
|
||||||
class ClientSide;
|
|
||||||
|
|
||||||
class NetPlay : public wxFrame
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NetPlay(wxWindow* parent, std::string GamePath = "", std::string GameName = "");
|
NetPlaySetupDiag(wxWindow* parent, const CGameListCtrl* const game_list);
|
||||||
~NetPlay();
|
|
||||||
|
|
||||||
void UpdateNetWindow(bool update_infos, wxString=wxT("NULL"));
|
private:
|
||||||
void AppendText(const wxString text) { m_Logging->AppendText(text); }
|
void OnJoin(wxCommandEvent& event);
|
||||||
|
void OnHost(wxCommandEvent& event);
|
||||||
|
void OnQuit(wxCommandEvent& event);
|
||||||
|
|
||||||
// Send and receive pads values
|
wxTextCtrl *m_nickname_text,
|
||||||
bool GetNetPads(u8 pad_nb, SPADStatus, u32 *netvalues);
|
*m_host_port_text,
|
||||||
void ChangeSelectedGame(std::string game);
|
*m_connect_port_text,
|
||||||
void IsGameFound(unsigned char*, std::string);
|
*m_connect_ip_text;
|
||||||
std::string GetSelectedGame() { wxCriticalSectionLocker lock(m_critical); return m_selectedGame; }
|
|
||||||
|
|
||||||
void LoadGame();
|
wxListBox* m_game_lbox;
|
||||||
|
|
||||||
protected:
|
const CGameListCtrl* const m_game_list;
|
||||||
// Protects our vars from being fuxored by threads
|
|
||||||
wxCriticalSection m_critical;
|
|
||||||
|
|
||||||
// this draws the GUI, ya rly
|
|
||||||
void DrawGUI();
|
|
||||||
void DrawNetWindow();
|
|
||||||
|
|
||||||
// event handlers
|
|
||||||
void OnGUIEvent(wxCommandEvent& event);
|
|
||||||
void OnDisconnect(wxCommandEvent& event);
|
|
||||||
void OnNetEvent(wxCommandEvent& event);
|
|
||||||
void OnQuit(wxCloseEvent& event);
|
|
||||||
|
|
||||||
void OnJoin(wxCommandEvent& event);
|
|
||||||
void OnHost(wxCommandEvent& event);
|
|
||||||
|
|
||||||
// Net play vars (used ingame)
|
|
||||||
int m_frame;
|
|
||||||
int m_lastframe;
|
|
||||||
Common::Timer m_timer;
|
|
||||||
int m_loopframe;
|
|
||||||
int m_frameDelay;
|
|
||||||
bool m_data_received;// True if first frame data received
|
|
||||||
|
|
||||||
// Basic vars
|
|
||||||
std::string m_paths; // Game paths list
|
|
||||||
std::string m_games; // Game names list
|
|
||||||
|
|
||||||
std::string m_selectedGame;// Selected game's string
|
|
||||||
std::string m_hostaddr; // Used with OnGetIP to cache it
|
|
||||||
bool m_ready, m_clients_ready;
|
|
||||||
std::string m_nick;
|
|
||||||
|
|
||||||
int m_NetModel; // Using P2P model (0) or Server model (1)
|
|
||||||
int m_isHosting; // 0 = false ; 1 = true ; 2 = Not set
|
|
||||||
unsigned char m_numClients; // starting from 0, 4 players max thus 3 clients
|
|
||||||
std::string m_address; // The address entered into connection box
|
|
||||||
unsigned short m_port;
|
|
||||||
|
|
||||||
Netpads m_pads[4]; // this struct is used to save synced pad values
|
|
||||||
IniFile ConfigIni;
|
|
||||||
|
|
||||||
// Sockets objects
|
|
||||||
ServerSide *m_sock_server;
|
|
||||||
ClientSide *m_sock_client;
|
|
||||||
|
|
||||||
// -----------
|
|
||||||
// GUI objects
|
|
||||||
// -----------
|
|
||||||
wxNotebook *m_Notebook;
|
|
||||||
wxPanel *m_Tab_Connect;
|
|
||||||
wxPanel *m_Tab_Host;
|
|
||||||
wxStaticText *m_SetNick_text;
|
|
||||||
wxTextCtrl *m_SetNick;
|
|
||||||
wxChoice *m_NetMode;
|
|
||||||
|
|
||||||
// Host tab :
|
|
||||||
wxArrayString m_GameList_str;
|
|
||||||
wxStaticText *m_GameList_text;
|
|
||||||
wxListBox *m_GameList;
|
|
||||||
wxStaticText *m_SetPort_text;
|
|
||||||
wxTextCtrl *m_SetPort;
|
|
||||||
wxButton *m_HostGame;
|
|
||||||
wxButton *m_ExitWindowH;
|
|
||||||
|
|
||||||
// Connect tab :
|
|
||||||
wxTextCtrl *m_ConAddr;
|
|
||||||
wxStaticText *m_ConAddr_text;
|
|
||||||
wxButton *m_JoinGame;
|
|
||||||
wxButton *m_ExitWindowC;
|
|
||||||
wxCheckBox *m_UseRandomPort;
|
|
||||||
|
|
||||||
// Connection window
|
|
||||||
wxButton *m_Game_str;
|
|
||||||
wxTextCtrl *m_Logging;
|
|
||||||
wxTextCtrl *m_Chat;
|
|
||||||
wxButton *m_Chat_ok;
|
|
||||||
// Right part
|
|
||||||
wxButton *m_wtfismyip;
|
|
||||||
wxButton *m_ChangeGame;
|
|
||||||
// Left Part
|
|
||||||
wxButton *m_Disconnect;
|
|
||||||
wxStaticText *m_ConInfo_text;
|
|
||||||
wxButton *m_GetPing;
|
|
||||||
wxCheckBox *m_Ready;
|
|
||||||
wxCheckBox *m_RecordGame;
|
|
||||||
|
|
||||||
// wxWidgets event table
|
|
||||||
DECLARE_EVENT_TABLE()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class GameListPopup : public wxDialog
|
class NetPlayDiag : public wxFrame
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GameListPopup(NetPlay *net_ptr, wxArrayString GameNames);
|
NetPlayDiag(wxWindow* parent, const CGameListCtrl* const game_list
|
||||||
~GameListPopup() {}
|
, const std::string& game, const bool is_hosting = false);
|
||||||
protected:
|
~NetPlayDiag();
|
||||||
void OnButtons(wxCommandEvent& event);
|
|
||||||
wxArrayString m_GameList_str;
|
LockingQueue<std::string> chat_msgs;
|
||||||
NetPlay* m_netParent;
|
//std::string chat_msg;
|
||||||
wxListBox *m_GameList;
|
|
||||||
wxButton *m_Accept;
|
void OnStart(wxCommandEvent& event);
|
||||||
wxButton *m_Cancel;
|
|
||||||
DECLARE_EVENT_TABLE()
|
private:
|
||||||
|
DECLARE_EVENT_TABLE()
|
||||||
|
|
||||||
|
void OnChat(wxCommandEvent& event);
|
||||||
|
void OnQuit(wxCommandEvent& event);
|
||||||
|
void OnThread(wxCommandEvent& event);
|
||||||
|
|
||||||
|
wxListBox* m_player_lbox;
|
||||||
|
wxTextCtrl* m_chat_text;
|
||||||
|
wxTextCtrl* m_chat_msg_text;
|
||||||
|
|
||||||
|
std::string m_selected_game;
|
||||||
|
wxButton* m_game_btn;
|
||||||
|
|
||||||
|
const CGameListCtrl* const m_game_list;
|
||||||
|
//NetPlay* const m_netplay;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
DECLARE_EVENT_TYPE(wxEVT_THREAD, -1)
|
||||||
{
|
|
||||||
ID_NOTEBOOK,
|
|
||||||
ID_TAB_HOST,
|
|
||||||
ID_TAB_CONN,
|
|
||||||
ID_BUTTON_HOST,
|
|
||||||
ID_BUTTON_JOIN,
|
|
||||||
ID_BUTTON_EXIT,
|
|
||||||
ID_NETMODE,
|
|
||||||
ID_GAMELIST,
|
|
||||||
ID_LOGGING_TXT,
|
|
||||||
ID_CHAT,
|
|
||||||
ID_SETNICK,
|
|
||||||
ID_SETPORT,
|
|
||||||
ID_CONNADDR,
|
|
||||||
ID_CONNINFO_TXT,
|
|
||||||
ID_USE_RANDOMPORT,
|
|
||||||
ID_BUTTON_GETPING,
|
|
||||||
ID_BUTTON_GETIP,
|
|
||||||
ID_CHANGEGAME,
|
|
||||||
ID_BUTTON_QUIT,
|
|
||||||
ID_BUTTON_CHAT,
|
|
||||||
ID_READY,
|
|
||||||
ID_RECORD,
|
|
||||||
|
|
||||||
ID_SOCKET,
|
|
||||||
ID_SERVER,
|
|
||||||
|
|
||||||
HOST_FULL = 200, // ...
|
|
||||||
HOST_ERROR, // Sent on socket error
|
|
||||||
HOST_DISCONNECTED,
|
|
||||||
HOST_NEWPLAYER,
|
|
||||||
HOST_PLAYERLEFT,
|
|
||||||
CLIENTS_READY,
|
|
||||||
CLIENTS_NOTREADY,
|
|
||||||
GUI_UPDATE, // Refresh the shown selectedgame on GUI
|
|
||||||
ADD_TEXT, // Add text to m_Logging (string)
|
|
||||||
ADD_INFO, // Sent when updating net infos (string)
|
|
||||||
NET_EVENT
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // _NETWINDOW_H_
|
#endif // _NETWINDOW_H_
|
||||||
|
|
||||||
|
|
|
@ -37,9 +37,7 @@ if wxenv['HAVE_WX']:
|
||||||
'stdafx.cpp',
|
'stdafx.cpp',
|
||||||
'WxUtils.cpp',
|
'WxUtils.cpp',
|
||||||
'MemoryCards/WiiSaveCrypted.cpp',
|
'MemoryCards/WiiSaveCrypted.cpp',
|
||||||
'NetEvent.cpp',
|
'NetPlay.cpp',
|
||||||
'NetFunctions.cpp',
|
|
||||||
'NetSockets.cpp',
|
|
||||||
'NetWindow.cpp',
|
'NetWindow.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue