Merge branch 'netplay'

This commit is contained in:
Jasper St. Pierre 2013-08-05 06:44:17 -04:00
commit 0d2083c670
14 changed files with 827 additions and 853 deletions

View file

@ -10,7 +10,6 @@ set(SRCS Src/ActionReplay.cpp
Src/GeckoCodeConfig.cpp
Src/GeckoCode.cpp
Src/Movie.cpp
Src/NetPlay.cpp
Src/NetPlayClient.cpp
Src/NetPlayServer.cpp
Src/PatchEngine.cpp

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="DebugFast|Win32">
@ -334,7 +334,6 @@
<ClCompile Include="Src\IPC_HLE\WII_IPC_HLE_WiiMote.cpp" />
<ClCompile Include="Src\x64MemTools.cpp" />
<ClCompile Include="Src\Movie.cpp" />
<ClCompile Include="Src\NetPlay.cpp" />
<ClCompile Include="Src\NetPlayClient.cpp" />
<ClCompile Include="Src\NetPlayServer.cpp" />
<ClCompile Include="Src\PatchEngine.cpp" />
@ -540,7 +539,6 @@
<ClInclude Include="Src\IPC_HLE\WII_IPC_HLE_WiiMote.h" />
<ClInclude Include="Src\MemTools.h" />
<ClInclude Include="Src\Movie.h" />
<ClInclude Include="Src\NetPlay.h" />
<ClInclude Include="Src\PatchEngine.h" />
<ClInclude Include="Src\DSPEmulator.h" />
<ClInclude Include="Src\PowerPC\CPUCoreBase.h" />
@ -599,4 +597,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="Src\ConfigManager.cpp" />
@ -529,9 +529,6 @@
<ClCompile Include="Src\HW\Wiimote.cpp">
<Filter>HW %28Flipper/Hollywood%29\Wiimote</Filter>
</ClCompile>
<ClCompile Include="Src\NetPlay.cpp">
<Filter>NetPlay</Filter>
</ClCompile>
<ClCompile Include="Src\NetPlayServer.cpp">
<Filter>NetPlay</Filter>
</ClCompile>
@ -1014,9 +1011,6 @@
<ClInclude Include="Src\PowerPC\CPUCoreBase.h">
<Filter>PowerPC</Filter>
</ClInclude>
<ClInclude Include="Src\NetPlay.h">
<Filter>NetPlay</Filter>
</ClInclude>
<ClInclude Include="Src\BootManager.h" />
<ClInclude Include="Src\FifoPlayer\FifoDataFile.h">
<Filter>FifoPlayer</Filter>
@ -1177,9 +1171,6 @@
<Filter Include="HW %28Flipper/Hollywood%29\Wiimote\Real">
<UniqueIdentifier>{1c21a3e1-b791-4a23-b0d5-ed2b2c34007f}</UniqueIdentifier>
</Filter>
<Filter Include="NetPlay">
<UniqueIdentifier>{231ceb02-1122-402a-87a8-094a9ed768c2}</UniqueIdentifier>
</Filter>
<Filter Include="FifoPlayer">
<UniqueIdentifier>{ca7d56f7-4e84-4d15-9aea-7ae6fa7d6586}</UniqueIdentifier>
</Filter>
@ -1187,4 +1178,4 @@
<UniqueIdentifier>{3e9e6e83-c1bf-45f9-aeff-231f98f60d29}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>
</Project>

View file

@ -34,7 +34,7 @@
#include "Host.h"
#include "VideoBackendBase.h"
#include "Movie.h"
#include "NetPlay.h"
#include "NetPlayClient.h"
namespace BootManager
{
@ -138,7 +138,7 @@ bool BootCore(const std::string& _rFilename)
}
}
if (NetPlay::GetNetPlayPtr())
if (NetPlay::IsNetPlayRunning())
{
StartUp.bDSPHLE = g_NetPlaySettings.m_DSPHLE;
StartUp.bEnableMemcardSaving = g_NetPlaySettings.m_WriteToMemcard;

View file

@ -7,7 +7,7 @@
#include "../ConfigManager.h"
#include "../CoreTiming.h"
#include "../Movie.h"
#include "../NetPlay.h"
#include "../NetPlayClient.h"
#include "SystemTimers.h"
#include "ProcessorInterface.h"
@ -262,7 +262,7 @@ void Init()
if (Movie::IsRecordingInput() || Movie::IsPlayingInput())
AddDevice(Movie::IsUsingPad(i) ? (Movie::IsUsingBongo(i) ? SIDEVICE_GC_TARUKONGA : SIDEVICE_GC_CONTROLLER) : SIDEVICE_NONE, i);
else if (NetPlay::GetNetPlayPtr())
else if (NetPlay::IsNetPlayRunning())
AddDevice((SIDevices) g_NetPlaySettings.m_Controllers[i], i);
else
AddDevice(SConfig::GetInstance().m_SIDevice[i], i);
@ -644,7 +644,7 @@ void RunSIBuffer()
int GetTicksToNextSIPoll()
{
// Poll for input at regular intervals (once per frame) when playing or recording a movie
if (Movie::IsPlayingInput() || Movie::IsRecordingInput() || NetPlay::GetNetPlayPtr())
if (Movie::IsPlayingInput() || Movie::IsRecordingInput() || NetPlay::IsNetPlayRunning())
{
return SystemTimers::GetTicksPerSecond() / VideoInterface::TargetRefreshRate;
}

View file

@ -1,401 +0,0 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "NetPlay.h"
// for wiimote
#include "IPC_HLE/WII_IPC_HLE_Device_usb.h"
#include "IPC_HLE/WII_IPC_HLE_WiiMote.h"
// for gcpad
#include "HW/SI_DeviceGCController.h"
#include "HW/SI_DeviceGCSteeringWheel.h"
#include "HW/SI_DeviceDanceMat.h"
// for gctime
#include "HW/EXI_DeviceIPL.h"
// for wiimote/ OSD messages
#include "Core.h"
#include "ConfigManager.h"
std::mutex crit_netplay_ptr;
static NetPlay* netplay_ptr = NULL;
NetSettings g_NetPlaySettings;
#define RPT_SIZE_HACK (1 << 16)
// called from ---GUI--- thread
NetPlay::NetPlay(NetPlayUI* dialog)
: m_dialog(dialog), m_is_running(false), m_do_loop(true)
{
m_target_buffer_size = 20;
ClearBuffers();
}
void NetPlay_Enable(NetPlay* const np)
{
std::lock_guard<std::mutex> lk(crit_netplay_ptr);
netplay_ptr = np;
}
void NetPlay_Disable()
{
std::lock_guard<std::mutex> lk(crit_netplay_ptr);
netplay_ptr = NULL;
}
// called from ---GUI--- thread
NetPlay::~NetPlay()
{
std::lock_guard<std::mutex> lk(crit_netplay_ptr);
netplay_ptr = NULL;
// not perfect
if (m_is_running)
StopGame();
}
NetPlay::Player::Player()
{
memset(pad_map, -1, sizeof(pad_map));
}
// called from ---GUI--- thread
std::string NetPlay::Player::ToString() const
{
std::ostringstream ss;
ss << name << '[' << (char)(pid+'0') << "] : " << revision << " |";
for (unsigned int i=0; i<4; ++i)
ss << (pad_map[i]>=0 ? (char)(pad_map[i]+'1') : '-');
ss << '|';
return ss.str();
}
NetPad::NetPad()
{
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);
}
// called from ---NETPLAY--- thread
void NetPlay::ClearBuffers()
{
// clear pad buffers, Clear method isn't thread safe
for (unsigned int i=0; i<4; ++i)
{
while (m_pad_buffer[i].Size())
m_pad_buffer[i].Pop();
while (m_wiimote_buffer[i].Size())
m_wiimote_buffer[i].Pop();
m_wiimote_input[i].clear();
}
}
// called from ---CPU--- thread
bool NetPlay::GetNetPads(const u8 pad_nb, const SPADStatus* const pad_status, NetPad* const netvalues)
{
{
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
// in game mapping for this local pad
unsigned int in_game_num = m_local_player->pad_map[pad_nb];
// does this local pad map in game?
if (in_game_num < 4)
{
NetPad np(pad_status);
// adjust the buffer either up or down
// inserting multiple padstates or dropping states
while (m_pad_buffer[in_game_num].Size() <= m_target_buffer_size)
{
// add to buffer
m_pad_buffer[in_game_num].Push(np);
// send
SendPadState(pad_nb, np);
}
}
} // unlock players
//Common::Timer bufftimer;
//bufftimer.Start();
// get padstate from buffer and send to game
while (!m_pad_buffer[pad_nb].Pop(*netvalues))
{
// wait for receiving thread to push some data
Common::SleepCurrentThread(1);
if (false == m_is_running)
return false;
// TODO: check the time of bufftimer here,
// if it gets pretty high, ask the user if they want to disconnect
}
//u64 hangtime = bufftimer.GetTimeElapsed();
//if (hangtime > 10)
//{
// std::ostringstream ss;
// ss << "Pad " << (int)pad_nb << ": Had to wait " << hangtime << "ms for pad data. (increase pad Buffer maybe)";
// Core::DisplayMessage(ss.str(), 1000);
//}
return true;
}
// called from ---CPU--- thread
void NetPlay::WiimoteInput(int _number, u16 _channelID, const void* _pData, u32 _Size)
{
//// in game mapping for this local wiimote
unsigned int in_game_num = m_local_player->pad_map[_number]; // just using gc pad_map for now
// does this local pad map in game?
if (in_game_num < 4)
{
m_wiimote_input[_number].resize(m_wiimote_input[_number].size() + 1);
m_wiimote_input[_number].back().assign((char*)_pData, (char*)_pData + _Size);
m_wiimote_input[_number].back().channel = _channelID;
}
}
// called from ---CPU--- thread
void NetPlay::WiimoteUpdate(int _number)
{
{
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
// in game mapping for this local wiimote
unsigned int in_game_num = m_local_player->pad_map[_number]; // just using gc pad_map for now
// does this local pad map in game?
if (in_game_num < 4)
{
m_wiimote_buffer[in_game_num].Push(m_wiimote_input[_number]);
// TODO: send it
m_wiimote_input[_number].clear();
}
} // unlock players
if (0 == m_wiimote_buffer[_number].Size())
{
//PanicAlert("PANIC");
return;
}
NetWiimote nw;
m_wiimote_buffer[_number].Pop(nw);
NetWiimote::const_iterator
i = nw.begin(), e = nw.end();
for ( ; i!=e; ++i)
Core::Callback_WiimoteInterruptChannel(_number, i->channel, &(*i)[0], (u32)i->size() + RPT_SIZE_HACK);
}
// called from ---GUI--- thread
bool NetPlay::StartGame(const std::string &path)
{
if (m_is_running)
{
PanicAlertT("Game is already running!");
return false;
}
m_dialog->AppendChat(" -- STARTING GAME -- ");
m_is_running = true;
NetPlay_Enable(this);
ClearBuffers();
// boot game
m_dialog->BootGame(path);
// temporary
NetWiimote nw;
for (unsigned int i = 0; i<4; ++i)
for (unsigned int f = 0; f<2; ++f)
m_wiimote_buffer[i].Push(nw);
return true;
}
// called from ---GUI--- thread and ---NETPLAY--- thread (client side)
bool NetPlay::StopGame()
{
std::lock_guard<std::recursive_mutex> lkg(m_crit.game);
if (false == m_is_running)
{
PanicAlertT("Game isn't running!");
return false;
}
m_dialog->AppendChat(" -- STOPPING GAME -- ");
m_is_running = false;
NetPlay_Disable();
// stop game
m_dialog->StopGame();
return true;
}
void NetPlay::SetMemcardWriteEnabled(bool enabled)
{
std::lock_guard<std::recursive_mutex> lkg(m_crit.game);
g_NetPlaySettings.m_WriteToMemcard = enabled;
}
// called from ---CPU--- thread
u8 NetPlay::GetPadNum(u8 numPAD)
{
// TODO: i don't like that this loop is running everytime there is rumble
unsigned int i = 0;
for (; i<4; ++i)
if (numPAD == m_local_player->pad_map[i])
break;
return i;
}
void NetPlay::GetNetSettings()
{
SConfig &instance = SConfig::GetInstance();
g_NetPlaySettings.m_DSPHLE = instance.m_LocalCoreStartupParameter.bDSPHLE;
g_NetPlaySettings.m_DSPEnableJIT = instance.m_EnableJIT;
for (unsigned int i = 0; i < 4; ++i)
g_NetPlaySettings.m_Controllers[i] = SConfig::GetInstance().m_SIDevice[i];
}
// stuff hacked into dolphin
// called from ---CPU--- thread
// Actual Core function which is called on every frame
bool CSIDevice_GCController::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus)
{
std::lock_guard<std::mutex> lk(crit_netplay_ptr);
if (netplay_ptr)
return netplay_ptr->GetNetPads(numPAD, &PadStatus, (NetPad*)PADStatus);
else
return false;
}
bool CSIDevice_GCSteeringWheel::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus)
{
return CSIDevice_GCController::NetPlay_GetInput(numPAD, PadStatus, PADStatus);
}
bool CSIDevice_DanceMat::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus)
{
return CSIDevice_GCController::NetPlay_GetInput(numPAD, PadStatus, PADStatus);
}
// called from ---CPU--- thread
// so all players' games get the same time
u32 CEXIIPL::NetPlay_GetGCTime()
{
std::lock_guard<std::mutex> lk(crit_netplay_ptr);
if (netplay_ptr)
return 1272737767; // watev
else
return 0;
}
// called from ---CPU--- thread
// return the local pad num that should rumble given a ingame pad num
u8 CSIDevice_GCController::NetPlay_GetPadNum(u8 numPAD)
{
std::lock_guard<std::mutex> lk(crit_netplay_ptr);
if (netplay_ptr)
return netplay_ptr->GetPadNum(numPAD);
else
return numPAD;
}
u8 CSIDevice_GCSteeringWheel::NetPlay_GetPadNum(u8 numPAD)
{
return CSIDevice_GCController::NetPlay_GetPadNum(numPAD);
}
u8 CSIDevice_DanceMat::NetPlay_GetPadNum(u8 numPAD)
{
return CSIDevice_GCController::NetPlay_GetPadNum(numPAD);
}
// called from ---CPU--- thread
// wiimote update / used for frame counting
//void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int _number)
void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int)
{
//CritLocker crit(crit_netplay_ptr);
//if (netplay_ptr)
// netplay_ptr->WiimoteUpdate(_number);
}
// called from ---CPU--- thread
//
int CWII_IPC_HLE_WiiMote::NetPlay_GetWiimoteNum(int _number)
{
//CritLocker crit(crit_netplay_ptr);
//if (netplay_ptr)
// return netplay_ptr->GetPadNum(_number); // just using gcpad mapping for now
//else
return _number;
}
// called from ---CPU--- thread
// intercept wiimote input callback
//bool CWII_IPC_HLE_WiiMote::NetPlay_WiimoteInput(int _number, u16 _channelID, const void* _pData, u32& _Size)
bool CWII_IPC_HLE_WiiMote::NetPlay_WiimoteInput(int, u16, const void*, u32&)
{
std::lock_guard<std::mutex> lk(crit_netplay_ptr);
if (netplay_ptr)
//{
// if (_Size >= RPT_SIZE_HACK)
// {
// _Size -= RPT_SIZE_HACK;
// return false;
// }
// else
// {
// netplay_ptr->WiimoteInput(_number, _channelID, _pData, _Size);
// // don't use this packet
return true;
// }
//}
else
return false;
}
NetPlay* NetPlay::GetNetPlayPtr()
{
return netplay_ptr;
}

