Advertisement
Guest User

Untitled

a guest
Jan 14th, 2019
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 29.95 KB | None | 0 0
  1. diff --git a/source/network/NetClient.cpp b/source/network/NetClient.cpp
  2. index c99a626b5c..662e537086 100644
  3. --- a/source/network/NetClient.cpp
  4. +++ b/source/network/NetClient.cpp
  5. @@ -36,6 +36,8 @@
  6.  #include "scriptinterface/ScriptInterface.h"
  7.  #include "simulation2/Simulation2.h"
  8.  
  9. +#include <map>
  10. +
  11.  CNetClient *g_NetClient = NULL;
  12.  
  13.  /**
  14. @@ -201,36 +203,25 @@ void CNetClient::Poll()
  15.  
  16.  void CNetClient::CheckServerConnection()
  17.  {
  18. -   // Trigger local warnings if the connection to the server is bad.
  19. -   // At most once per second.
  20.     std::time_t now = std::time(nullptr);
  21.     if (now <= m_LastConnectionCheck)
  22.         return;
  23.  
  24.     m_LastConnectionCheck = now;
  25.  
  26. -   JSContext* cx = GetScriptInterface().GetContext();
  27. -   JSAutoRequest rq(cx);
  28. +   m_ClientPerformance[m_GUID] = std::make_tuple(
  29. +       std::make_pair(m_Session->GetMeanRTT(), now),
  30. +       std::make_pair(m_Session->GetLastReceivedTime(), now),
  31. +       m_Session->GetPacketLossRatio());
  32.  
  33. -   // Report if we are losing the connection to the server
  34. -   u32 lastReceived = m_Session->GetLastReceivedTime();
  35. -   if (lastReceived > NETWORK_WARNING_TIMEOUT)
  36. +   // Remove old timeouts and pings, a23 fallback code
  37. +   for (std::map<std::string, std::tuple<std::pair<u32, u32>, std::pair<u32, u32>, double>>::iterator iter = m_ClientPerformance.begin(); iter != m_ClientPerformance.end(); ++iter)
  38.     {
  39. -       JS::RootedValue msg(cx);
  40. -       GetScriptInterface().Eval("({ 'type':'netwarn', 'warntype': 'server-timeout' })", &msg);
  41. -       GetScriptInterface().SetProperty(msg, "lastReceivedTime", lastReceived);
  42. -       PushGuiMessage(msg);
  43. -       return;
  44. -   }
  45. +       if (now - std::get<0>(iter->second).second >= 3)
  46. +           std::get<0>(iter->second) = std::make_pair(0, now);
  47.  
  48. -   // Report if we have a bad ping to the server
  49. -   u32 meanRTT = m_Session->GetMeanRTT();
  50. -   if (meanRTT > DEFAULT_TURN_LENGTH_MP)
  51. -   {
  52. -       JS::RootedValue msg(cx);
  53. -       GetScriptInterface().Eval("({ 'type':'netwarn', 'warntype': 'server-latency' })", &msg);
  54. -       GetScriptInterface().SetProperty(msg, "meanRTT", meanRTT);
  55. -       PushGuiMessage(msg);
  56. +       if (now - std::get<1>(iter->second).second >= 3)
  57. +           std::get<1>(iter->second) = std::make_pair(0, now);
  58.     }
  59.  }
  60.  
  61. @@ -663,10 +654,20 @@ bool CNetClient::OnPlayerAssignment(void* context, CFsmEvent* event)
  62.         assignment.m_PlayerID = message->m_Hosts[i].m_PlayerID;
  63.         assignment.m_Status = message->m_Hosts[i].m_Status;
  64.         newPlayerAssignments[message->m_Hosts[i].m_GUID] = assignment;
  65. +
  66. +       if (!client->m_ClientPerformance.count(message->m_Hosts[i].m_GUID))
  67. +           client->m_ClientPerformance[message->m_Hosts[i].m_GUID] = std::make_tuple(std::make_pair(0, 0), std::make_pair(0, 0), 0.d);
  68.     }
  69.  
  70.     client->m_PlayerAssignments.swap(newPlayerAssignments);
  71.  
  72. +   for (std::map<std::string, std::tuple<std::pair<u32, u32>, std::pair<u32, u32>, double>>::iterator iter = client->m_ClientPerformance.begin(); iter != client->m_ClientPerformance.end(); ++iter)
  73. +       if (!client->m_PlayerAssignments.count(iter->first))
  74. +       {
  75. +           client->m_ClientPerformance.erase(iter);
  76. +           break;
  77. +       }
  78. +
  79.     client->PostPlayerAssignmentsToScript();
  80.  
  81.     return true;
  82. @@ -780,14 +781,9 @@ bool CNetClient::OnClientTimeout(void *context, CFsmEvent* event)
  83.     JSAutoRequest rq(cx);
  84.  
  85.     CClientTimeoutMessage* message = (CClientTimeoutMessage*)event->GetParamRef();
  86. -   JS::RootedValue msg(cx);
  87. +   std::get<1>(client->m_ClientPerformance[message->m_GUID]) = std::make_pair(message->m_LastReceivedTime, std::time(nullptr));
  88.  
  89. -   client->GetScriptInterface().Eval("({ 'type':'netwarn', 'warntype': 'client-timeout' })", &msg);
  90. -   client->GetScriptInterface().SetProperty(msg, "guid", std::string(message->m_GUID));
  91. -   client->GetScriptInterface().SetProperty(msg, "lastReceivedTime", message->m_LastReceivedTime);
  92. -   client->PushGuiMessage(msg);
  93. -
  94. -   return true;
  95. +   return true;
  96.  }
  97.  
  98.  bool CNetClient::OnClientPerformance(void *context, CFsmEvent* event)
  99. @@ -802,17 +798,10 @@ bool CNetClient::OnClientPerformance(void *context, CFsmEvent* event)
  100.  
  101.     CClientPerformanceMessage* message = (CClientPerformanceMessage*)event->GetParamRef();
  102.  
  103. -   // Display warnings for other clients with bad ping
  104. -   for (size_t i = 0; i < message->m_Clients.size(); ++i)
  105. +   for (const CClientPerformanceMessage::S_m_Clients& mClient : message->m_Clients)
  106.     {
  107. -       if (message->m_Clients[i].m_MeanRTT < DEFAULT_TURN_LENGTH_MP || message->m_Clients[i].m_GUID == client->m_GUID)
  108. -           continue;
  109. -
  110. -       JS::RootedValue msg(cx);
  111. -       client->GetScriptInterface().Eval("({ 'type':'netwarn', 'warntype': 'client-latency' })", &msg);
  112. -       client->GetScriptInterface().SetProperty(msg, "guid", message->m_Clients[i].m_GUID);
  113. -       client->GetScriptInterface().SetProperty(msg, "meanRTT", message->m_Clients[i].m_MeanRTT);
  114. -       client->PushGuiMessage(msg);
  115. +       std::get<0>(client->m_ClientPerformance[mClient.m_GUID]) = std::make_pair(mClient.m_MeanRTT, std::time(nullptr));
  116. +       std::get<2>(client->m_ClientPerformance[mClient.m_GUID]) = (double) mClient.m_PacketLoss / (double) ENET_PEER_PACKET_LOSS_SCALE;
  117.     }
  118.  
  119.     return true;
  120. @@ -924,3 +913,22 @@ bool CNetClient::OnInGame(void *context, CFsmEvent* event)
  121.  
  122.     return true;
  123.  }
  124. +
  125. +JS::Value CNetClient::GetClientPerformance()
  126. +{
  127. +   JSContext* cx = GetScriptInterface().GetContext();
  128. +   JSAutoRequest rq(cx);
  129. +
  130. +   JS::RootedValue performanceVals(cx, JS::ObjectValue(*JS_NewPlainObject(cx)));
  131. +
  132. +   for (const std::pair<std::string, std::tuple<std::pair<u32, u32>, std::pair<u32, u32>, double>>& clientPerf : m_ClientPerformance)
  133. +   {
  134. +       JS::RootedValue performanceVal(cx, JS::ObjectValue(*JS_NewPlainObject(cx)));
  135. +       GetScriptInterface().SetProperty(performanceVal, "meanRTT", std::get<0>(clientPerf.second).first);
  136. +       GetScriptInterface().SetProperty(performanceVal, "lastReceivedTime", std::get<1>(clientPerf.second).first);
  137. +       GetScriptInterface().SetProperty(performanceVal, "packetLoss", std::get<2>(clientPerf.second));
  138. +       GetScriptInterface().SetProperty(performanceVals, clientPerf.first.c_str(), performanceVal);
  139. +   }
  140. +
  141. +   return performanceVals;
  142. +}
  143. diff --git a/source/network/NetClient.h b/source/network/NetClient.h
  144. index 9f0772f6e5..db28f2e170 100644
  145. --- a/source/network/NetClient.h
  146. +++ b/source/network/NetClient.h
  147. @@ -149,6 +149,8 @@ public:
  148.      */
  149.     void GuiPoll(JS::MutableHandleValue);
  150.  
  151. +   JS::Value GetClientPerformance();
  152. +
  153.     /**
  154.      * Add a message to the queue, to be read by GuiPoll.
  155.      * The script value must be in the GetScriptInterface() JS context.
  156. @@ -284,6 +286,9 @@ private:
  157.     /// Latest copy of player assignments heard from the server
  158.     PlayerAssignmentMap m_PlayerAssignments;
  159.  
  160. +   // Latest copy of roundtrip time and lost packets
  161. +   std::map<std::string, std::tuple<std::pair<u32, u32>, std::pair<u32, u32>, double>> m_ClientPerformance;
  162. +
  163.     /// Globally unique identifier to distinguish users beyond the lifetime of a single network session
  164.     CStr m_GUID;
  165.  
  166. diff --git a/source/network/NetClientTurnManager.cpp b/source/network/NetClientTurnManager.cpp
  167. index d94c75fc4f..0363aba9b5 100644
  168. --- a/source/network/NetClientTurnManager.cpp
  169. +++ b/source/network/NetClientTurnManager.cpp
  170. @@ -27,6 +27,8 @@
  171.  #include "ps/Util.h"
  172.  #include "simulation2/Simulation2.h"
  173.  
  174. +#include <chrono>
  175. +
  176.  #if 0
  177.  #define NETCLIENTTURN_LOG(...) debug_printf(__VA_ARGS__)
  178.  #else
  179. @@ -78,6 +80,8 @@ void CNetClientTurnManager::NotifyFinishedUpdate(u32 turn)
  180.         ENSURE(m_Simulation2.ComputeStateHash(hash, quick));
  181.     }
  182.  
  183. +   //debug_printf("%lu NotifyFinishedUpdate turn %d\n", std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(), turn);
  184. +
  185.     NETCLIENTTURN_LOG("NotifyFinishedUpdate(%d, %hs)\n", turn, Hexify(hash).c_str());
  186.  
  187.     m_Replay.Hash(hash, quick);
  188. diff --git a/source/network/NetMessages.h b/source/network/NetMessages.h
  189. index 902058935d..99be37ffae 100644
  190. --- a/source/network/NetMessages.h
  191. +++ b/source/network/NetMessages.h
  192. @@ -194,6 +194,7 @@ START_NMT_CLASS_(ClientPerformance, NMT_CLIENT_PERFORMANCE)
  193.     NMT_START_ARRAY(m_Clients)
  194.         NMT_FIELD(CStr, m_GUID)
  195.         NMT_FIELD_INT(m_MeanRTT, u32, 4)
  196. +       NMT_FIELD_INT(m_PacketLoss, u32, 4)
  197.     NMT_END_ARRAY()
  198.  END_NMT_CLASS()
  199.  
  200. diff --git a/source/network/NetServer.cpp b/source/network/NetServer.cpp
  201. index 7f884fc455..7988404adb 100644
  202. --- a/source/network/NetServer.cpp
  203. +++ b/source/network/NetServer.cpp
  204. @@ -45,6 +45,7 @@
  205.  #include <miniupnpc/upnperrors.h>
  206.  #endif
  207.  
  208. +#include <chrono>
  209.  #include <string>
  210.  
  211.  /**
  212. @@ -137,7 +138,7 @@ CNetServerWorker::CNetServerWorker(bool useLobbyAuth, int autostartPlayers) :
  213.     m_Shutdown(false),
  214.     m_ScriptInterface(NULL),
  215.     m_NextHostID(1), m_Host(NULL), m_HostGUID(), m_Stats(NULL),
  216. -   m_LastConnectionCheck(0)
  217. +   m_LastConnectionCheck(std::chrono::high_resolution_clock::now())
  218.  {
  219.     m_State = SERVER_STATE_UNCONNECTED;
  220.  
  221. @@ -361,6 +362,24 @@ bool CNetServerWorker::Broadcast(const CNetMessage* message, const std::vector<N
  222.     return ok;
  223.  }
  224.  
  225. +std::string CNetServerWorker::GetClientIPAddress(const std::string& guid)
  226. +{
  227. +   for (CNetServerSession* session : m_Sessions)
  228. +       if (session->GetGUID() == guid)
  229. +           return session->GetIPAddressString();
  230. +
  231. +   return "";
  232. +}
  233. +
  234. +std::string CNetServerWorker::GetHostname(const std::string& guid)
  235. +{
  236. +   for (CNetServerSession* session : m_Sessions)
  237. +       if (session->GetGUID() == guid)
  238. +           return session->GetHostname();
  239. +
  240. +   return "";
  241. +}
  242. +
  243.  void* CNetServerWorker::RunThread(void* data)
  244.  {
  245.     debug_SetThreadName("NetServer");
  246. @@ -452,7 +471,7 @@ bool CNetServerWorker::RunStep()
  247.     for (CNetServerSession* session : m_Sessions)
  248.         session->GetFileTransferer().Poll();
  249.  
  250. -   CheckClientConnections();
  251. +   BroadcastClientPerformance();
  252.  
  253.     // Process network events:
  254.  
  255. @@ -555,57 +574,54 @@ bool CNetServerWorker::RunStep()
  256.     return true;
  257.  }
  258.  
  259. -void CNetServerWorker::CheckClientConnections()
  260. +void CNetServerWorker::BroadcastClientPerformance()
  261.  {
  262.     // Send messages at most once per second
  263. -   std::time_t now = std::time(nullptr);
  264. -   if (now <= m_LastConnectionCheck)
  265. +   std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now();
  266. +   if (std::chrono::duration_cast<std::chrono::milliseconds>(now - m_LastConnectionCheck).count() < DEFAULT_TURN_LENGTH_MP * 2)
  267.         return;
  268.  
  269.     m_LastConnectionCheck = now;
  270.  
  271. -   for (size_t i = 0; i < m_Sessions.size(); ++i)
  272. +   for (CNetServerSession* addresseeSession : m_Sessions)
  273.     {
  274. -       u32 lastReceived = m_Sessions[i]->GetLastReceivedTime();
  275. -       u32 meanRTT = m_Sessions[i]->GetMeanRTT();
  276. +       // Skip disconnecting clients and clients in the loading screen
  277. +       if (addresseeSession->GetLastReceivedTime() >= 2000 ||
  278. +           addresseeSession->GetCurrState() == FSM_INVALID_STATE ||
  279. +           addresseeSession->GetCurrState() < NSS_PREGAME ||
  280. +           (addresseeSession->GetCurrState() == NSS_PREGAME && m_State == SERVER_STATE_LOADING))
  281. +              continue;
  282. +
  283. +       CClientPerformanceMessage performanceMsg;
  284. +       for (CNetServerSession* measuredSession : m_Sessions)
  285. +       {
  286. +           // Inform clients about every connection except their own (since they measure that themself)
  287. +           if (measuredSession == addresseeSession)
  288. +               continue;
  289.  
  290. -       CNetMessage* message = nullptr;
  291. +           // Step 1: Remember meanRTT
  292. +           u32 simDelay = m_ServerTurnManager ? m_ServerTurnManager->GetClientSimulationDelay(*measuredSession) : 0;
  293. +           if (simDelay < DEFAULT_TURN_LENGTH_MP * 1.1 ||
  294. +               std::find(m_PausingPlayers.begin(), m_PausingPlayers.end(), measuredSession->GetGUID()) != m_PausingPlayers.end())
  295. +               simDelay = 0;
  296.  
  297. -       // Report if we didn't hear from the client since few seconds
  298. -       if (lastReceived > NETWORK_WARNING_TIMEOUT)
  299. -       {
  300. -           CClientTimeoutMessage* msg = new CClientTimeoutMessage();
  301. -           msg->m_GUID = m_Sessions[i]->GetGUID();
  302. -           msg->m_LastReceivedTime = lastReceived;
  303. -           message = msg;
  304. -       }
  305. -       // Report if the client has bad ping
  306. -       else if (meanRTT > DEFAULT_TURN_LENGTH_MP)
  307. -       {
  308. -           CClientPerformanceMessage* msg = new CClientPerformanceMessage();
  309. -           CClientPerformanceMessage::S_m_Clients client;
  310. -           client.m_GUID = m_Sessions[i]->GetGUID();
  311. -           client.m_MeanRTT = meanRTT;
  312. -           msg->m_Clients.push_back(client);
  313. -           message = msg;
  314. -       }
  315. +           CClientPerformanceMessage::S_m_Clients msgPerformanceClient;
  316. +           msgPerformanceClient.m_GUID = measuredSession->GetGUID();
  317. +           msgPerformanceClient.m_MeanRTT = std::max(measuredSession->GetMeanRTT(), simDelay);
  318. +           msgPerformanceClient.m_PacketLoss = measuredSession->GetPacketLoss();
  319. +
  320. +           performanceMsg.m_Clients.push_back(msgPerformanceClient);
  321.  
  322. -       // Send to all clients except the affected one
  323. -       // (since that will show the locally triggered warning instead).
  324. -       // Also send it to clients that finished the loading screen while
  325. -       // the game is still waiting for other clients to finish the loading screen.
  326. -       if (message)
  327. -           for (size_t j = 0; j < m_Sessions.size(); ++j)
  328. +           // Step 2: Send timeout message per client
  329. +           if (measuredSession->GetLastReceivedTime() >= 2000)
  330.             {
  331. -               if (i != j && (
  332. -                   (m_Sessions[j]->GetCurrState() == NSS_PREGAME && m_State == SERVER_STATE_PREGAME) ||
  333. -                   m_Sessions[j]->GetCurrState() == NSS_INGAME))
  334. -               {
  335. -                   m_Sessions[j]->SendMessage(message);
  336. -               }
  337. +               CClientTimeoutMessage timeoutMsg;
  338. +               timeoutMsg.m_GUID = measuredSession->GetGUID();
  339. +               timeoutMsg.m_LastReceivedTime = measuredSession->GetLastReceivedTime();
  340. +               addresseeSession->SendMessage(&timeoutMsg);
  341.             }
  342. -
  343. -       SAFE_DELETE(message);
  344. +       }
  345. +       addresseeSession->SendMessage(&performanceMsg);
  346.     }
  347.  }
  348.  
  349. @@ -686,6 +702,8 @@ bool CNetServerWorker::HandleConnect(CNetServerSession* session)
  350.         return false;
  351.     }
  352.  
  353. +   // TODO: check for banned hostnames
  354. +
  355.     CSrvHandshakeMessage handshake;
  356.     handshake.m_Magic = PS_PROTOCOL_MAGIC;
  357.     handshake.m_ProtocolVersion = PS_PROTOCOL_VERSION;
  358. @@ -1580,6 +1598,19 @@ bool CNetServer::SetupConnection(const u16 port)
  359.     return m_Worker->SetupConnection(port);
  360.  }
  361.  
  362. +std::string CNetServer::GetClientIPAddress(const std::string& guid)
  363. +{
  364. +   // The server should broadcast the countries, IPs and hostnames in an admin packet each time a player joins/disconnects
  365. +   CScopeLock lock(m_Worker->m_WorkerMutex);
  366. +   return m_Worker->GetClientIPAddress(guid);
  367. +}
  368. +
  369. +std::string CNetServer::GetHostname(const std::string& guid)
  370. +{
  371. +   CScopeLock lock(m_Worker->m_WorkerMutex);
  372. +   return m_Worker->GetHostname(guid);
  373. +}
  374. +
  375.  void CNetServer::StartGame()
  376.  {
  377.     CScopeLock lock(m_Worker->m_WorkerMutex);
  378. diff --git a/source/network/NetServer.h b/source/network/NetServer.h
  379. index f17aebecc7..1b228cc6e7 100644
  380. --- a/source/network/NetServer.h
  381. +++ b/source/network/NetServer.h
  382. @@ -25,6 +25,7 @@
  383.  #include "ps/ThreadUtil.h"
  384.  #include "scriptinterface/ScriptTypes.h"
  385.  
  386. +#include <chrono>
  387.  #include <string>
  388.  #include <utility>
  389.  #include <vector>
  390. @@ -141,6 +142,9 @@ public:
  391.  
  392.     bool UseLobbyAuth() const;
  393.  
  394. +   std::string GetClientIPAddress(const std::string& guid);
  395. +   std::string GetHostname(const std::string& guid);
  396. +
  397.     void OnLobbyAuth(const CStr& name, const CStr& token);
  398.  
  399.     void SendHolePunchingMessage(const CStr& ip, u16 port);
  400. @@ -184,6 +188,9 @@ public:
  401.      */
  402.     bool Broadcast(const CNetMessage* message, const std::vector<NetServerSessionState>& targetStates);
  403.  
  404. +   std::string GetClientIPAddress(const std::string& guid);
  405. +   std::string GetHostname(const std::string& guid);
  406. +
  407.  private:
  408.     friend class CNetServer;
  409.     friend class CNetFileReceiveTask_ServerRejoin;
  410. @@ -281,9 +288,9 @@ private:
  411.     void HandleMessageReceive(const CNetMessage* message, CNetServerSession* session);
  412.  
  413.     /**
  414. -    * Send a network warning if the connection to a client is being lost or has bad latency.
  415. +    * Inform clients if the connection to a client is being lost or has bad latency.
  416.      */
  417. -   void CheckClientConnections();
  418. +   void BroadcastClientPerformance();
  419.  
  420.     void SendHolePunchingMessage(const CStr& ip, u16 port);
  421.  
  422. @@ -321,6 +328,11 @@ private:
  423.     std::vector<u32> m_BannedIPs;
  424.     std::vector<CStrW> m_BannedPlayers;
  425.  
  426. +   /**
  427. +    * Caches hostname per GUID of connected players.
  428. +    */
  429. +   //std::vector<std::string, std::string> g_HostNames;
  430. +
  431.     /**
  432.      * Holds the GUIDs of all currently paused players.
  433.      */
  434. @@ -348,7 +360,7 @@ private:
  435.     /**
  436.      *  Time when the clients connections were last checked for timeouts and latency.
  437.      */
  438. -   std::time_t m_LastConnectionCheck;
  439. +   std::chrono::high_resolution_clock::time_point m_LastConnectionCheck;
  440.  
  441.  private:
  442.     // Thread-related stuff:
  443. diff --git a/source/network/NetServerTurnManager.cpp b/source/network/NetServerTurnManager.cpp
  444. index 11130b29a3..53f7b30032 100644
  445. --- a/source/network/NetServerTurnManager.cpp
  446. +++ b/source/network/NetServerTurnManager.cpp
  447. @@ -32,7 +32,8 @@
  448.  #endif
  449.  
  450.  CNetServerTurnManager::CNetServerTurnManager(CNetServerWorker& server)
  451. -   : m_NetServer(server), m_ReadyTurn(1), m_TurnLength(DEFAULT_TURN_LENGTH_MP), m_HasSyncError(false)
  452. +   : m_NetServer(server), m_ReadyTurn(1), m_TurnLength(DEFAULT_TURN_LENGTH_MP), m_HasSyncError(false),
  453. +   m_ReadyTurnStartTime(std::chrono::high_resolution_clock::now())
  454.  {
  455.     // The first turn we will actually execute is number 2,
  456.     // so store dummy values into the saved lengths list
  457. @@ -62,6 +63,7 @@ void CNetServerTurnManager::NotifyFinishedClientCommands(CNetServerSession& sess
  458.     }
  459.  
  460.     m_ClientsReady[client] = turn;
  461. +   //debug_printf("%lu Client %d ready for turn %d\n", std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(), m_ReadyTurn);
  462.  
  463.     // Check whether this was the final client to become ready
  464.     CheckClientsReady();
  465. @@ -78,6 +80,8 @@ void CNetServerTurnManager::CheckClientsReady()
  466.     }
  467.  
  468.     ++m_ReadyTurn;
  469. +   m_ReadyTurnStartTime = std::chrono::high_resolution_clock::now();
  470. +   //debug_printf("%lu Next turn %d %d\n", std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(), m_ReadyTurn);
  471.  
  472.     NETSERVERTURN_LOG("CheckClientsReady: ready for turn %d\n", m_ReadyTurn);
  473.  
  474. @@ -199,3 +203,11 @@ u32 CNetServerTurnManager::GetSavedTurnLength(u32 turn)
  475.     ENSURE(turn <= m_ReadyTurn);
  476.     return m_SavedTurnLengths.at(turn);
  477.  }
  478. +
  479. +u32 CNetServerTurnManager::GetClientSimulationDelay(CNetServerSession& session)
  480. +{
  481. +   if (m_ClientsReady.find(session.GetHostID()) == m_ClientsReady.end() || m_ClientsReady[session.GetHostID()] > m_ReadyTurn)
  482. +       return 0;
  483. +
  484. +   return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - m_ReadyTurnStartTime).count();
  485. +}
  486. diff --git a/source/network/NetServerTurnManager.h b/source/network/NetServerTurnManager.h
  487. index 2eb3b81b50..10bb473280 100644
  488. --- a/source/network/NetServerTurnManager.h
  489. +++ b/source/network/NetServerTurnManager.h
  490. @@ -18,9 +18,11 @@
  491.  #ifndef INCLUDED_NETSERVERTURNMANAGER
  492.  #define INCLUDED_NETSERVERTURNMANAGER
  493.  
  494. -#include <map>
  495.  #include "ps/CStr.h"
  496.  
  497. +#include <chrono>
  498. +#include <map>
  499. +
  500.  class CNetServerWorker;
  501.  class CNetServerSession;
  502.  
  503. @@ -67,6 +69,11 @@ public:
  504.      */
  505.     u32 GetSavedTurnLength(u32 turn);
  506.  
  507. +   /**
  508. +    * Returns the number of milliseconds everyone is waiting for the client to progress.
  509. +    */
  510. +   u32 GetClientSimulationDelay(CNetServerSession& session);
  511. +
  512.  private:
  513.     void CheckClientsReady();
  514.  
  515. @@ -86,6 +93,9 @@ private:
  516.     // Map of client ID -> playername
  517.     std::map<u32, CStrW> m_ClientPlayernames;
  518.  
  519. +   // Time since when the server is waiting for clients
  520. +   std::chrono::high_resolution_clock::time_point m_ReadyTurnStartTime;
  521. +
  522.     // Current turn length
  523.     u32 m_TurnLength;
  524.  
  525. diff --git a/source/network/NetSession.cpp b/source/network/NetSession.cpp
  526. index f0a5bbf2af..a318e5ff4f 100644
  527. --- a/source/network/NetSession.cpp
  528. +++ b/source/network/NetSession.cpp
  529. @@ -27,10 +27,11 @@
  530.  #include "ps/Profile.h"
  531.  #include "scriptinterface/ScriptInterface.h"
  532.  
  533. -const u32 NETWORK_WARNING_TIMEOUT = 2000;
  534. -
  535.  const u32 MAXIMUM_HOST_TIMEOUT = std::numeric_limits<u32>::max();
  536.  
  537. +const double PACKET_LOSS_SCALE = (1 << 16);
  538. +const double PACKET_LOSS_SCALE_FACTOR = PACKET_LOSS_SCALE / ENET_PEER_PACKET_LOSS_SCALE;
  539. +
  540.  static const int CHANNEL_COUNT = 1;
  541.  
  542.  // Only disable long timeouts after a packet from the remote enet peer has been processed.
  543. @@ -149,6 +150,7 @@ void CNetClientSession::Poll()
  544.             // Report the server address
  545.             char hostname[256] = "(error)";
  546.             enet_address_get_host_ip(&event.peer->address, hostname, ARRAY_SIZE(hostname));
  547. +
  548.             LOGMESSAGE("Net client: Connected to %s:%u", hostname, (unsigned int)event.peer->address.port);
  549.  
  550.             m_Client.HandleConnect();
  551. @@ -221,6 +223,14 @@ u32 CNetClientSession::GetMeanRTT() const
  552.     return m_Server->roundTripTime;
  553.  }
  554.  
  555. +double CNetClientSession::GetPacketLossRatio() const
  556. +{
  557. +   if (!m_Server)
  558. +       return 0;
  559. +
  560. +   return (double) m_Server->packetLoss / (double) ENET_PEER_PACKET_LOSS_SCALE;
  561. +}
  562. +
  563.  void CNetClientSession::SetLongTimeout(bool enabled)
  564.  {
  565.     SetEnetLongTimeout(m_Server, m_IsLocalClient, enabled);
  566. @@ -229,6 +239,9 @@ void CNetClientSession::SetLongTimeout(bool enabled)
  567.  CNetServerSession::CNetServerSession(CNetServerWorker& server, ENetPeer* peer) :
  568.     m_Server(server), m_FileTransferer(this), m_Peer(peer), m_IsLocalClient(false), m_HostID(0), m_GUID(), m_UserName()
  569.  {
  570. +   char hostname[256] = "(error)";
  571. +   if (enet_address_get_host(&peer->address, hostname, ARRAY_SIZE(hostname)) == 0)
  572. +       m_Hostname = hostname;
  573.  }
  574.  
  575.  u32 CNetServerSession::GetIPAddress() const
  576. @@ -236,6 +249,22 @@ u32 CNetServerSession::GetIPAddress() const
  577.     return m_Peer->address.host;
  578.  }
  579.  
  580. +std::string CNetServerSession::GetIPAddressString() const
  581. +{
  582. +   char ipAddress[256];
  583. +   ipAddress[255] = '\0';
  584. +
  585. +   if (enet_address_get_host_ip(&m_Peer->address, ipAddress, sizeof ipAddress) != 0)
  586. +       return std::string();
  587. +
  588. +   return ipAddress;
  589. +}
  590. +
  591. +std::string CNetServerSession::GetHostname() const
  592. +{
  593. +   return m_Hostname;
  594. +}
  595. +
  596.  u32 CNetServerSession::GetLastReceivedTime() const
  597.  {
  598.     if (!m_Peer)
  599. @@ -252,6 +281,14 @@ u32 CNetServerSession::GetMeanRTT() const
  600.     return m_Peer->roundTripTime;
  601.  }
  602.  
  603. +u32 CNetServerSession::GetPacketLoss() const
  604. +{
  605. +   if (!m_Peer)
  606. +       return 0;
  607. +
  608. +   return (double) m_Peer->packetLoss * PACKET_LOSS_SCALE_FACTOR;
  609. +}
  610. +
  611.  void CNetServerSession::Disconnect(u32 reason)
  612.  {
  613.     Update((uint)NMT_CONNECTION_LOST, NULL);
  614. diff --git a/source/network/NetSession.h b/source/network/NetSession.h
  615. index 298d99c75f..5fba4f7ac9 100644
  616. --- a/source/network/NetSession.h
  617. +++ b/source/network/NetSession.h
  618. @@ -25,14 +25,14 @@
  619.  #include "scriptinterface/ScriptVal.h"
  620.  
  621.  /**
  622. - * Report the peer if we didn't receive a packet after this time (milliseconds).
  623. + *  Maximum timeout of the local client of the host (milliseconds).
  624.   */
  625. -extern const u32 NETWORK_WARNING_TIMEOUT;
  626. +extern const u32 MAXIMUM_HOST_TIMEOUT;
  627.  
  628.  /**
  629. - *  Maximum timeout of the local client of the host (milliseconds).
  630. + * Denominator of the packet loss ratio, whereas the numerator is sent as u32.
  631.   */
  632. -extern const u32 MAXIMUM_HOST_TIMEOUT;
  633. +extern const double PACKET_LOSS_SCALE;
  634.  
  635.  class CNetClient;
  636.  class CNetServerWorker;
  637. @@ -105,6 +105,11 @@ public:
  638.      */
  639.     u32 GetMeanRTT() const;
  640.  
  641. +   /**
  642. +    * Average ratio of packets lost.
  643. +    */
  644. +   double GetPacketLossRatio() const;
  645. +
  646.     /**
  647.      * Allows increasing the timeout to prevent drops during an expensive operation,
  648.      * and decreasing it back to normal afterwards.
  649. @@ -153,6 +158,8 @@ public:
  650.     void SetHostID(u32 id) { m_HostID = id; }
  651.  
  652.     u32 GetIPAddress() const;
  653. +   std::string GetIPAddressString() const;
  654. +   std::string GetHostname() const;
  655.  
  656.     /**
  657.      * Whether this client is running in the same process as the server.
  658. @@ -169,6 +176,11 @@ public:
  659.      */
  660.     u32 GetMeanRTT() const;
  661.  
  662. +   /**
  663. +    * Average ratio of packets lost with regards to ENET_PEER_PACKET_LOSS_SCALE. Indicates connection quality.
  664. +    */
  665. +   u32 GetPacketLoss() const;
  666. +
  667.     /**
  668.      * Sends a disconnection notification to the client,
  669.      * and sends a NMT_CONNECTION_LOST message to the session FSM.
  670. @@ -213,6 +225,9 @@ private:
  671.     CStrW m_UserName;
  672.     u32 m_HostID;
  673.  
  674. +   // Cache
  675. +   CStr m_Hostname;
  676. +
  677.     bool m_IsLocalClient;
  678.  };
  679.  
  680. diff --git a/source/network/scripting/JSInterface_Network.cpp b/source/network/scripting/JSInterface_Network.cpp
  681. index 9b7fd7136a..b21b71e023 100644
  682. --- a/source/network/scripting/JSInterface_Network.cpp
  683. +++ b/source/network/scripting/JSInterface_Network.cpp
  684. @@ -23,12 +23,14 @@
  685.  #include "lib/external_libraries/libsdl.h"
  686.  #include "lib/types.h"
  687.  #include "lobby/IXmppClient.h"
  688. +#include "network/IPTools.h"
  689.  #include "network/NetClient.h"
  690.  #include "network/NetMessage.h"
  691.  #include "network/NetServer.h"
  692.  #include "network/StunClient.h"
  693.  #include "ps/CLogger.h"
  694.  #include "ps/Game.h"
  695. +#include "simulation2/system/TurnManager.h"
  696.  #include "scriptinterface/ScriptInterface.h"
  697.  
  698.  u16 JSI_Network::GetDefaultPort(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
  699. @@ -163,6 +165,18 @@ JS::Value JSI_Network::PollNetworkClient(ScriptInterface::CxPrivate* pCxPrivate)
  700.     return pCxPrivate->pScriptInterface->CloneValueFromOtherContext(g_NetClient->GetScriptInterface(), pollNet);
  701.  }
  702.  
  703. +JS::Value JSI_Network::GetNetworkClientPerformance(ScriptInterface::CxPrivate* pCxPrivate)
  704. +{
  705. +   if (!g_NetClient)
  706. +       return JS::UndefinedValue();
  707. +// TODO: Too many questionmarks in the dialog
  708. +   // Convert from net client context to GUI script context
  709. +   JSContext* cxNet = g_NetClient->GetScriptInterface().GetContext();
  710. +   JSAutoRequest rqNet(cxNet);
  711. +   JS::RootedValue pollNet(cxNet, g_NetClient->GetClientPerformance());
  712. +   return pCxPrivate->pScriptInterface->CloneValueFromOtherContext(g_NetClient->GetScriptInterface(), pollNet);
  713. +}
  714. +
  715.  void JSI_Network::SetNetworkGameAttributes(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue attribs1)
  716.  {
  717.     ENSURE(g_NetClient);
  718. @@ -216,6 +230,11 @@ void JSI_Network::StartNetworkGame(ScriptInterface::CxPrivate* UNUSED(pCxPrivate
  719.     g_NetClient->SendStartGameMessage();
  720.  }
  721.  
  722. +u32 JSI_Network::GetTurnLength(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
  723. +{
  724. +   return DEFAULT_TURN_LENGTH_MP;
  725. +}
  726. +
  727.  void JSI_Network::SetTurnLength(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int length)
  728.  {
  729.     if (g_NetServer)
  730. @@ -224,6 +243,32 @@ void JSI_Network::SetTurnLength(ScriptInterface::CxPrivate* UNUSED(pCxPrivate),
  731.         LOGERROR("Only network host can change turn length");
  732.  }
  733.  
  734. +std::string JSI_Network::GetClientIPAddress(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const std::string& guid)
  735. +{
  736. +   if (!g_NetServer)
  737. +       return std::string();
  738. +
  739. +   return g_NetServer->GetClientIPAddress(guid);
  740. +}
  741. +
  742. +std::string JSI_Network::LookupClientHostname(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const std::string& guid)
  743. +{
  744. +   if (!g_NetServer)
  745. +       return std::string();
  746. +
  747. +   return g_NetServer->GetHostname(guid);
  748. +}
  749. +
  750. +u32 JSI_Network::IPv4ToNumber(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const std::string& ipAddress)
  751. +{
  752. +   u32 ipAddressNum = 0;
  753. +
  754. +   if (!IPTools::ParseIPv4Address(ipAddress, ipAddressNum))
  755. +       return 0;
  756. +
  757. +   return ipAddressNum;
  758. +}
  759. +
  760.  void JSI_Network::RegisterScriptFunctions(const ScriptInterface& scriptInterface)
  761.  {
  762.     scriptInterface.RegisterFunction<u16, &GetDefaultPort>("GetDefaultPort");
  763. @@ -235,6 +280,7 @@ void JSI_Network::RegisterScriptFunctions(const ScriptInterface& scriptInterface
  764.     scriptInterface.RegisterFunction<void, &DisconnectNetworkGame>("DisconnectNetworkGame");
  765.     scriptInterface.RegisterFunction<CStr, &GetPlayerGUID>("GetPlayerGUID");
  766.     scriptInterface.RegisterFunction<JS::Value, &PollNetworkClient>("PollNetworkClient");
  767. +   scriptInterface.RegisterFunction<JS::Value, &GetNetworkClientPerformance>("GetNetworkClientPerformance");
  768.     scriptInterface.RegisterFunction<void, JS::HandleValue, &SetNetworkGameAttributes>("SetNetworkGameAttributes");
  769.     scriptInterface.RegisterFunction<void, int, CStr, &AssignNetworkPlayer>("AssignNetworkPlayer");
  770.     scriptInterface.RegisterFunction<void, CStrW, bool, &KickPlayer>("KickPlayer");
  771. @@ -242,5 +288,9 @@ void JSI_Network::RegisterScriptFunctions(const ScriptInterface& scriptInterface
  772.     scriptInterface.RegisterFunction<void, int, &SendNetworkReady>("SendNetworkReady");
  773.     scriptInterface.RegisterFunction<void, &ClearAllPlayerReady>("ClearAllPlayerReady");
  774.     scriptInterface.RegisterFunction<void, &StartNetworkGame>("StartNetworkGame");
  775. +   scriptInterface.RegisterFunction<u32, &GetTurnLength>("GetTurnLength");
  776.     scriptInterface.RegisterFunction<void, int, &SetTurnLength>("SetTurnLength");
  777. +   scriptInterface.RegisterFunction<std::string, std::string, &GetClientIPAddress>("GetClientIPAddress");
  778. +   scriptInterface.RegisterFunction<u32, std::string, &IPv4ToNumber>("IPv4ToNumber");
  779. +   scriptInterface.RegisterFunction<std::string, std::string, &LookupClientHostname>("LookupClientHostname");
  780.  }
  781. diff --git a/source/network/scripting/JSInterface_Network.h b/source/network/scripting/JSInterface_Network.h
  782. index 852bc47ace..7ccdbb2d28 100644
  783. --- a/source/network/scripting/JSInterface_Network.h
  784. +++ b/source/network/scripting/JSInterface_Network.h
  785. @@ -34,13 +34,18 @@ namespace JSI_Network
  786.     JS::Value FindStunEndpoint(ScriptInterface::CxPrivate* pCxPrivate, int port);
  787.     void DisconnectNetworkGame(ScriptInterface::CxPrivate* pCxPrivate);
  788.     JS::Value PollNetworkClient(ScriptInterface::CxPrivate* pCxPrivate);
  789. +   JS::Value GetNetworkClientPerformance(ScriptInterface::CxPrivate* pCxPrivate);
  790.     CStr GetPlayerGUID(ScriptInterface::CxPrivate* pCxPrivate);
  791.     void KickPlayer(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& playerName, bool ban);
  792.     void AssignNetworkPlayer(ScriptInterface::CxPrivate* pCxPrivate, int playerID, const CStr& guid);
  793.     void ClearAllPlayerReady (ScriptInterface::CxPrivate* pCxPrivate);
  794.     void SendNetworkChat(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& message);
  795.     void SendNetworkReady(ScriptInterface::CxPrivate* pCxPrivate, int message);
  796. +   u32 GetTurnLength(ScriptInterface::CxPrivate* pCxPrivate);
  797.     void SetTurnLength(ScriptInterface::CxPrivate* pCxPrivate, int length);
  798. +   std::string GetClientIPAddress(ScriptInterface::CxPrivate* pCxPrivate, const std::string& guid);
  799. +   std::string LookupClientHostname(ScriptInterface::CxPrivate* pCxPrivate, const std::string& guid);
  800. +   u32 IPv4ToNumber(ScriptInterface::CxPrivate* pCxPrivate, const std::string& ipAddress);
  801.  
  802.     void RegisterScriptFunctions(const ScriptInterface& scriptInterface);
  803.  }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement