diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 5474083132..bf8d86494e 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -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 diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index 53000b2cc9..964a6927e0 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -1,4 +1,4 @@ - + @@ -334,7 +334,6 @@ - @@ -540,7 +539,6 @@ - @@ -599,4 +597,4 @@ - \ No newline at end of file + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 75c592a685..f82b0d8832 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -529,9 +529,6 @@ HW %28Flipper/Hollywood%29\Wiimote - - NetPlay - NetPlay @@ -1014,9 +1011,6 @@ PowerPC - - NetPlay - FifoPlayer @@ -1177,9 +1171,6 @@ {1c21a3e1-b791-4a23-b0d5-ed2b2c34007f} - - {231ceb02-1122-402a-87a8-094a9ed768c2} - {ca7d56f7-4e84-4d15-9aea-7ae6fa7d6586} @@ -1187,4 +1178,4 @@ {3e9e6e83-c1bf-45f9-aeff-231f98f60d29} - \ No newline at end of file + diff --git a/Source/Core/Core/Src/BootManager.cpp b/Source/Core/Core/Src/BootManager.cpp index c9a8568205..c4bf6d485a 100644 --- a/Source/Core/Core/Src/BootManager.cpp +++ b/Source/Core/Core/Src/BootManager.cpp @@ -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; diff --git a/Source/Core/Core/Src/HW/SI.cpp b/Source/Core/Core/Src/HW/SI.cpp index 85c84f92dd..ebd839a8bf 100644 --- a/Source/Core/Core/Src/HW/SI.cpp +++ b/Source/Core/Core/Src/HW/SI.cpp @@ -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; } diff --git a/Source/Core/Core/Src/NetPlay.cpp b/Source/Core/Core/Src/NetPlay.cpp deleted file mode 100644 index 45d1689abe..0000000000 --- a/Source/Core/Core/Src/NetPlay.cpp +++ /dev/null @@ -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 lk(crit_netplay_ptr); - netplay_ptr = np; -} - -void NetPlay_Disable() -{ - std::lock_guard lk(crit_netplay_ptr); - netplay_ptr = NULL; -} - -// called from ---GUI--- thread -NetPlay::~NetPlay() -{ - std::lock_guard 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 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 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 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 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 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 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 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 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; -} diff --git a/Source/Core/Core/Src/NetPlay.h b/Source/Core/Core/Src/NetPlay.h deleted file mode 100644 index 222fb680cf..0000000000 --- a/Source/Core/Core/Src/NetPlay.h +++ /dev/null @@ -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 - -#include "GCPadStatus.h" - -#include -#include -#include -#include - -#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 -{ - u16 channel; -}; - -typedef std::vector 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& 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 m_pad_buffer[4]; - Common::FifoQueue m_wiimote_buffer[4]; - - NetWiimote m_wiimote_input[4]; - - NetPlayUI* m_dialog; - sf::SocketTCP m_socket; - std::thread m_thread; - sf::Selector 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& 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 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& 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 m_players; -}; - -#endif diff --git a/Source/Core/Core/Src/NetPlayClient.cpp b/Source/Core/Core/Src/NetPlayClient.cpp index 7163be001a..e10cc25186 100644 --- a/Source/Core/Core/Src/NetPlayClient.cpp +++ b/Source/Core/Core/Src/NetPlayClient.cpp @@ -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 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 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 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 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 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 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 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 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 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 lk(crit_netplay_client); + netplay_client = np; +} + +void NetPlay_Disable() +{ + std::lock_guard lk(crit_netplay_client); + netplay_client = NULL; +} diff --git a/Source/Core/Core/Src/NetPlayClient.h b/Source/Core/Core/Src/NetPlayClient.h new file mode 100644 index 0000000000..d44a4c84b8 --- /dev/null +++ b/Source/Core/Core/Src/NetPlayClient.h @@ -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 + +#include "NetPlayProto.h" +#include "GCPadStatus.h" + +#include +#include +#include +#include + +#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& 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 m_pad_buffer[4]; + Common::FifoQueue m_wiimote_buffer[4]; + + NetWiimote m_wiimote_input[4]; + + NetPlayUI* m_dialog; + sf::SocketTCP m_socket; + std::thread m_thread; + sf::Selector 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 m_players; +}; + +namespace NetPlay { + bool IsNetPlayRunning(); +}; + +void NetPlay_Enable(NetPlayClient* const np); +void NetPlay_Disable(); + +#endif diff --git a/Source/Core/Core/Src/NetPlayProto.h b/Source/Core/Core/Src/NetPlayProto.h new file mode 100644 index 0000000000..84e2b420fd --- /dev/null +++ b/Source/Core/Core/Src/NetPlayProto.h @@ -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 +{ + u16 channel; +}; + +typedef std::vector 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 diff --git a/Source/Core/Core/Src/NetPlayServer.cpp b/Source/Core/Core/Src/NetPlayServer.cpp index db3a41a398..505e6a8f76 100644 --- a/Source/Core/Core/Src/NetPlayServer.cpp +++ b/Source/Core/Core/Src/NetPlayServer.cpp @@ -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 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 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 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 lkp(m_crit.players); - - std::map::const_iterator - i = m_players.begin(), - e = m_players.end(); - std::priority_queue 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 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 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 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 lks(m_crit.send); - SendToClients(spac); + m_settings = settings; } // called from ---GUI--- thread bool NetPlayServer::StartGame(const std::string &path) { std::lock_guard 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 lkp(m_crit.players); std::lock_guard 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; diff --git a/Source/Core/Core/Src/NetPlayServer.h b/Source/Core/Core/Src/NetPlayServer.h new file mode 100644 index 0000000000..95f98e2a73 --- /dev/null +++ b/Source/Core/Core/Src/NetPlayServer.h @@ -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 + +#include "NetPlayProto.h" + +#include +#include +#include +#include + +class NetPlayServer +{ +public: + void ThreadFunc(); + + NetPlayServer(const u16 port); + ~NetPlayServer(); + + void GetPlayerList(std::string& list, std::vector& 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 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 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 diff --git a/Source/Core/DolphinWX/Src/NetWindow.cpp b/Source/Core/DolphinWX/Src/NetWindow.cpp index 22cd588236..1c8f0549b9 100644 --- a/Source/Core/DolphinWX/Src/NetWindow.cpp +++ b/Source/Core/DolphinWX/Src/NetWindow.cpp @@ -6,10 +6,12 @@ #include #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 #include @@ -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)"); } diff --git a/Source/Core/DolphinWX/Src/NetWindow.h b/Source/Core/DolphinWX/Src/NetWindow.h index 76fbc03431..543c164994 100644 --- a/Source/Core/DolphinWX/Src/NetWindow.h +++ b/Source/Core/DolphinWX/Src/NetWindow.h @@ -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;