View file

@ -1,275 +0,0 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _NETPLAY_H
#define _NETPLAY_H
#include "Common.h"
#include "CommonTypes.h"
#include "Thread.h"
#include "Timer.h"
#include <SFML/Network.hpp>
#include "GCPadStatus.h"
#include <functional>
#include <map>
#include <queue>
#include <sstream>
#include "FifoQueue.h"
class NetPad
{
public:
NetPad();
NetPad(const SPADStatus* const);
u32 nHi;
u32 nLo;
};
struct NetSettings
{
bool m_DSPHLE;
bool m_DSPEnableJIT;
bool m_WriteToMemcard;
u8 m_Controllers[4];
};
extern NetSettings g_NetPlaySettings;
struct Rpt : public std::vector<u8>
{
u16 channel;
};
typedef std::vector<Rpt> NetWiimote;
#define NETPLAY_VERSION "Dolphin NetPlay 2013-07-22"
// messages
enum
{
NP_MSG_PLAYER_JOIN = 0x10,
NP_MSG_PLAYER_LEAVE = 0x11,
NP_MSG_CHAT_MESSAGE = 0x30,
NP_MSG_PAD_DATA = 0x60,
NP_MSG_PAD_MAPPING = 0x61,
NP_MSG_PAD_BUFFER = 0x62,
NP_MSG_WIIMOTE_DATA = 0x70,
NP_MSG_WIIMOTE_MAPPING = 0x71, // just using pad mapping for now
NP_MSG_START_GAME = 0xA0,
NP_MSG_CHANGE_GAME = 0xA1,
NP_MSG_STOP_GAME = 0xA2,
NP_MSG_DISABLE_GAME = 0xA3,
NP_MSG_READY = 0xD0,
NP_MSG_NOT_READY = 0xD1,
NP_MSG_PING = 0xE0,
NP_MSG_PONG = 0xE1,
};
typedef u8 MessageId;
typedef u8 PlayerId;
typedef s8 PadMapping;
typedef u32 FrameNum;
enum
{
CON_ERR_SERVER_FULL = 1,
CON_ERR_GAME_RUNNING,
CON_ERR_VERSION_MISMATCH
};
class NetPlayUI
{
public:
virtual ~NetPlayUI() {};
virtual void BootGame(const std::string& filename) = 0;
virtual void StopGame() = 0;
virtual void Update() = 0;
virtual void AppendChat(const std::string& msg) = 0;
virtual void OnMsgChangeGame(const std::string& filename) = 0;
virtual void OnMsgStartGame() = 0;
virtual void OnMsgStopGame() = 0;
};
class NetPlay
{
public:
NetPlay(NetPlayUI* _dialog);
virtual ~NetPlay();
//virtual void ThreadFunc() = 0;
bool is_connected;
// Send and receive pads values
void WiimoteInput(int _number, u16 _channelID, const void* _pData, u32 _Size);
void WiimoteUpdate(int _number);
bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues);
virtual bool ChangeGame(const std::string& game) = 0;
virtual void GetPlayerList(std::string& list, std::vector<int>& pid_list) = 0;
virtual void SendChatMessage(const std::string& msg) = 0;
virtual bool StartGame(const std::string &path);
virtual bool StopGame();
virtual void SetMemcardWriteEnabled(bool enabled);
//void PushPadStates(unsigned int count);
u8 GetPadNum(u8 numPAD);
static NetPlay* GetNetPlayPtr();
protected:
//void GetBufferedPad(const u8 pad_nb, NetPad* const netvalues);
void ClearBuffers();
void GetNetSettings();
virtual void SendPadState(const PadMapping local_nb, const NetPad& np) = 0;
struct
{
std::recursive_mutex game;
// lock order
std::recursive_mutex players, send;
} m_crit;
class Player
{
public:
Player();
std::string ToString() const;
PlayerId pid;
std::string name;
PadMapping pad_map[4];
std::string revision;
};
Common::FifoQueue<NetPad> m_pad_buffer[4];
Common::FifoQueue<NetWiimote> m_wiimote_buffer[4];
NetWiimote m_wiimote_input[4];
NetPlayUI* m_dialog;
sf::SocketTCP m_socket;
std::thread m_thread;
sf::Selector<sf::SocketTCP> m_selector;
std::string m_selected_game;
volatile bool m_is_running;
volatile bool m_do_loop;
unsigned int m_target_buffer_size;
Player* m_local_player;
u32 m_current_game;
};
void NetPlay_Enable(NetPlay* const np);
void NetPlay_Disable();
class NetPlayServer : public NetPlay
{
public:
void ThreadFunc();
NetPlayServer(const u16 port, const std::string& name, NetPlayUI* dialog);
~NetPlayServer();
void GetPlayerList(std::string& list, std::vector<int>& pid_list);
// Send and receive pads values
//bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues);
bool ChangeGame(const std::string& game);
void SendChatMessage(const std::string& msg);
bool StartGame(const std::string &path);
bool StopGame();
bool GetPadMapping(const int pid, int map[]);
bool SetPadMapping(const int pid, const int map[]);
u64 CalculateMinimumBufferTime();
void AdjustPadBufferSize(unsigned int size);
#ifdef USE_UPNP
void TryPortmapping(u16 port);
#endif
private:
class Client : public Player
{
public:
Client() : ping(0), current_game(0) {}
sf::SocketTCP socket;
u64 ping;
u32 current_game;
};
void SendPadState(const PadMapping local_nb, const NetPad& np);
void SendToClients(sf::Packet& packet, const PlayerId skip_pid = 0);
unsigned int OnConnect(sf::SocketTCP& socket);
unsigned int OnDisconnect(sf::SocketTCP& socket);
unsigned int OnData(sf::Packet& packet, sf::SocketTCP& socket);
void UpdatePadMapping();
std::map<sf::SocketTCP, Client> m_players;
Common::Timer m_ping_timer;
u32 m_ping_key;
bool m_update_pings;
#ifdef USE_UPNP
static void mapPortThread(const u16 port);
static void unmapPortThread();
static bool initUPnP();
static bool UPnPMapPort(const std::string& addr, const u16 port);
static bool UPnPUnmapPort(const u16 port);
static struct UPNPUrls m_upnp_urls;
static struct IGDdatas m_upnp_data;
static u16 m_upnp_mapped;
static bool m_upnp_inited;
static bool m_upnp_error;
static std::thread m_upnp_thread;
#endif
};
class NetPlayClient : public NetPlay
{
public:
void ThreadFunc();
NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name);
~NetPlayClient();
void GetPlayerList(std::string& list, std::vector<int>& pid_list);
// Send and receive pads values
//bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues);
bool StartGame(const std::string &path);
bool ChangeGame(const std::string& game);
void SendChatMessage(const std::string& msg);
private:
void SendPadState(const PadMapping local_nb, const NetPad& np);
unsigned int OnData(sf::Packet& packet);
PlayerId m_pid;
std::map<PlayerId, Player> m_players;
};
#endif

