diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt
index e80b2cb786..6c3b6ae79b 100644
--- a/Source/Core/Common/CMakeLists.txt
+++ b/Source/Core/Common/CMakeLists.txt
@@ -1,6 +1,7 @@
set(SRCS BreakPoints.cpp
CDUtils.cpp
ColorUtil.cpp
+ ENetUtil.cpp
FileSearch.cpp
FileUtil.cpp
GekkoDisassembler.cpp
diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj
index ced0c431df..7b2c278cd1 100644
--- a/Source/Core/Common/Common.vcxproj
+++ b/Source/Core/Common/Common.vcxproj
@@ -51,6 +51,7 @@
+
@@ -94,6 +95,7 @@
+
@@ -146,4 +148,4 @@
-
\ No newline at end of file
+
diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters
index 8545274fc4..ffaf7d6be8 100644
--- a/Source/Core/Common/Common.vcxproj.filters
+++ b/Source/Core/Common/Common.vcxproj.filters
@@ -25,6 +25,7 @@
+
@@ -78,6 +79,7 @@
+
diff --git a/Source/Core/Common/ENetUtil.cpp b/Source/Core/Common/ENetUtil.cpp
new file mode 100644
index 0000000000..ae5b19b2c3
--- /dev/null
+++ b/Source/Core/Common/ENetUtil.cpp
@@ -0,0 +1,40 @@
+// Copyright 2015 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "ENetUtil.h"
+
+namespace ENetUtil
+{
+
+void WakeupThread(ENetHost* host)
+{
+ // Send ourselves a spurious message. This is hackier than it should be.
+ // comex reported this as https://github.com/lsalzman/enet/issues/23, so
+ // hopefully there will be a better way to do it in the future.
+ ENetAddress address;
+ if (host->address.port != 0)
+ address.port = host->address.port;
+ else
+ enet_socket_get_address(host->socket, &address);
+ address.host = 0x0100007f; // localhost
+ u8 byte = 0;
+ ENetBuffer buf;
+ buf.data = &byte;
+ buf.dataLength = 1;
+ enet_socket_send(host->socket, &address, &buf, 1);
+}
+
+int ENET_CALLBACK InterceptCallback(ENetHost* host, ENetEvent* event)
+{
+ // wakeup packet received
+ if (host->receivedDataLength == 1 && host->receivedData[0] == 0)
+ {
+ event->type = (ENetEventType) 42;
+ return 1;
+ }
+ return 0;
+}
+
+
+}
diff --git a/Source/Core/Common/ENetUtil.h b/Source/Core/Common/ENetUtil.h
new file mode 100644
index 0000000000..219f51d425
--- /dev/null
+++ b/Source/Core/Common/ENetUtil.h
@@ -0,0 +1,16 @@
+// Copyright 2015 Dolphin Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+//
+#pragma once
+
+#include
+#include "Common.h"
+
+namespace ENetUtil
+{
+
+void WakeupThread(ENetHost* host);
+int ENET_CALLBACK InterceptCallback(ENetHost* host, ENetEvent* event);
+
+}
diff --git a/Source/Core/Common/TraversalClient.cpp b/Source/Core/Common/TraversalClient.cpp
index 72d18244f3..f17ce0d921 100644
--- a/Source/Core/Common/TraversalClient.cpp
+++ b/Source/Core/Common/TraversalClient.cpp
@@ -7,9 +7,10 @@ static void GetRandomishBytes(u8* buf, size_t size)
{
// We don't need high quality random numbers (which might not be available),
// just non-repeating numbers!
- srand(enet_time_get());
+ static std::mt19937 prng(enet_time_get());
+ static std::uniform_int_distribution u8_distribution(0, 255);
for (size_t i = 0; i < size; i++)
- buf[i] = rand() & 0xff;
+ buf[i] = u8_distribution(prng);
}
TraversalClient::TraversalClient(ENetHost* netHost, const std::string& server, const u16 port)
@@ -301,7 +302,8 @@ void TraversalClient::Reset()
int ENET_CALLBACK TraversalClient::InterceptCallback(ENetHost* host, ENetEvent* event)
{
auto traversalClient = g_TraversalClient.get();
- if (traversalClient->TestPacket(host->receivedData, host->receivedDataLength, &host->receivedAddress))
+ if (traversalClient->TestPacket(host->receivedData, host->receivedDataLength, &host->receivedAddress)
+ || (host->receivedDataLength == 1 && host->receivedData[0] == 0))
{
event->type = (ENetEventType)42;
return 1;
diff --git a/Source/Core/Common/TraversalClient.h b/Source/Core/Common/TraversalClient.h
index 0263d863fb..ddfb38fce1 100644
--- a/Source/Core/Common/TraversalClient.h
+++ b/Source/Core/Common/TraversalClient.h
@@ -4,6 +4,7 @@
#include
#include
#include
+#include
#include
#include "Common/Common.h"
#include "Common/Thread.h"
diff --git a/Source/Core/Core/NetPlayClient.cpp b/Source/Core/Core/NetPlayClient.cpp
index b2012c10ce..b424932e77 100644
--- a/Source/Core/Core/NetPlayClient.cpp
+++ b/Source/Core/Core/NetPlayClient.cpp
@@ -103,7 +103,10 @@ NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlay
if (net > 0 && netEvent.type == ENET_EVENT_TYPE_CONNECT)
{
if (Connect())
+ {
+ m_client->intercept = ENetUtil::InterceptCallback;
m_thread = std::thread(&NetPlayClient::ThreadFunc, this);
+ }
}
else
{
@@ -416,7 +419,6 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
spac << (MessageId)NP_MSG_PONG;
spac << ping_key;
- std::lock_guard lks(m_crit.send);
Send(spac);
}
break;
@@ -480,6 +482,15 @@ void NetPlayClient::Disconnect()
m_server = nullptr;
}
+void NetPlayClient::SendAsync(sf::Packet* packet)
+{
+ {
+ std::lock_guard lkq(m_crit.async_queue_write);
+ m_async_queue.Push(std::unique_ptr(packet));
+ }
+ ENetUtil::WakeupThread(m_client);
+}
+
// called from ---NETPLAY--- thread
void NetPlayClient::ThreadFunc()
{
@@ -487,11 +498,13 @@ void NetPlayClient::ThreadFunc()
{
ENetEvent netEvent;
int net;
+ if (m_traversal_client)
+ m_traversal_client->HandleResends();
+ net = enet_host_service(m_client, &netEvent, 250);
+ while (!m_async_queue.Empty())
{
- std::lock_guard lks(m_crit.send);
- if (m_traversal_client)
- m_traversal_client->HandleResends();
- net = enet_host_service(m_client, &netEvent, 4);
+ Send(*(m_async_queue.Front().get()));
+ m_async_queue.Pop();
}
if (net > 0)
{
@@ -517,7 +530,6 @@ void NetPlayClient::ThreadFunc()
break;
}
}
-
}
Disconnect();
@@ -577,57 +589,47 @@ void NetPlayClient::GetPlayers(std::vector &player_list)
// called from ---GUI--- thread
void NetPlayClient::SendChatMessage(const std::string& msg)
{
- sf::Packet spac;
- spac << (MessageId)NP_MSG_CHAT_MESSAGE;
- spac << msg;
-
- std::lock_guard lks(m_crit.send);
- Send(spac);
+ sf::Packet* spac = new sf::Packet;
+ *spac << (MessageId)NP_MSG_CHAT_MESSAGE;
+ *spac << msg;
+ SendAsync(spac);
}
// called from ---CPU--- thread
void NetPlayClient::SendPadState(const PadMapping in_game_pad, const GCPadStatus& pad)
{
- // send to server
- sf::Packet spac;
- spac << (MessageId)NP_MSG_PAD_DATA;
- spac << in_game_pad;
- spac << pad.button << pad.analogA << pad.analogB << pad.stickX << pad.stickY << pad.substickX << pad.substickY << pad.triggerLeft << pad.triggerRight;
+ sf::Packet* spac = new sf::Packet;
+ *spac << (MessageId)NP_MSG_PAD_DATA;
+ *spac << in_game_pad;
+ *spac << pad.button << pad.analogA << pad.analogB << pad.stickX << pad.stickY << pad.substickX << pad.substickY << pad.triggerLeft << pad.triggerRight;
- std::lock_guard lks(m_crit.send);
- Send(spac);
+ SendAsync(spac);
}
// called from ---CPU--- thread
void NetPlayClient::SendWiimoteState(const PadMapping in_game_pad, const NetWiimote& nw)
{
- // send to server
- sf::Packet spac;
- spac << (MessageId)NP_MSG_WIIMOTE_DATA;
- spac << in_game_pad;
- spac << (u8)nw.size();
+ sf::Packet* spac = new sf::Packet;
+ *spac << (MessageId)NP_MSG_WIIMOTE_DATA;
+ *spac << in_game_pad;
+ *spac << (u8)nw.size();
for (auto it : nw)
{
- spac << it;
+ *spac << it;
}
-
- std::lock_guard lks(m_crit.send);
- Send(spac);
+ SendAsync(spac);
}
// called from ---GUI--- thread
bool NetPlayClient::StartGame(const std::string &path)
{
std::lock_guard lkg(m_crit.game);
-
// tell server i started the game
- sf::Packet spac;
- spac << (MessageId)NP_MSG_START_GAME;
- spac << m_current_game;
- spac << (char *)&g_NetPlaySettings;
-
- std::lock_guard lks(m_crit.send);
- Send(spac);
+ sf::Packet* spac = new sf::Packet;
+ *spac << (MessageId)NP_MSG_START_GAME;
+ *spac << m_current_game;
+ *spac << (char *)&g_NetPlaySettings;
+ SendAsync(spac);
if (m_is_running)
{
@@ -954,6 +956,7 @@ bool NetPlayClient::StopGame()
return true;
}
+// called from ---GUI--- thread
void NetPlayClient::Stop()
{
if (m_is_running == false)
@@ -976,9 +979,9 @@ void NetPlayClient::Stop()
// tell the server to stop if we have a pad mapped in game.
if (isPadMapped)
{
- sf::Packet spac;
- spac << (MessageId)NP_MSG_STOP_GAME;
- Send(spac);
+ sf::Packet* spac = new sf::Packet;
+ *spac << (MessageId)NP_MSG_STOP_GAME;
+ SendAsync(spac);
}
}
diff --git a/Source/Core/Core/NetPlayClient.h b/Source/Core/Core/NetPlayClient.h
index ab5763d313..e47dcb7e94 100644
--- a/Source/Core/Core/NetPlayClient.h
+++ b/Source/Core/Core/NetPlayClient.h
@@ -9,6 +9,7 @@
#include
#include
#include "Common/CommonTypes.h"
+#include "Common/ENetUtil.h"
#include "Common/FifoQueue.h"
#include "Common/Thread.h"
#include "Common/Timer.h"
@@ -47,6 +48,7 @@ class NetPlayClient : public TraversalClientClient
{
public:
void ThreadFunc();
+ void SendAsync(sf::Packet* packet);
NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name, bool traversal, std::string centralServer, u16 centralPort);
~NetPlayClient();
@@ -92,9 +94,12 @@ protected:
{
std::recursive_mutex game;
// lock order
- std::recursive_mutex players, send;
+ std::recursive_mutex players;
+ std::recursive_mutex async_queue_write;
} m_crit;
+ Common::FifoQueue, false> m_async_queue;
+
Common::FifoQueue m_pad_buffer[4];
Common::FifoQueue m_wiimote_buffer[4];
diff --git a/Source/Core/Core/NetPlayServer.cpp b/Source/Core/Core/NetPlayServer.cpp
index 1dcd5c1c8f..977d87e1fc 100644
--- a/Source/Core/Core/NetPlayServer.cpp
+++ b/Source/Core/Core/NetPlayServer.cpp
@@ -91,8 +91,9 @@ NetPlayServer::NetPlayServer(const u16 port, bool traversal, std::string central
serverAddr.host = ENET_HOST_ANY;
serverAddr.port = port;
m_server = enet_host_create(&serverAddr, 10, 3, 0, 0);
+ if (m_server != nullptr)
+ m_server->intercept = ENetUtil::InterceptCallback;
}
-
if (m_server != nullptr)
{
is_connected = true;
@@ -117,7 +118,6 @@ void NetPlayServer::ThreadFunc()
spac << (MessageId)NP_MSG_PING;
spac << m_ping_key;
- std::lock_guard lks(m_crit.send);
m_ping_timer.Start();
SendToClients(spac);
m_update_pings = false;
@@ -125,11 +125,16 @@ void NetPlayServer::ThreadFunc()
ENetEvent netEvent;
int net;
+ if (m_traversal_client)
+ m_traversal_client->HandleResends();
+ net = enet_host_service(m_server, &netEvent, 1000);
+ while (!m_async_queue.Empty())
{
- std::lock_guard lks(m_crit.send);
- if (m_traversal_client)
- m_traversal_client->HandleResends();
- net = enet_host_service(m_server, &netEvent, 4);
+ {
+ std::lock_guard lkp(m_crit.players);
+ SendToClients(*(m_async_queue.Front().get()));
+ }
+ m_async_queue.Pop();
}
if (net > 0)
{
@@ -149,7 +154,6 @@ void NetPlayServer::ThreadFunc()
sf::Packet spac;
spac << (MessageId)error;
// don't need to lock, this client isn't in the client map
- std::lock_guard lks(m_crit.send);
Send(accept_peer, spac);
if (netEvent.peer->data)
{
@@ -272,52 +276,46 @@ unsigned int NetPlayServer::OnConnect(ENetPeer* socket)
}
}
+ // send join message to already connected clients
+ sf::Packet spac;
+ spac << (MessageId)NP_MSG_PLAYER_JOIN;
+ spac << player.pid << player.name << player.revision;
+ SendToClients(spac);
+
+ // send new client success message with their id
+ spac.clear();
+ spac << (MessageId)0;
+ spac << player.pid;
+ Send(player.socket, spac);
+
+ // send new client the selected game
+ if (m_selected_game != "")
{
- std::lock_guard lks(m_crit.send);
+ spac.clear();
+ spac << (MessageId)NP_MSG_CHANGE_GAME;
+ spac << m_selected_game;
+ Send(player.socket, spac);
+ }
- // send join message to already connected clients
- sf::Packet spac;
+ // send the pad buffer value
+ spac.clear();
+ spac << (MessageId)NP_MSG_PAD_BUFFER;
+ spac << (u32)m_target_buffer_size;
+ Send(player.socket, spac);
+
+ // sync values with new client
+ for (const auto& p : m_players)
+ {
+ spac.clear();
spac << (MessageId)NP_MSG_PLAYER_JOIN;
- spac << player.pid << player.name << player.revision;
- SendToClients(spac);
-
- // send new client success message with their id
- spac.clear();
- spac << (MessageId)0;
- spac << player.pid;
+ spac << p.second.pid << p.second.name << p.second.revision;
Send(player.socket, spac);
-
- // send new client the selected game
- if (m_selected_game != "")
- {
- spac.clear();
- spac << (MessageId)NP_MSG_CHANGE_GAME;
- spac << m_selected_game;
- Send(player.socket, spac);
- }
-
- // send the pad buffer value
- spac.clear();
- spac << (MessageId)NP_MSG_PAD_BUFFER;
- spac << (u32)m_target_buffer_size;
- Send(player.socket, spac);
-
- // sync values with new client
- for (const auto& p : m_players)
- {
- spac.clear();
- spac << (MessageId)NP_MSG_PLAYER_JOIN;
- spac << p.second.pid << p.second.name << p.second.revision;
- Send(player.socket, spac);
- }
-
- } // unlock send
+ }
// add client to the player list
{
std::lock_guard lkp(m_crit.players);
m_players.insert(std::pair(*(PlayerId *)player.socket->data, player));
- std::lock_guard lks(m_crit.send);
UpdatePadMapping(); // sync pad mappings with everyone
UpdateWiimoteMapping();
}
@@ -343,7 +341,6 @@ unsigned int NetPlayServer::OnDisconnect(Client& player)
sf::Packet spac;
spac << (MessageId)NP_MSG_DISABLE_GAME;
// this thread doesn't need players lock
- std::lock_guard lks(m_crit.send);
SendToClients(spac, 1);
break;
}
@@ -362,7 +359,6 @@ unsigned int NetPlayServer::OnDisconnect(Client& player)
m_players.erase(it);
// alert other players of disconnect
- std::lock_guard lks(m_crit.send);
SendToClients(spac);
for (PadMapping& mapping : m_pad_map)
@@ -447,13 +443,20 @@ void NetPlayServer::AdjustPadBufferSize(unsigned int size)
m_target_buffer_size = size;
// tell clients to change buffer size
- sf::Packet spac;
- spac << (MessageId)NP_MSG_PAD_BUFFER;
- spac << (u32)m_target_buffer_size;
+ sf::Packet* spac = new sf::Packet;
+ *spac << (MessageId)NP_MSG_PAD_BUFFER;
+ *spac << (u32)m_target_buffer_size;
- std::lock_guard lkp(m_crit.players);
- std::lock_guard lks(m_crit.send);
- SendToClients(spac);
+ SendAsyncToClients(spac);
+}
+
+void NetPlayServer::SendAsyncToClients(sf::Packet* packet)
+{
+ {
+ std::lock_guard lkq(m_crit.async_queue_write);
+ m_async_queue.Push(std::unique_ptr(packet));
+ }
+ ENetUtil::WakeupThread(m_server);
}
// called from ---NETPLAY--- thread
@@ -478,10 +481,7 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
spac << player.pid;
spac << msg;
- {
- std::lock_guard lks(m_crit.send);
- SendToClients(spac, player.pid);
- }
+ SendToClients(spac, player.pid);
}
break;
@@ -505,7 +505,6 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
spac << (MessageId)NP_MSG_PAD_DATA;
spac << map << pad.button << pad.analogA << pad.analogB << pad.stickX << pad.stickY << pad.substickX << pad.substickY << pad.triggerLeft << pad.triggerRight;
- std::lock_guard lks(m_crit.send);
SendToClients(spac, player.pid);
}
break;
@@ -538,7 +537,6 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
for (const u8& byte : data)
spac << byte;
- std::lock_guard lks(m_crit.send);
SendToClients(spac, player.pid);
}
break;
@@ -559,7 +557,6 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
spac << player.pid;
spac << player.ping;
- std::lock_guard lks(m_crit.send);
SendToClients(spac);
}
break;
@@ -577,7 +574,6 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
spac << (MessageId)NP_MSG_STOP_GAME;
std::lock_guard lkp(m_crit.players);
- std::lock_guard lks(m_crit.send);
SendToClients(spac);
m_is_running = false;
@@ -601,17 +597,15 @@ void NetPlayServer::OnTraversalStateChanged()
m_dialog->Update();
}
-// called from ---GUI--- thread / and ---NETPLAY--- thread
+// called from ---GUI--- thread
void NetPlayServer::SendChatMessage(const std::string& msg)
{
- sf::Packet spac;
- spac << (MessageId)NP_MSG_CHAT_MESSAGE;
- spac << (PlayerId)0; // server id always 0
- spac << msg;
+ sf::Packet* spac = new sf::Packet;
+ *spac << (MessageId)NP_MSG_CHAT_MESSAGE;
+ *spac << (PlayerId)0; // server id always 0
+ *spac << msg;
- std::lock_guard lkp(m_crit.players);
- std::lock_guard lks(m_crit.send);
- SendToClients(spac);
+ SendAsyncToClients(spac);
}
// called from ---GUI--- thread
@@ -622,13 +616,11 @@ bool NetPlayServer::ChangeGame(const std::string &game)
m_selected_game = game;
// send changed game to clients
- sf::Packet spac;
- spac << (MessageId)NP_MSG_CHANGE_GAME;
- spac << game;
+ sf::Packet* spac = new sf::Packet;
+ *spac << (MessageId)NP_MSG_CHANGE_GAME;
+ *spac << game;
- std::lock_guard lkp(m_crit.players);
- std::lock_guard lks(m_crit.send);
- SendToClients(spac);
+ SendAsyncToClients(spac);
return true;
}
@@ -651,24 +643,22 @@ bool NetPlayServer::StartGame()
g_netplay_initial_gctime = Common::Timer::GetLocalTimeSinceJan1970();
// tell clients to start game
- sf::Packet spac;
- spac << (MessageId)NP_MSG_START_GAME;
- spac << m_current_game;
- spac << m_settings.m_CPUthread;
- spac << m_settings.m_CPUcore;
- spac << m_settings.m_DSPEnableJIT;
- spac << m_settings.m_DSPHLE;
- spac << m_settings.m_WriteToMemcard;
- spac << m_settings.m_OCEnable;
- spac << m_settings.m_OCFactor;
- spac << m_settings.m_EXIDevice[0];
- spac << m_settings.m_EXIDevice[1];
- spac << (u32)g_netplay_initial_gctime;
- spac << (u32)g_netplay_initial_gctime << 32;
+ sf::Packet* spac = new sf::Packet;
+ *spac << (MessageId)NP_MSG_START_GAME;
+ *spac << m_current_game;
+ *spac << m_settings.m_CPUthread;
+ *spac << m_settings.m_CPUcore;
+ *spac << m_settings.m_DSPEnableJIT;
+ *spac << m_settings.m_DSPHLE;
+ *spac << m_settings.m_WriteToMemcard;
+ *spac << m_settings.m_OCEnable;
+ *spac << m_settings.m_OCFactor;
+ *spac << m_settings.m_EXIDevice[0];
+ *spac << m_settings.m_EXIDevice[1];
+ *spac << (u32)g_netplay_initial_gctime;
+ *spac << (u32)g_netplay_initial_gctime << 32;
- std::lock_guard lkp(m_crit.players);
- std::lock_guard lks(m_crit.send);
- SendToClients(spac);
+ SendAsyncToClients(spac);
m_is_running = true;
diff --git a/Source/Core/Core/NetPlayServer.h b/Source/Core/Core/NetPlayServer.h
index 5e8ac76411..e1a22c8de9 100644
--- a/Source/Core/Core/NetPlayServer.h
+++ b/Source/Core/Core/NetPlayServer.h
@@ -9,6 +9,7 @@
#include
#include
#include
+#include "Common/ENetUtil.h"
#include "Common/Thread.h"
#include "Common/Timer.h"
#include "Common/TraversalClient.h"
@@ -20,6 +21,7 @@ class NetPlayServer : public TraversalClientClient
{
public:
void ThreadFunc();
+ void SendAsyncToClients(sf::Packet* packet);
NetPlayServer(const u16 port, bool traversal, std::string centralServer, u16 centralPort);
~NetPlayServer();
@@ -101,11 +103,13 @@ private:
{
std::recursive_mutex game;
// lock order
- std::recursive_mutex players, send;
+ std::recursive_mutex players;
+ std::recursive_mutex async_queue_write;
} m_crit;
std::string m_selected_game;
std::thread m_thread;
+ Common::FifoQueue, false> m_async_queue;
ENetHost* m_server;
TraversalClient* m_traversal_client;
diff --git a/Source/Core/DolphinWX/NetWindow.cpp b/Source/Core/DolphinWX/NetWindow.cpp
index 02e16cda3b..bae82f5bec 100644
--- a/Source/Core/DolphinWX/NetWindow.cpp
+++ b/Source/Core/DolphinWX/NetWindow.cpp
@@ -360,10 +360,10 @@ void NetPlaySetupDiag::OnHost(wxCommandEvent&)
unsigned long centralPort = 0;
m_traversal_port->GetValue().ToULong(¢ralPort);
netplay_server = new NetPlayServer(u16(port), trav, WxStrToStr(m_traversal_server->GetValue()), u16(centralPort));
- netplay_server->ChangeGame(game);
- netplay_server->AdjustPadBufferSize(INITIAL_PAD_BUFFER_SIZE);
if (netplay_server->is_connected)
{
+ netplay_server->ChangeGame(game);
+ netplay_server->AdjustPadBufferSize(INITIAL_PAD_BUFFER_SIZE);
#ifdef USE_UPNP
if (m_upnp_chk->GetValue())
netplay_server->TryPortmapping(port);