View file

@ -2,21 +2,81 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "NetPlay.h"
#include "NetPlayClient.h"
// for wiimote
#include "IPC_HLE/WII_IPC_HLE_Device_usb.h"
#include "IPC_HLE/WII_IPC_HLE_WiiMote.h"
// for gcpad
#include "HW/SI_DeviceGCController.h"
#include "HW/SI_DeviceGCSteeringWheel.h"
#include "HW/SI_DeviceDanceMat.h"
// for gctime
#include "HW/EXI_DeviceIPL.h"
// for wiimote/ OSD messages
#include "Core.h"
#include "ConfigManager.h"
std::mutex crit_netplay_client;
static NetPlayClient * netplay_client = NULL;
NetSettings g_NetPlaySettings;
#define RPT_SIZE_HACK (1 << 16)
NetPlayClient::Player::Player()
{
memset(pad_map, -1, sizeof(pad_map));
}
// called from ---GUI--- thread
std::string NetPlayClient::Player::ToString() const
{
std::ostringstream ss;
ss << name << '[' << (char)(pid+'0') << "] : " << revision << " |";
for (unsigned int i=0; i<4; ++i)
ss << (pad_map[i]>=0 ? (char)(pad_map[i]+'1') : '-');
ss << " | " << ping << "ms";
return ss.str();
}
NetPad::NetPad()
{
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);
}
// called from ---GUI--- thread
NetPlayClient::~NetPlayClient()
{
// not perfect
if (m_is_running)
StopGame();
if (is_connected)
{
m_do_loop = false;
m_thread.join();
}
}
}
// called from ---GUI--- thread
NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name) : NetPlay(dialog)
NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name) : m_dialog(dialog), m_is_running(false), m_do_loop(true)
{
m_target_buffer_size = 20;
ClearBuffers();
is_connected = false;
// why is false successful? documentation says true is
@ -233,6 +293,21 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
}
break;
case NP_MSG_PLAYER_PING_DATA:
{
PlayerId pid;
packet >> pid;
{
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
Player& player = m_players[pid];
packet >> player.ping;
}
m_dialog->Update();
}
break;
default :
PanicAlertT("Unknown message received with id : %d", mid);
break;
@ -328,12 +403,31 @@ bool NetPlayClient::StartGame(const std::string &path)
spac << m_current_game;
spac << (char *)&g_NetPlaySettings;
if (false == NetPlay::StartGame(path))
return false;
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
m_socket.Send(spac);
if (m_is_running)
{
PanicAlertT("Game is already running!");
return false;
}
m_dialog->AppendChat(" -- STARTING GAME -- ");
m_is_running = true;
NetPlay_Enable(this);
ClearBuffers();
// boot game
m_dialog->BootGame(path);
// temporary
NetWiimote nw;
for (unsigned int i = 0; i<4; ++i)
for (unsigned int f = 0; f<2; ++f)
m_wiimote_buffer[i].Push(nw);
return true;
}
@ -342,3 +436,283 @@ bool NetPlayClient::ChangeGame(const std::string&)
{
return true;
}
// called from ---NETPLAY--- thread
void NetPlayClient::ClearBuffers()
{
// clear pad buffers, Clear method isn't thread safe
for (unsigned int i=0; i<4; ++i)
{
while (m_pad_buffer[i].Size())
m_pad_buffer[i].Pop();
while (m_wiimote_buffer[i].Size())
m_wiimote_buffer[i].Pop();
m_wiimote_input[i].clear();
}
}
// called from ---CPU--- thread
bool NetPlayClient::GetNetPads(const u8 pad_nb, const SPADStatus* const pad_status, NetPad* const netvalues)
{
{
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
// in game mapping for this local pad
unsigned int in_game_num = m_local_player->pad_map[pad_nb];
// does this local pad map in game?
if (in_game_num < 4)
{
NetPad np(pad_status);
// adjust the buffer either up or down
// inserting multiple padstates or dropping states
while (m_pad_buffer[in_game_num].Size() <= m_target_buffer_size)
{
// add to buffer
m_pad_buffer[in_game_num].Push(np);
// send
SendPadState(pad_nb, np);
}
}
} // unlock players
//Common::Timer bufftimer;
//bufftimer.Start();
// get padstate from buffer and send to game
while (!m_pad_buffer[pad_nb].Pop(*netvalues))
{
// wait for receiving thread to push some data
Common::SleepCurrentThread(1);
if (false == m_is_running)
return false;
// TODO: check the time of bufftimer here,
// if it gets pretty high, ask the user if they want to disconnect
}
//u64 hangtime = bufftimer.GetTimeElapsed();
//if (hangtime > 10)
//{
// std::ostringstream ss;
// ss << "Pad " << (int)pad_nb << ": Had to wait " << hangtime << "ms for pad data. (increase pad Buffer maybe)";
// Core::DisplayMessage(ss.str(), 1000);
//}
return true;
}
// called from ---CPU--- thread
void NetPlayClient::WiimoteInput(int _number, u16 _channelID, const void* _pData, u32 _Size)
{
//// in game mapping for this local wiimote
unsigned int in_game_num = m_local_player->pad_map[_number]; // just using gc pad_map for now
// does this local pad map in game?
if (in_game_num < 4)
{
m_wiimote_input[_number].resize(m_wiimote_input[_number].size() + 1);
m_wiimote_input[_number].back().assign((char*)_pData, (char*)_pData + _Size);
m_wiimote_input[_number].back().channel = _channelID;
}
}
// called from ---CPU--- thread
void NetPlayClient::WiimoteUpdate(int _number)
{
{
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
// in game mapping for this local wiimote
unsigned int in_game_num = m_local_player->pad_map[_number]; // just using gc pad_map for now
// does this local pad map in game?
if (in_game_num < 4)
{
m_wiimote_buffer[in_game_num].Push(m_wiimote_input[_number]);
// TODO: send it
m_wiimote_input[_number].clear();
}
} // unlock players
if (0 == m_wiimote_buffer[_number].Size())
{
//PanicAlert("PANIC");
return;
}
NetWiimote nw;
m_wiimote_buffer[_number].Pop(nw);
NetWiimote::const_iterator
i = nw.begin(), e = nw.end();
for ( ; i!=e; ++i)
Core::Callback_WiimoteInterruptChannel(_number, i->channel, &(*i)[0], (u32)i->size() + RPT_SIZE_HACK);
}
// called from ---GUI--- thread and ---NETPLAY--- thread (client side)
bool NetPlayClient::StopGame()
{
std::lock_guard<std::recursive_mutex> lkg(m_crit.game);
if (false == m_is_running)
{
PanicAlertT("Game isn't running!");
return false;
}
m_dialog->AppendChat(" -- STOPPING GAME -- ");
m_is_running = false;
NetPlay_Disable();
// stop game
m_dialog->StopGame();
return true;
}
// called from ---CPU--- thread
u8 NetPlayClient::GetPadNum(u8 numPAD)
{
// TODO: i don't like that this loop is running everytime there is rumble
unsigned int i = 0;
for (; i<4; ++i)
if (numPAD == m_local_player->pad_map[i])
break;
return i;
}
// stuff hacked into dolphin
// called from ---CPU--- thread
// Actual Core function which is called on every frame
bool CSIDevice_GCController::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus)
{
std::lock_guard<std::mutex> lk(crit_netplay_client);
if (netplay_client)
return netplay_client->GetNetPads(numPAD, &PadStatus, (NetPad*)PADStatus);
else
return false;
}
bool CSIDevice_GCSteeringWheel::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus)
{
return CSIDevice_GCController::NetPlay_GetInput(numPAD, PadStatus, PADStatus);
}
bool CSIDevice_DanceMat::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus)
{
return CSIDevice_GCController::NetPlay_GetInput(numPAD, PadStatus, PADStatus);
}
// called from ---CPU--- thread
// so all players' games get the same time
u32 CEXIIPL::NetPlay_GetGCTime()
{
std::lock_guard<std::mutex> lk(crit_netplay_client);
if (netplay_client)
return 1272737767; // watev
else
return 0;
}
// called from ---CPU--- thread
// return the local pad num that should rumble given a ingame pad num
u8 CSIDevice_GCController::NetPlay_GetPadNum(u8 numPAD)
{
std::lock_guard<std::mutex> lk(crit_netplay_client);
if (netplay_client)
return netplay_client->GetPadNum(numPAD);
else
return numPAD;
}
u8 CSIDevice_GCSteeringWheel::NetPlay_GetPadNum(u8 numPAD)
{
return CSIDevice_GCController::NetPlay_GetPadNum(numPAD);
}
u8 CSIDevice_DanceMat::NetPlay_GetPadNum(u8 numPAD)
{
return CSIDevice_GCController::NetPlay_GetPadNum(numPAD);
}
// called from ---CPU--- thread
// wiimote update / used for frame counting
//void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int _number)
void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int)
{
//CritLocker crit(crit_netplay_client);
//if (netplay_client)
// netplay_client->WiimoteUpdate(_number);
}
// called from ---CPU--- thread
//
int CWII_IPC_HLE_WiiMote::NetPlay_GetWiimoteNum(int _number)
{
//CritLocker crit(crit_netplay_client);
//if (netplay_client)
// return netplay_client->GetPadNum(_number); // just using gcpad mapping for now
//else
return _number;
}
// called from ---CPU--- thread
// intercept wiimote input callback
//bool CWII_IPC_HLE_WiiMote::NetPlay_WiimoteInput(int _number, u16 _channelID, const void* _pData, u32& _Size)
bool CWII_IPC_HLE_WiiMote::NetPlay_WiimoteInput(int, u16, const void*, u32&)
{
std::lock_guard<std::mutex> lk(crit_netplay_client);
if (netplay_client)
//{
// if (_Size >= RPT_SIZE_HACK)
// {
// _Size -= RPT_SIZE_HACK;
// return false;
// }
// else
// {
// netplay_client->WiimoteInput(_number, _channelID, _pData, _Size);
// // don't use this packet
return true;
// }
//}
else
return false;
}
bool NetPlay::IsNetPlayRunning()
{
return netplay_client != NULL;
}
void NetPlay_Enable(NetPlayClient* const np)
{
std::lock_guard<std::mutex> lk(crit_netplay_client);
netplay_client = np;
}
void NetPlay_Disable()
{
std::lock_guard<std::mutex> lk(crit_netplay_client);
netplay_client = NULL;
}

View file

@ -0,0 +1,135 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _NETPLAY_H
#define _NETPLAY_H
#include "Common.h"
#include "CommonTypes.h"
#include "Thread.h"
#include "Timer.h"
#include <SFML/Network.hpp>
#include "NetPlayProto.h"
#include "GCPadStatus.h"
#include <functional>
#include <map>
#include <queue>
#include <sstream>
#include "FifoQueue.h"
class NetPad
{
public:
NetPad();
NetPad(const SPADStatus* const);
u32 nHi;
u32 nLo;
};
class NetPlayUI
{
public:
virtual ~NetPlayUI() {};
virtual void BootGame(const std::string& filename) = 0;
virtual void StopGame() = 0;
virtual void Update() = 0;
virtual void AppendChat(const std::string& msg) = 0;
virtual void OnMsgChangeGame(const std::string& filename) = 0;
virtual void OnMsgStartGame() = 0;
virtual void OnMsgStopGame() = 0;
};
extern NetSettings g_NetPlaySettings;
class NetPlayClient
{
public:
void ThreadFunc();
NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name);
~NetPlayClient();
void GetPlayerList(std::string& list, std::vector<int>& pid_list);
bool is_connected;
bool StartGame(const std::string &path);
bool StopGame();
bool ChangeGame(const std::string& game);
void SendChatMessage(const std::string& msg);
// Send and receive pads values
void WiimoteInput(int _number, u16 _channelID, const void* _pData, u32 _Size);
void WiimoteUpdate(int _number);
bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues);
u8 GetPadNum(u8 numPAD);
protected:
void ClearBuffers();
struct
{
std::recursive_mutex game;
// lock order
std::recursive_mutex players, send;
} m_crit;
class Player
{
public:
Player();
std::string ToString() const;
PlayerId pid;
std::string name;
PadMapping pad_map[4];
std::string revision;
u32 ping;
};
Common::FifoQueue<NetPad> m_pad_buffer[4];
Common::FifoQueue<NetWiimote> m_wiimote_buffer[4];
NetWiimote m_wiimote_input[4];
NetPlayUI* m_dialog;
sf::SocketTCP m_socket;
std::thread m_thread;
sf::Selector<sf::SocketTCP> m_selector;
std::string m_selected_game;
volatile bool m_is_running;
volatile bool m_do_loop;
unsigned int m_target_buffer_size;
Player* m_local_player;
u32 m_current_game;
private:
void SendPadState(const PadMapping local_nb, const NetPad& np);
unsigned int OnData(sf::Packet& packet);
PlayerId m_pid;
std::map<PlayerId, Player> m_players;
};
namespace NetPlay {
bool IsNetPlayRunning();
};
void NetPlay_Enable(NetPlayClient* const np);
void NetPlay_Disable();
#endif

View file

@ -0,0 +1,68 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _NETPLAY_PROTO_H
#define _NETPLAY_PROTO_H
#include "Common.h"
#include "CommonTypes.h"
struct NetSettings
{
bool m_DSPHLE;
bool m_DSPEnableJIT;
bool m_WriteToMemcard;
u8 m_Controllers[4];
};
struct Rpt : public std::vector<u8>
{
u16 channel;
};
typedef std::vector<Rpt> NetWiimote;
#define NETPLAY_VERSION "Dolphin NetPlay 2013-08-05"
// messages
enum
{
NP_MSG_PLAYER_JOIN = 0x10,
NP_MSG_PLAYER_LEAVE = 0x11,
NP_MSG_CHAT_MESSAGE = 0x30,
NP_MSG_PAD_DATA = 0x60,
NP_MSG_PAD_MAPPING = 0x61,
NP_MSG_PAD_BUFFER = 0x62,
NP_MSG_WIIMOTE_DATA = 0x70,
NP_MSG_WIIMOTE_MAPPING = 0x71, // just using pad mapping for now
NP_MSG_START_GAME = 0xA0,
NP_MSG_CHANGE_GAME = 0xA1,
NP_MSG_STOP_GAME = 0xA2,
NP_MSG_DISABLE_GAME = 0xA3,
NP_MSG_READY = 0xD0,
NP_MSG_NOT_READY = 0xD1,
NP_MSG_PING = 0xE0,
NP_MSG_PONG = 0xE1,
NP_MSG_PLAYER_PING_DATA = 0xE2,
};
typedef u8 MessageId;
typedef u8 PlayerId;
typedef s8 PadMapping;
typedef u32 FrameNum;
enum
{
CON_ERR_SERVER_FULL = 1,
CON_ERR_GAME_RUNNING,
CON_ERR_VERSION_MISMATCH
};
#endif

View file

@ -2,15 +2,31 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "NetPlay.h"
#include "NetPlayServer.h"
NetPlayServer::Client::Client()
{
memset(pad_map, -1, sizeof(pad_map));
}
// called from ---GUI--- thread
std::string NetPlayServer::Client::ToString() const
{
std::ostringstream ss;
ss << name << '[' << (char)(pid+'0') << "] : " << revision << " |";
for (unsigned int i=0; i<4; ++i)
ss << (pad_map[i]>=0 ? (char)(pad_map[i]+'1') : '-');
ss << '|';
return ss.str();
}
NetPlayServer::~NetPlayServer()
{
if (is_connected)
{
m_do_loop = false;
m_thread.join();
m_socket.Close();
}
#ifdef USE_UPNP
@ -22,35 +38,15 @@ NetPlayServer::~NetPlayServer()
}
// called from ---GUI--- thread
NetPlayServer::NetPlayServer(const u16 port, const std::string& name, NetPlayUI* dialog) : NetPlay(dialog)
NetPlayServer::NetPlayServer(const u16 port) : is_connected(false), m_is_running(false)
{
m_update_pings = true;
if (m_socket.Listen(port))
{
Client 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;
m_local_player = &m_players[m_socket];
//PanicAlertT("Listening");
m_dialog->Update();
is_connected = true;
m_do_loop = true;
m_selector.Add(m_socket);
m_thread = std::thread(std::mem_fun(&NetPlayServer::ThreadFunc), this);
}
else
is_connected = false;
}
// called from ---NETPLAY--- thread
@ -258,8 +254,6 @@ unsigned int NetPlayServer::OnConnect(sf::SocketTCP& socket)
// add client to selector/ used for receiving
m_selector.Add(socket);
m_dialog->Update();
return 0;
}
@ -271,7 +265,6 @@ unsigned int NetPlayServer::OnDisconnect(sf::SocketTCP& socket)
PanicAlertT("Client disconnect while game is running!! NetPlay is disabled. You must manually stop the game.");
std::lock_guard<std::recursive_mutex> lkg(m_crit.game);
m_is_running = false;
NetPlay_Disable();
sf::Packet spac;
spac << (MessageId)NP_MSG_DISABLE_GAME;
@ -293,8 +286,6 @@ unsigned int NetPlayServer::OnDisconnect(sf::SocketTCP& socket)
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
SendToClients(spac);
m_dialog->Update();
return 0;
}
@ -357,8 +348,6 @@ bool NetPlayServer::SetPadMapping(const int pid, const int map[])
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
UpdatePadMapping(); // sync pad mappings with everyone
m_dialog->Update();
return true;
}
@ -380,29 +369,6 @@ void NetPlayServer::UpdatePadMapping()
}
// called from ---GUI--- thread and ---NETPLAY--- thread
u64 NetPlayServer::CalculateMinimumBufferTime()
{
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
std::map<sf::SocketTCP, Client>::const_iterator
i = m_players.begin(),
e = m_players.end();
std::priority_queue<unsigned int> pings;
for ( ;i!=e; ++i)
pings.push(i->second.ping/2);
unsigned int required_ms = pings.top();
// if there is more than 1 client, buffersize must be >= (2 highest ping times combined)
if (pings.size() > 1)
{
pings.pop();
required_ms += pings.top();
}
return required_ms;
}
// called from ---GUI--- thread and ---NETPLAY--- thread
void NetPlayServer::AdjustPadBufferSize(unsigned int size)
{
@ -447,12 +413,6 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, sf::SocketTCP& socket)
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
SendToClients(spac, player.pid);
}
// add to gui
std::ostringstream ss;
ss << player.name << '[' << (char)(player.pid+'0') << "]: " << msg;
m_dialog->AppendChat(ss.str());
}
break;
@ -463,8 +423,8 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, sf::SocketTCP& socket)
break;
PadMapping map = 0;
NetPad np;
packet >> map >> np.nHi >> np.nLo;
int hi, lo;
packet >> map >> hi >> lo;
// check if client's pad indeed maps in game
if (map >= 0 && map < 4)
@ -477,14 +437,12 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, sf::SocketTCP& socket)
if (map < 0)
return 1;
// add to pad buffer
m_pad_buffer[(unsigned)map].Push(np);
// relay to clients
sf::Packet spac;
spac << (MessageId)NP_MSG_PAD_DATA;
spac << map; // in game mapping
spac << np.nHi << np.nLo;
spac << hi << lo;
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
SendToClients(spac, player.pid);
@ -498,11 +456,15 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, sf::SocketTCP& socket)
packet >> ping_key;
if (m_ping_key == ping_key)
{
//PanicAlertT("Good pong");
player.ping = ping;
}
m_dialog->Update();
sf::Packet spac;
spac << (MessageId)NP_MSG_PLAYER_PING_DATA;
spac << player.pid;
spac << player.ping;
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
SendToClients(spac);
}
break;
@ -573,29 +535,16 @@ bool NetPlayServer::ChangeGame(const std::string &game)
return true;
}
// called from ---CPU--- thread
void NetPlayServer::SendPadState(const PadMapping local_nb, const NetPad& np)
// called from ---GUI--- thread
void NetPlayServer::SetNetSettings(const NetSettings &settings)
{
// send to server
sf::Packet spac;
spac << (MessageId)NP_MSG_PAD_DATA;
spac << m_local_player->pad_map[local_nb]; // in-game pad num
spac << np.nHi << np.nLo;
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
SendToClients(spac);
m_settings = settings;
}
// called from ---GUI--- thread
bool NetPlayServer::StartGame(const std::string &path)
{
std::lock_guard<std::recursive_mutex> lkg(m_crit.game);
GetNetSettings();
if (false == NetPlay::StartGame(path))
return false;
// TODO: i dont like this here
m_current_game = Common::Timer::GetTimeMs();
// no change, just update with clients
@ -604,17 +553,19 @@ bool NetPlayServer::StartGame(const std::string &path)
// tell clients to start game
sf::Packet spac;
spac << (MessageId)NP_MSG_START_GAME;
spac << NetPlay::m_current_game;
spac << g_NetPlaySettings.m_DSPEnableJIT;
spac << g_NetPlaySettings.m_DSPHLE;
spac << g_NetPlaySettings.m_WriteToMemcard;
spac << m_current_game;
spac << m_settings.m_DSPEnableJIT;
spac << m_settings.m_DSPHLE;
spac << m_settings.m_WriteToMemcard;
for (unsigned int i = 0; i < 4; ++i)
spac << g_NetPlaySettings.m_Controllers[i];
spac << m_settings.m_Controllers[i];
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
SendToClients(spac);
m_is_running = true;
return true;
}
@ -622,9 +573,6 @@ bool NetPlayServer::StartGame(const std::string &path)
// called from ---GUI--- thread
bool NetPlayServer::StopGame()
{
if (false == NetPlay::StopGame())
return false;
// tell clients to stop game
sf::Packet spac;
spac << (MessageId)NP_MSG_STOP_GAME;

View file

@ -0,0 +1,116 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _NETPLAY_SERVER_H
#define _NETPLAY_SERVER_H
#include "Common.h"
#include "CommonTypes.h"
#include "Thread.h"
#include "Timer.h"
#include <SFML/Network.hpp>
#include "NetPlayProto.h"
#include <functional>
#include <map>
#include <queue>
#include <sstream>
class NetPlayServer
{
public:
void ThreadFunc();
NetPlayServer(const u16 port);
~NetPlayServer();
void GetPlayerList(std::string& list, std::vector<int>& pid_list);
bool ChangeGame(const std::string& game);
void SendChatMessage(const std::string& msg);
void SetNetSettings(const NetSettings &settings);
bool StartGame(const std::string &path);
bool StopGame();
bool GetPadMapping(const int pid, int map[]);
bool SetPadMapping(const int pid, const int map[]);
void AdjustPadBufferSize(unsigned int size);
bool is_connected;
#ifdef USE_UPNP
void TryPortmapping(u16 port);
#endif
private:
class Client
{
public:
Client();
std::string ToString() const;
PlayerId pid;
std::string name;
PadMapping pad_map[4];
std::string revision;
sf::SocketTCP socket;
u32 ping;
u32 current_game;
};
void SendToClients(sf::Packet& packet, const PlayerId skip_pid = 0);
unsigned int OnConnect(sf::SocketTCP& socket);
unsigned int OnDisconnect(sf::SocketTCP& socket);
unsigned int OnData(sf::Packet& packet, sf::SocketTCP& socket);
void UpdatePadMapping();
NetSettings m_settings;
bool m_is_running;
bool m_do_loop;
Common::Timer m_ping_timer;
u32 m_ping_key;
bool m_update_pings;
u32 m_current_game;
unsigned int m_target_buffer_size;
std::map<sf::SocketTCP, Client> m_players;
struct
{
std::recursive_mutex game;
// lock order
std::recursive_mutex players, send;
} m_crit;
std::string m_selected_game;
sf::SocketTCP m_socket;
std::thread m_thread;
sf::Selector<sf::SocketTCP> m_selector;
#ifdef USE_UPNP
static void mapPortThread(const u16 port);
static void unmapPortThread();
static bool initUPnP();
static bool UPnPMapPort(const std::string& addr, const u16 port);
static bool UPnPUnmapPort(const u16 port);
static struct UPNPUrls m_upnp_urls;
static struct IGDdatas m_upnp_data;
static u16 m_upnp_mapped;
static bool m_upnp_inited;
static bool m_upnp_error;
static std::thread m_upnp_thread;
#endif
};
#endif

View file

@ -6,10 +6,12 @@
#include <IniFile.h>
#include "WxUtils.h"
#include "NetPlay.h"
#include "NetPlayClient.h"
#include "NetPlayServer.h"
#include "NetWindow.h"
#include "Frame.h"
#include "Core.h"
#include "ConfigManager.h"
#include <sstream>
#include <string>
@ -20,7 +22,8 @@ BEGIN_EVENT_TABLE(NetPlayDiag, wxFrame)
EVT_COMMAND(wxID_ANY, wxEVT_THREAD, NetPlayDiag::OnThread)
END_EVENT_TABLE()
static NetPlay* netplay_ptr = NULL;
static NetPlayServer* netplay_server = NULL;
static NetPlayClient* netplay_client = NULL;
extern CFrame* main_frame;
NetPlayDiag *NetPlayDiag::npd = NULL;
@ -200,6 +203,28 @@ NetPlaySetupDiag::~NetPlaySetupDiag()
main_frame->g_NetPlaySetupDiag = NULL;
}
void NetPlaySetupDiag::MakeNetPlayDiag(int port, const std::string &game, bool is_hosting)
{
NetPlayDiag *&npd = NetPlayDiag::GetInstance();
std::string ip;
npd = new NetPlayDiag(m_parent, m_game_list, game, is_hosting);
if (is_hosting)
ip = "127.0.0.1";
else
ip = WxStrToStr(m_connect_ip_text->GetValue());
netplay_client = new NetPlayClient(ip, (u16)port, npd, WxStrToStr(m_nickname_text->GetValue()));
if (netplay_client->is_connected)
{
npd->Show();
Destroy();
}
else
{
npd->Destroy();
}
}
void NetPlaySetupDiag::OnHost(wxCommandEvent&)
{
NetPlayDiag *&npd = NetPlayDiag::GetInstance();
@ -217,25 +242,19 @@ void NetPlaySetupDiag::OnHost(wxCommandEvent&)
std::string game(WxStrToStr(m_game_lbox->GetStringSelection()));
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), WxStrToStr(m_nickname_text->GetValue()), npd);
netplay_ptr->ChangeGame(game);
if (netplay_ptr->is_connected)
netplay_server = new NetPlayServer(u16(port));
netplay_server->ChangeGame(game);
if (netplay_server->is_connected)
{
#ifdef USE_UPNP
if(m_upnp_chk->GetValue())
((NetPlayServer*)netplay_ptr)->TryPortmapping(port);
netplay_server->TryPortmapping(port);
#endif
npd->Show();
Destroy();
}
else
{
PanicAlertT("Failed to Listen!!");
npd->Destroy();
}
MakeNetPlayDiag(port, game, true);
}
void NetPlaySetupDiag::OnJoin(wxCommandEvent&)
@ -247,20 +266,9 @@ void NetPlaySetupDiag::OnJoin(wxCommandEvent&)
return;
}
npd = new NetPlayDiag(m_parent, m_game_list, "");
unsigned long port = 0;
m_connect_port_text->GetValue().ToULong(&port);
netplay_ptr = new NetPlayClient(WxStrToStr(m_connect_ip_text->GetValue())
, (u16)port, npd, WxStrToStr(m_nickname_text->GetValue()));
if (netplay_ptr->is_connected)
{
npd->Show();
Destroy();
}
else
{
npd->Destroy();
}
MakeNetPlayDiag(port, "", false);
}
void NetPlaySetupDiag::OnQuit(wxCommandEvent&)
@ -344,7 +352,6 @@ NetPlayDiag::NetPlayDiag(wxWindow* const parent, const CGameListCtrl* const game
}
m_memcard_write = new wxCheckBox(panel, wxID_ANY, _("Write memcards (GC)"));
m_memcard_write->Bind(wxEVT_COMMAND_CHECKBOX_CLICKED, &NetPlayDiag::OnMemcardWriteCheck, this);
bottom_szr->Add(m_memcard_write, 0, wxCENTER);
bottom_szr->AddStretchSpacer(1);
@ -366,10 +373,15 @@ NetPlayDiag::NetPlayDiag(wxWindow* const parent, const CGameListCtrl* const game
NetPlayDiag::~NetPlayDiag()
{
if (netplay_ptr)
if (netplay_client)
{
delete netplay_ptr;
netplay_ptr = NULL;
delete netplay_client;
netplay_client = NULL;
}
if (netplay_server)
{
delete netplay_server;
netplay_server = NULL;
}
npd = NULL;
}
@ -380,37 +392,50 @@ void NetPlayDiag::OnChat(wxCommandEvent&)
if (s.Length())
{
netplay_ptr->SendChatMessage(WxStrToStr(s));
netplay_client->SendChatMessage(WxStrToStr(s));
m_chat_text->AppendText(s.Prepend(wxT(" >> ")).Append(wxT('\n')));
m_chat_msg_text->Clear();
}
}
void NetPlayDiag::OnStart(wxCommandEvent&)
void NetPlayDiag::GetNetSettings(NetSettings &settings)
{
SConfig &instance = SConfig::GetInstance();
settings.m_DSPHLE = instance.m_LocalCoreStartupParameter.bDSPHLE;
settings.m_DSPEnableJIT = instance.m_EnableJIT;
settings.m_WriteToMemcard = m_memcard_write->GetValue();
for (unsigned int i = 0; i < 4; ++i)
settings.m_Controllers[i] = SConfig::GetInstance().m_SIDevice[i];
}
const std::string& NetPlayDiag::FindGame()
{
// find path for selected game, sloppy..
for (u32 i = 0 ; auto game = m_game_list->GetISO(i); ++i)
{
if (m_selected_game == BuildGameName(*game))
{
netplay_ptr->StartGame(game->GetFileName());
return;
}
}
return game->GetFileName();
PanicAlertT("Game not found!");
return "";
}
void NetPlayDiag::OnStart(wxCommandEvent&)
{
NetSettings settings;
GetNetSettings(settings);
netplay_server->SetNetSettings(settings);
netplay_server->StartGame(FindGame());
}
void NetPlayDiag::OnStop(wxCommandEvent&)
{
netplay_ptr->StopGame();
netplay_server->StopGame();
}
void NetPlayDiag::BootGame(const std::string& filename)
{
main_frame->BootGame(filename);
Core::g_CoreStartupParameter.bEnableMemcardSaving = m_memcard_write->GetValue();
}
void NetPlayDiag::StopGame()
@ -452,19 +477,14 @@ void NetPlayDiag::OnMsgStopGame()
GetEventHandler()->AddPendingEvent(evt);
}
void NetPlayDiag::OnMemcardWriteCheck(wxCommandEvent &event)
{
netplay_ptr->SetMemcardWriteEnabled(m_memcard_write->GetValue());
}
void NetPlayDiag::OnAdjustBuffer(wxCommandEvent& event)
{
const int val = ((wxSpinCtrl*)event.GetEventObject())->GetValue();
((NetPlayServer*)netplay_ptr)->AdjustPadBufferSize(val);
netplay_server->AdjustPadBufferSize(val);
std::ostringstream ss;
ss << "< Pad Buffer: " << val << " >";
netplay_ptr->SendChatMessage(ss.str());
netplay_client->SendChatMessage(ss.str());
m_chat_text->AppendText(StrToWxStr(ss.str()).Append(wxT('\n')));
}
@ -479,7 +499,7 @@ void NetPlayDiag::OnThread(wxCommandEvent& event)
// player list
m_playerids.clear();
std::string tmps;
netplay_ptr->GetPlayerList(tmps, m_playerids);
netplay_client->GetPlayerList(tmps, m_playerids);
const int selection = m_player_lbox->GetSelection();
@ -502,15 +522,13 @@ void NetPlayDiag::OnThread(wxCommandEvent& event)
case NP_GUI_EVT_START_GAME :
// client start game :/
{
wxCommandEvent evt;
OnStart(evt);
netplay_client->StartGame(FindGame());
}
break;
case NP_GUI_EVT_STOP_GAME :
// client stop game
{
wxCommandEvent evt;
OnStop(evt);
netplay_client->StopGame();
}
break;
}
@ -534,7 +552,7 @@ void NetPlayDiag::OnChangeGame(wxCommandEvent&)
if (game_name.length())
{
m_selected_game = WxStrToStr(game_name);
netplay_ptr->ChangeGame(m_selected_game);
netplay_server->ChangeGame(m_selected_game);
m_game_btn->SetLabel(game_name.Prepend(_(" Game : ")));
}
}
@ -549,13 +567,13 @@ void NetPlayDiag::OnConfigPads(wxCommandEvent&)
return;
pid = m_playerids.at(pid);
if (false == ((NetPlayServer*)netplay_ptr)->GetPadMapping(pid, mapping))
if (false == netplay_server->GetPadMapping(pid, mapping))
return;
PadMapDiag pmd(this, mapping);
pmd.ShowModal();
if (false == ((NetPlayServer*)netplay_ptr)->SetPadMapping(pid, mapping))
if (false == netplay_server->SetPadMapping(pid, mapping))
PanicAlertT("Could not set pads. The player left or the game is currently running!\n"
"(setting pads while the game is running is not yet supported)");
}

View file

@ -23,7 +23,7 @@
#include "FifoQueue.h"
#include "NetPlay.h"
#include "NetPlayClient.h"
enum
{
@ -42,6 +42,8 @@ private:
void OnHost(wxCommandEvent& event);
void OnQuit(wxCommandEvent& event);
void MakeNetPlayDiag(int port, const std::string &game, bool is_hosting);
wxTextCtrl *m_nickname_text,
*m_host_port_text,
*m_connect_port_text,
@ -85,11 +87,12 @@ private:
void OnChat(wxCommandEvent& event);
void OnQuit(wxCommandEvent& event);
void OnMemcardWriteCheck(wxCommandEvent& event);
void OnThread(wxCommandEvent& event);
void OnChangeGame(wxCommandEvent& event);
void OnAdjustBuffer(wxCommandEvent& event);
void OnConfigPads(wxCommandEvent& event);
void GetNetSettings(NetSettings &settings);
const std::string& FindGame();
wxListBox* m_player_lbox;
wxTextCtrl* m_chat_text;