Ticket #3264: t3264_show_network_warnings_v1.patch
File t3264_show_network_warnings_v1.patch, 34.0 KB (added by , 8 years ago) |
---|
-
binaries/data/config/default.cfg
xpartamupp = "wfgbot20" ; Na 350 350 enabledmods = "mod public" 351 351 352 352 [overlay] 353 353 fps = "false" ; Show frames per second in top right corner 354 354 realtime = "false" ; Show current system time in top right corner 355 netwarnings = "true" ; Show warnings if the network connection is bad 355 356 356 357 [profiler2] 357 358 autoenable = false ; Enable HTTP server output at startup (default off for security/performance) 358 359 script.enable = false ; Enable Javascript profiling. Needs to be set before startup and can't be changed later. (default off for performance) 359 360 gpu.arb.enable = true ; Allow GL_ARB_timer_query timing mode when available -
binaries/data/mods/public/gui/common/functions_global_object.js
1 /* 2 DESCRIPTION : Contains global GUI functions, which will later be accessible from every GUI script/file. 3 NOTES : So far, only the message box-related functions are implemented. 4 */ 1 /** 2 * Contains global GUI functions accessible from every GUI script/file. 3 * File will be reloaded when switching pages or showing message boxes! 4 */ 5 6 /** 7 * Number of milliseconds to display network warnings. 8 */ 9 var g_NetworkWarningTimeout = 3000; 10 11 /** 12 * Currently displayed network warnings. At most one message per user. 13 */ 14 var g_NetworkWarnings = {}; 15 16 /** 17 * Update GUI object once per second. 18 */ 19 var g_NetworkWarningsLastUpdate = 0; 20 21 /** 22 * Message-types to be displayed. 23 */ 24 var g_NetworkWarningTexts = { 25 26 "server-timeout": (msg, username) => 27 sprintf(translate("Losing connection to server (%(seconds)s)"), { 28 "seconds": Math.ceil(msg.lastReceivedTime / 1000) 29 }), 30 31 "client-timeout": (msg, username) => 32 sprintf(translate("%(player)s losing connection (%(seconds)s)"), { 33 "player": username, 34 "seconds": Math.ceil(msg.lastReceivedTime / 1000) 35 }), 36 37 "server-latency": (msg, username) => 38 sprintf(translate("Bad connection to server (%(milliseconds)sms)"), { 39 "milliseconds": msg.meanRTT 40 }), 41 42 "client-latency": (msg, username) => 43 sprintf(translate("Bad connection to %(player)s (%(milliseconds)sms)"), { 44 "player": username, 45 "milliseconds": msg.meanRTT 46 }) 47 }; 5 48 6 49 // ******************************************* 7 50 // messageBox 8 51 // ******************************************* 9 52 // @params: int mbWidth, int mbHeight, string mbMessage, string mbTitle, int mbMode, arr mbButtonCaptions, function mbBtnCode, var mbCallbackArgs … … function updateCounters() 138 181 139 182 var dataCounter = Engine.GetGUIObjectByName("dataCounter"); 140 183 dataCounter.caption = caption; 141 184 dataCounter.size = sprintf("100%%-100 40 100%%-5 %(bottom)s", { bottom: 40 + 14 * linesCount }); 142 185 } 186 187 /** 188 * @param msg - GUI message sent by NetServer or NetClient 189 */ 190 function addNetworkWarning(msg) 191 { 192 if (Engine.ConfigDB_GetValue("user", "overlay.netwarnings") != "true") 193 return; 194 195 if (!g_NetworkWarningTexts[msg.warntype]) 196 { 197 warn("Unknown network warning type received: " + JSON.stringify(msg)); 198 return; 199 } 200 201 // Remember this message for few seconds. 202 // Overwrite previous messages for this user. 203 g_NetworkWarnings[msg.guid || "server"] = { 204 "added": Date.now(), 205 "msg": msg 206 }; 207 } 208 209 /** 210 * Displays the most recent network warning of each client onscreen. 211 */ 212 function displayNetworkWarnings() 213 { 214 // Update once per second 215 let now = Date.now(); 216 if (now <= g_NetworkWarningsLastUpdate) 217 return; 218 219 // Hide GUI object if disabled 220 let showWarnings = Engine.ConfigDB_GetValue("user", "overlay.netwarnings") == "true"; 221 222 let networkWarnings = Engine.GetGUIObjectByName("networkWarnings"); 223 networkWarnings.hidden = !showWarnings; 224 225 if (!showWarnings) 226 return; 227 228 // Remove outdated messages 229 for (let guid in g_NetworkWarnings) 230 if (now - g_NetworkWarnings[guid].added > g_NetworkWarningTimeout || !g_PlayerAssignments[guid]) 231 delete g_NetworkWarnings[guid]; 232 233 // Sort messages to show local ones first 234 let guids = Object.keys(g_NetworkWarnings).sort(guid => guid != "server"); 235 236 // Get text and width 237 let formattedMessages = []; 238 let maxTextWidth = 0; 239 for (let guid of guids) 240 { 241 let msg = g_NetworkWarnings[guid].msg; 242 243 // Colorize message 244 formattedMessages.push(g_NetworkWarningTexts[msg.warntype](msg, colorizePlayernameByGUID(guid))); 245 246 // Get width of unformatted text 247 let textWidth = Engine.GetTextWidth("mono-stroke-10", g_NetworkWarningTexts[msg.warntype](msg, g_PlayerAssignments[guid].name)); 248 maxTextWidth = Math.max(textWidth, maxTextWidth); 249 } 250 251 // Update textbox size 252 let width = maxTextWidth + 20; 253 let height = 14 * formattedMessages.length; 254 255 let top = "40"; 256 let right = "100%-110"; 257 let bottom = top + "+" + height; 258 let left = right + "-" + width; 259 260 networkWarnings.caption = formattedMessages.join("\n"); 261 networkWarnings.size = left + " " + top + " " + right + " " + bottom; 262 } -
binaries/data/mods/public/gui/common/global.xml
12 12 13 13 <object> 14 14 15 15 <!-- 16 16 ========================================== 17 - NETWORK WARNINGS 18 ========================================== 19 --> 20 <object name="networkWarnings" 21 type="text" 22 ghost="true" 23 z="199" 24 size="100%-110 40 100%-110 40" 25 font="mono-stroke-10" 26 textcolor="255 219 77" 27 text_align="center" 28 text_valign="top" 29 sprite="color: 0 0 0 100" 30 > 31 <action on="Tick"> 32 displayNetworkWarnings(); 33 </action> 34 </object> 35 36 <!-- 37 ========================================== 17 38 - FPS & REAL TIME & GAME TIME COUNTER 18 39 ========================================== 19 40 --> 20 41 <object name="dataCounter" 21 42 type="text" -
binaries/data/mods/public/gui/gamesetup/gamesetup.js
const g_MapPath = { 26 26 /** 27 27 * Processes a CNetMessage (see NetMessage.h, NetMessages.h) sent by the CNetServer. 28 28 */ 29 29 const g_NetMessageTypes = { 30 30 "netstatus": msg => handleNetStatusMessage(msg), 31 "netwarn": msg => addNetworkWarning(msg), 31 32 "gamesetup": msg => handleGamesetupMessage(msg), 32 33 "players": msg => handlePlayerAssignmentMessage(msg), 33 34 "ready": msg => handleReadyMessage(msg), 34 35 "start": msg => handleGamestartMessage(msg), 35 36 "kicked": msg => addChatMessage({ "type": "kicked", "username": msg.username }), -
binaries/data/mods/public/gui/gamesetup/gamesetup_mp.js
function pollAndHandleNetworkClient() 124 124 "playerAssignments": g_PlayerAssignments 125 125 }); 126 126 break; 127 127 128 128 case "chat": 129 // Ignore, since we have nowhere to display chat messages 129 break; 130 131 case "netwarn": 130 132 break; 131 133 132 134 default: 133 135 error(sprintf("Unrecognised net message type %(messageType)s", { messageType: message.type })); 134 136 } … … function pollAndHandleNetworkClient() 167 169 default: 168 170 error(sprintf("Unrecognised netstatus type %(netType)s", { netType: message.status })); 169 171 break; 170 172 } 171 173 break; 174 175 case "netwarn": 176 break; 177 172 178 default: 173 179 error(sprintf("Unrecognised net message type %(messageType)s", { messageType: message.type })); 174 180 break; 175 181 } 176 182 } -
binaries/data/mods/public/gui/options/options.json
25 25 "tooltip": "Show detailed tooltips for trainable units in unit-producing buildings.", 26 26 "parameters": { "config": "showdetailedtooltips" } 27 27 }, 28 28 { 29 29 "type": "boolean", 30 "label": "Network Warnings", 31 "tooltip": "Show which player has a bad connection in multiplayer games.", 32 "parameters": { "config": "overlay.netwarnings" } 33 }, 34 { 35 "type": "boolean", 30 36 "label": "FPS Overlay", 31 37 "tooltip": "Show frames per second in top right corner.", 32 38 "parameters": { "config": "overlay.fps" } 33 39 }, 34 40 { -
binaries/data/mods/public/gui/session/messages.js
var g_ChatTimers = []; 27 27 /** 28 28 * Handle all netmessage types that can occur. 29 29 */ 30 30 var g_NetMessageTypes = { 31 31 "netstatus": msg => handleNetStatusMessage(msg), 32 "netwarn": msg => addNetworkWarning(msg), 32 33 "players": msg => handlePlayerAssignmentsMessage(msg), 33 34 "rejoined": msg => addChatMessage({ "type": "rejoined", "guid": msg.guid }), 34 35 "kicked": msg => addChatMessage({ "type": "system", "text": sprintf(translate("%(username)s has been kicked"), { "username": msg.username }) }), 35 36 "banned": msg => addChatMessage({ "type": "system", "text": sprintf(translate("%(username)s has been banned"), { "username": msg.username }) }), 36 37 "chat": msg => addChatMessage({ "type": "message", "guid": msg.guid, "text": msg.text }), -
source/gui/scripting/ScriptFunctions.cpp
18 18 #include "precompiled.h" 19 19 20 20 #include "scriptinterface/ScriptInterface.h" 21 21 22 22 #include "graphics/Camera.h" 23 #include "graphics/FontMetrics.h" 23 24 #include "graphics/GameView.h" 24 25 #include "graphics/MapReader.h" 25 26 #include "graphics/scripting/JSInterface_GameView.h" 26 27 #include "gui/GUI.h" 27 28 #include "gui/GUIManager.h" … … bool TemplateExists(ScriptInterface::CxP 873 874 CParamNode GetTemplate(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const std::string& templateName) 874 875 { 875 876 return g_GUI->GetTemplate(templateName); 876 877 } 877 878 879 int GetTextWidth(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), const std::string& fontName, const std::wstring& text) 880 { 881 int width = 0; 882 int height = 0; 883 CStrIntern _fontName (fontName); 884 CFontMetrics fontMetrics(_fontName); 885 fontMetrics.CalculateStringSize(text.c_str(), width, height); 886 return width; 887 } 888 878 889 //----------------------------------------------------------------------------- 879 890 // Timer 880 891 //----------------------------------------------------------------------------- 881 892 882 893 … … void GuiScriptingInit(ScriptInterface& s 1047 1058 scriptInterface.RegisterFunction<std::wstring, int, &GetBuildTimestamp>("GetBuildTimestamp"); 1048 1059 scriptInterface.RegisterFunction<JS::Value, std::wstring, &ReadJSONFile>("ReadJSONFile"); 1049 1060 scriptInterface.RegisterFunction<void, std::wstring, JS::HandleValue, &WriteJSONFile>("WriteJSONFile"); 1050 1061 scriptInterface.RegisterFunction<bool, std::string, &TemplateExists>("TemplateExists"); 1051 1062 scriptInterface.RegisterFunction<CParamNode, std::string, &GetTemplate>("GetTemplate"); 1063 scriptInterface.RegisterFunction<int, std::string, std::wstring, &GetTextWidth>("GetTextWidth"); 1052 1064 1053 1065 // User report functions 1054 1066 scriptInterface.RegisterFunction<bool, &IsUserReportEnabled>("IsUserReportEnabled"); 1055 1067 scriptInterface.RegisterFunction<void, bool, &SetUserReportEnabled>("SetUserReportEnabled"); 1056 1068 scriptInterface.RegisterFunction<std::string, &GetUserReportStatus>("GetUserReportStatus"); -
source/network/NetClient.cpp
1 /* Copyright (C) 201 5Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 5 * it under the terms of the GNU General Public License as published by 6 6 * the Free Software Foundation, either version 2 of the License, or … … private: 68 68 69 69 CNetClient::CNetClient(CGame* game) : 70 70 m_Session(NULL), 71 71 m_UserName(L"anonymous"), 72 72 m_GUID(ps_generate_guid()), m_HostID((u32)-1), m_ClientTurnManager(NULL), m_Game(game), 73 m_GameAttributes(game->GetSimulation2()->GetScriptInterface().GetContext()) 73 m_GameAttributes(game->GetSimulation2()->GetScriptInterface().GetContext()), 74 m_LastConnectionCheck(0) 74 75 { 75 76 m_Game->SetTurnManager(NULL); // delete the old local turn manager so we don't accidentally use it 76 77 77 78 void* context = this; 78 79 … … CNetClient::CNetClient(CGame* game) : 92 93 AddTransition(NCS_PREGAME, (uint)NMT_CHAT, NCS_PREGAME, (void*)&OnChat, context); 93 94 AddTransition(NCS_PREGAME, (uint)NMT_READY, NCS_PREGAME, (void*)&OnReady, context); 94 95 AddTransition(NCS_PREGAME, (uint)NMT_GAME_SETUP, NCS_PREGAME, (void*)&OnGameSetup, context); 95 96 AddTransition(NCS_PREGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_PREGAME, (void*)&OnPlayerAssignment, context); 96 97 AddTransition(NCS_PREGAME, (uint)NMT_KICKED, NCS_PREGAME, (void*)&OnKicked, context); 98 AddTransition(NCS_PREGAME, (uint)NMT_CLIENT_TIMEOUT, NCS_PREGAME, (void*)&OnClientTimeout, context); 99 AddTransition(NCS_PREGAME, (uint)NMT_CLIENT_PERFORMANCE, NCS_PREGAME, (void*)&OnClientPerformance, context); 97 100 AddTransition(NCS_PREGAME, (uint)NMT_GAME_START, NCS_LOADING, (void*)&OnGameStart, context); 98 101 AddTransition(NCS_PREGAME, (uint)NMT_JOIN_SYNC_START, NCS_JOIN_SYNCING, (void*)&OnJoinSyncStart, context); 99 102 100 103 AddTransition(NCS_JOIN_SYNCING, (uint)NMT_CHAT, NCS_JOIN_SYNCING, (void*)&OnChat, context); 101 104 AddTransition(NCS_JOIN_SYNCING, (uint)NMT_GAME_SETUP, NCS_JOIN_SYNCING, (void*)&OnGameSetup, context); 102 105 AddTransition(NCS_JOIN_SYNCING, (uint)NMT_PLAYER_ASSIGNMENT, NCS_JOIN_SYNCING, (void*)&OnPlayerAssignment, context); 106 AddTransition(NCS_JOIN_SYNCING, (uint)NMT_CLIENT_TIMEOUT, NCS_JOIN_SYNCING, (void*)&OnClientTimeout, context); 107 AddTransition(NCS_JOIN_SYNCING, (uint)NMT_CLIENT_PERFORMANCE, NCS_JOIN_SYNCING, (void*)&OnClientPerformance, context); 103 108 AddTransition(NCS_JOIN_SYNCING, (uint)NMT_GAME_START, NCS_JOIN_SYNCING, (void*)&OnGameStart, context); 104 109 AddTransition(NCS_JOIN_SYNCING, (uint)NMT_SIMULATION_COMMAND, NCS_JOIN_SYNCING, (void*)&OnInGame, context); 105 110 AddTransition(NCS_JOIN_SYNCING, (uint)NMT_END_COMMAND_BATCH, NCS_JOIN_SYNCING, (void*)&OnJoinSyncEndCommandBatch, context); 106 111 AddTransition(NCS_JOIN_SYNCING, (uint)NMT_LOADED_GAME, NCS_INGAME, (void*)&OnLoadedGame, context); 107 112 108 113 AddTransition(NCS_LOADING, (uint)NMT_CHAT, NCS_LOADING, (void*)&OnChat, context); 109 114 AddTransition(NCS_LOADING, (uint)NMT_GAME_SETUP, NCS_LOADING, (void*)&OnGameSetup, context); 110 115 AddTransition(NCS_LOADING, (uint)NMT_PLAYER_ASSIGNMENT, NCS_LOADING, (void*)&OnPlayerAssignment, context); 116 AddTransition(NCS_LOADING, (uint)NMT_CLIENT_TIMEOUT, NCS_LOADING, (void*)&OnClientTimeout, context); 117 AddTransition(NCS_LOADING, (uint)NMT_CLIENT_PERFORMANCE, NCS_LOADING, (void*)&OnClientPerformance, context); 111 118 AddTransition(NCS_LOADING, (uint)NMT_LOADED_GAME, NCS_INGAME, (void*)&OnLoadedGame, context); 112 119 113 120 AddTransition(NCS_INGAME, (uint)NMT_REJOINED, NCS_INGAME, (void*)&OnRejoined, context); 114 121 AddTransition(NCS_INGAME, (uint)NMT_KICKED, NCS_INGAME, (void*)&OnKicked, context); 122 AddTransition(NCS_INGAME, (uint)NMT_CLIENT_TIMEOUT, NCS_INGAME, (void*)&OnClientTimeout, context); 123 AddTransition(NCS_INGAME, (uint)NMT_CLIENT_PERFORMANCE, NCS_INGAME, (void*)&OnClientPerformance, context); 115 124 AddTransition(NCS_INGAME, (uint)NMT_CHAT, NCS_INGAME, (void*)&OnChat, context); 116 125 AddTransition(NCS_INGAME, (uint)NMT_GAME_SETUP, NCS_INGAME, (void*)&OnGameSetup, context); 117 126 AddTransition(NCS_INGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_INGAME, (void*)&OnPlayerAssignment, context); 118 127 AddTransition(NCS_INGAME, (uint)NMT_SIMULATION_COMMAND, NCS_INGAME, (void*)&OnInGame, context); 119 128 AddTransition(NCS_INGAME, (uint)NMT_SYNC_ERROR, NCS_INGAME, (void*)&OnInGame, context); … … void CNetClient::DestroyConnection() 168 177 SAFE_DELETE(m_Session); 169 178 } 170 179 171 180 void CNetClient::Poll() 172 181 { 173 if (m_Session) 174 m_Session->Poll(); 182 if (!m_Session) 183 return; 184 185 CheckServerConnection(); 186 m_Session->Poll(); 187 } 188 189 void CNetClient::CheckServerConnection() 190 { 191 // Trigger local warnings if the connection to the server is bad. 192 // At most once per second. 193 std::time_t now = std::time(nullptr); 194 if (now <= m_LastConnectionCheck) 195 return; 196 197 m_LastConnectionCheck = now; 198 199 JSContext* cx = GetScriptInterface().GetContext(); 200 201 // Report if we are losing the connection to the server 202 u32 lastReceived = m_Session->GetLastReceivedTime(); 203 if (lastReceived > NETWORK_WARNING_TIMEOUT) 204 { 205 JS::RootedValue msg(cx); 206 GetScriptInterface().Eval("({ 'type':'netwarn', 'warntype': 'server-timeout' })", &msg); 207 GetScriptInterface().SetProperty(msg, "lastReceivedTime", lastReceived); 208 PushGuiMessage(msg); 209 return; 210 } 211 212 // Report if we have a bad ping to the server 213 u32 meanRTT = m_Session->GetMeanRTT(); 214 if (meanRTT > DEFAULT_TURN_LENGTH_MP * NETWORK_WARNING_LATENCY) 215 { 216 JS::RootedValue msg(cx); 217 GetScriptInterface().Eval("({ 'type':'netwarn', 'warntype': 'server-latency' })", &msg); 218 GetScriptInterface().SetProperty(msg, "meanRTT", meanRTT); 219 PushGuiMessage(msg); 220 } 175 221 } 176 222 177 223 void CNetClient::Flush() 178 224 { 179 225 if (m_Session) … … bool CNetClient::OnKicked(void *context, 625 671 client->PushGuiMessage(msg); 626 672 627 673 return true; 628 674 } 629 675 676 bool CNetClient::OnClientTimeout(void *context, CFsmEvent* event) 677 { 678 // Report the timeout of some other client 679 680 ENSURE(event->GetType() == (uint)NMT_CLIENT_TIMEOUT); 681 682 CNetClient* client = (CNetClient*)context; 683 JSContext* cx = client->GetScriptInterface().GetContext(); 684 685 if (client->GetCurrState() == NCS_LOADING) 686 return true; 687 688 CClientTimeoutMessage* message = (CClientTimeoutMessage*)event->GetParamRef(); 689 JS::RootedValue msg(cx); 690 691 client->GetScriptInterface().Eval("({ 'type':'netwarn', 'warntype': 'client-timeout' })", &msg); 692 client->GetScriptInterface().SetProperty(msg, "guid", std::string(message->m_GUID)); 693 client->GetScriptInterface().SetProperty(msg, "lastReceivedTime", message->m_LastReceivedTime); 694 client->PushGuiMessage(msg); 695 696 return true; 697 } 698 699 bool CNetClient::OnClientPerformance(void *context, CFsmEvent* event) 700 { 701 // Performance statistics for one or multiple clients 702 703 ENSURE(event->GetType() == (uint)NMT_CLIENT_PERFORMANCE); 704 705 CNetClient* client = (CNetClient*)context; 706 JSContext* cx = client->GetScriptInterface().GetContext(); 707 708 if (client->GetCurrState() == NCS_LOADING) 709 return true; 710 711 CClientPerformanceMessage* message = (CClientPerformanceMessage*)event->GetParamRef(); 712 std::vector<CClientPerformanceMessage::S_m_Clients> &clients = message->m_Clients; 713 714 // Display warnings for other clients with bad ping 715 for (size_t i = 0; i < clients.size(); ++i) 716 { 717 u32 meanRTT = clients[i].m_MeanRTT; 718 719 if (meanRTT < DEFAULT_TURN_LENGTH_MP * NETWORK_WARNING_LATENCY || clients[i].m_GUID == client->m_GUID) 720 continue; 721 722 JS::RootedValue msg(cx); 723 client->GetScriptInterface().Eval("({ 'type':'netwarn', 'warntype': 'client-latency' })", &msg); 724 client->GetScriptInterface().SetProperty(msg, "guid", clients[i].m_GUID); 725 client->GetScriptInterface().SetProperty(msg, "meanRTT", meanRTT); 726 client->PushGuiMessage(msg); 727 } 728 729 return true; 730 } 731 630 732 bool CNetClient::OnLoadedGame(void* context, CFsmEvent* event) 631 733 { 632 734 ENSURE(event->GetType() == (uint)NMT_LOADED_GAME); 633 735 634 736 CNetClient* client = (CNetClient*)context; -
source/network/NetClient.h
1 /* Copyright (C) 201 5Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 5 * it under the terms of the GNU General Public License as published by 6 6 * the Free Software Foundation, either version 2 of the License, or … … public: 107 107 * This must be called frequently (i.e. once per frame). 108 108 */ 109 109 void Poll(); 110 110 111 111 /** 112 * Locally triggers a GUI message if the connection to the server is being lost or has bad latency. 113 */ 114 void CheckServerConnection(); 115 116 /** 112 117 * Flush any queued outgoing network messages. 113 118 * This should be called soon after sending a group of messages that may be batched together. 114 119 */ 115 120 void Flush(); 116 121 … … private: 200 205 static bool OnGameStart(void* context, CFsmEvent* event); 201 206 static bool OnJoinSyncStart(void* context, CFsmEvent* event); 202 207 static bool OnJoinSyncEndCommandBatch(void* context, CFsmEvent* event); 203 208 static bool OnRejoined(void* context, CFsmEvent* event); 204 209 static bool OnKicked(void* context, CFsmEvent* event); 210 static bool OnClientTimeout(void* context, CFsmEvent* event); 211 static bool OnClientPerformance(void* context, CFsmEvent* event); 205 212 static bool OnLoadedGame(void* context, CFsmEvent* event); 206 213 207 214 /** 208 215 * Take ownership of a session object, and use it for all network communication. 209 216 */ … … private: 238 245 /// Queue of messages for GuiPoll 239 246 std::deque<JS::Heap<JS::Value> > m_GuiMessageQueue; 240 247 241 248 /// Serialized game state received when joining an in-progress game 242 249 std::string m_JoinSyncBuffer; 250 251 /// Time when the server was last checked for timeout 252 std::time_t m_LastConnectionCheck; 243 253 }; 244 254 245 255 /// Global network client for the standard game 246 256 extern CNetClient *g_NetClient; 247 257 -
source/network/NetMessage.cpp
1 /* Copyright (C) 201 5Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 5 * it under the terms of the GNU General Public License as published by 6 6 * the Free Software Foundation, either version 2 of the License, or … … CNetMessage* CNetMessageFactory::CreateM 137 137 138 138 case NMT_KICKED: 139 139 pNewMessage = new CKickedMessage; 140 140 break; 141 141 142 case NMT_CLIENT_TIMEOUT: 143 pNewMessage = new CClientTimeoutMessage; 144 break; 145 146 case NMT_CLIENT_PERFORMANCE: 147 pNewMessage = new CClientPerformanceMessage; 148 break; 149 142 150 case NMT_LOADED_GAME: 143 151 pNewMessage = new CLoadedGameMessage; 144 152 break; 145 153 146 154 case NMT_SERVER_HANDSHAKE: -
source/network/NetMessages.h
1 /* Copyright (C) 201 5Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 5 * it under the terms of the GNU General Public License as published by 6 6 * the Free Software Foundation, either version 2 of the License, or … … 26 26 #include "ps/CStr.h" 27 27 #include "scriptinterface/ScriptVal.h" 28 28 29 29 #define PS_PROTOCOL_MAGIC 0x5073013f // 'P', 's', 0x01, '?' 30 30 #define PS_PROTOCOL_MAGIC_RESPONSE 0x50630121 // 'P', 'c', 0x01, '!' 31 #define PS_PROTOCOL_VERSION 0x0101000 8// Arbitrary protocol31 #define PS_PROTOCOL_VERSION 0x01010009 // Arbitrary protocol 32 32 #define PS_DEFAULT_PORT 0x5073 // 'P', 's' 33 33 34 34 // Defines the list of message types. The order of the list must not change. 35 35 // The message types having a negative value are used internally and not sent 36 36 // over the network. The message types used for network communication have … … enum NetMessageType 58 58 NMT_JOIN_SYNC_START, 59 59 60 60 NMT_REJOINED, 61 61 NMT_KICKED, 62 62 63 NMT_CLIENT_TIMEOUT, 64 NMT_CLIENT_PERFORMANCE, 65 63 66 NMT_LOADED_GAME, 64 67 NMT_GAME_START, 65 68 NMT_END_COMMAND_BATCH, 66 69 NMT_SYNC_CHECK, // OOS-detection hash checking 67 70 NMT_SYNC_ERROR, // OOS-detection error … … END_NMT_CLASS() 165 168 START_NMT_CLASS_(Kicked, NMT_KICKED) 166 169 NMT_FIELD(CStrW, m_Name) 167 170 NMT_FIELD_INT(m_Ban, u8, 1) 168 171 END_NMT_CLASS() 169 172 173 START_NMT_CLASS_(ClientTimeout, NMT_CLIENT_TIMEOUT) 174 NMT_FIELD(CStr8, m_GUID) 175 NMT_FIELD_INT(m_LastReceivedTime, u32, 4) 176 END_NMT_CLASS() 177 178 START_NMT_CLASS_(ClientPerformance, NMT_CLIENT_PERFORMANCE) 179 NMT_START_ARRAY(m_Clients) 180 NMT_FIELD(CStr8, m_GUID) 181 NMT_FIELD_INT(m_MeanRTT, u32, 4) 182 NMT_END_ARRAY() 183 END_NMT_CLASS() 184 170 185 START_NMT_CLASS_(LoadedGame, NMT_LOADED_GAME) 171 186 NMT_FIELD_INT(m_CurrentTurn, u32, 4) 172 187 END_NMT_CLASS() 173 188 174 189 START_NMT_CLASS_(GameStart, NMT_GAME_START) -
source/network/NetServer.cpp
private: 119 119 120 120 CNetServerWorker::CNetServerWorker(int autostartPlayers) : 121 121 m_AutostartPlayers(autostartPlayers), 122 122 m_Shutdown(false), 123 123 m_ScriptInterface(NULL), 124 m_NextHostID(1), m_Host(NULL), m_HostGUID(), m_Stats(NULL) 124 m_NextHostID(1), m_Host(NULL), m_HostGUID(), m_Stats(NULL), 125 m_LastConnectionCheck(0) 125 126 { 126 127 m_State = SERVER_STATE_UNCONNECTED; 127 128 128 129 m_ServerTurnManager = NULL; 129 130 … … bool CNetServerWorker::RunStep() 449 450 450 451 // Perform file transfers 451 452 for (size_t i = 0; i < m_Sessions.size(); ++i) 452 453 m_Sessions[i]->GetFileTransferer().Poll(); 453 454 455 CheckClientConnections(); 456 454 457 // Process network events: 455 458 456 459 ENetEvent event; 457 460 int status = enet_host_service(m_Host, &event, HOST_SERVICE_TIMEOUT); 458 461 if (status < 0) … … bool CNetServerWorker::RunStep() 547 550 } 548 551 549 552 return true; 550 553 } 551 554 555 void CNetServerWorker::CheckClientConnections() 556 { 557 if (m_State == SERVER_STATE_LOADING) 558 return; 559 560 // Send messages at most once per second 561 std::time_t now = std::time(nullptr); 562 if (now <= m_LastConnectionCheck) 563 return; 564 565 m_LastConnectionCheck = now; 566 567 for (size_t i = 0; i < m_Sessions.size(); ++i) 568 { 569 u32 lastReceived = m_Sessions[i]->GetLastReceivedTime(); 570 u32 meanRTT = m_Sessions[i]->GetMeanRTT(); 571 572 CNetMessage* message = nullptr; 573 574 // Report if we didn't hear from the client since few seconds 575 if (lastReceived > NETWORK_WARNING_TIMEOUT) 576 { 577 CClientTimeoutMessage* msg = new CClientTimeoutMessage(); 578 msg->m_GUID = m_Sessions[i]->GetGUID(); 579 msg->m_LastReceivedTime = lastReceived; 580 message = msg; 581 } 582 // Report if the client has bad ping 583 else if (meanRTT > DEFAULT_TURN_LENGTH_MP * NETWORK_WARNING_LATENCY) 584 { 585 CClientPerformanceMessage* msg = new CClientPerformanceMessage(); 586 CClientPerformanceMessage::S_m_Clients client; 587 client.m_GUID = m_Sessions[i]->GetGUID(); 588 client.m_MeanRTT = meanRTT; 589 msg->m_Clients.push_back(client); 590 message = msg; 591 } 592 593 // Send to all clients except the affected one 594 // (since that will show the locally triggered warning instead) 595 if (message) 596 for (size_t j = 0; j < m_Sessions.size(); ++j) 597 if (i != j) 598 m_Sessions[j]->SendMessage(message); 599 600 SAFE_DELETE(message); 601 } 602 } 603 552 604 void CNetServerWorker::HandleMessageReceive(const CNetMessage* message, CNetServerSession* session) 553 605 { 554 606 // Handle non-FSM messages first 555 607 Status status = session->GetFileTransferer().HandleMessageReceive(message); 556 608 if (status != INFO::SKIPPED) -
source/network/NetServer.h
1 /* Copyright (C) 201 5Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 5 * it under the terms of the GNU General Public License as published by 6 6 * the Free Software Foundation, either version 2 of the License, or … … private: 279 279 280 280 void ConstructPlayerAssignmentMessage(CPlayerAssignmentMessage& message); 281 281 282 282 void HandleMessageReceive(const CNetMessage* message, CNetServerSession* session); 283 283 284 /** 285 * Send a network warning if the connection to a client is being lost or has bad latency. 286 */ 287 void CheckClientConnections(); 284 288 285 289 /** 286 290 * Internal script context for (de)serializing script messages, 287 291 * and for storing game attributes. 288 292 * (TODO: we shouldn't bother deserializing (except for debug printing of messages), … … private: 329 333 * The latest copy of the simulation state, received from an existing 330 334 * client when a new client has asked to rejoin the game. 331 335 */ 332 336 std::string m_JoinSyncFile; 333 337 338 /** 339 * Time when the clients connections were last checked for timeouts and latency. 340 */ 341 std::time_t m_LastConnectionCheck; 342 334 343 private: 335 344 // Thread-related stuff: 336 345 337 346 #if CONFIG2_MINIUPNPC 338 347 /** -
source/network/NetSession.cpp
23 23 #include "NetStats.h" 24 24 #include "lib/external_libraries/enet.h" 25 25 #include "ps/CLogger.h" 26 26 #include "scriptinterface/ScriptInterface.h" 27 27 28 const u32 NETWORK_WARNING_TIMEOUT = 4000; 29 const float NETWORK_WARNING_LATENCY = 1.1f; 30 28 31 static const int CHANNEL_COUNT = 1; 29 32 30 33 CNetClientSession::CNetClientSession(CNetClient& client) : 31 34 m_Client(client), m_FileTransferer(this), m_Host(NULL), m_Server(NULL), m_Stats(NULL) 32 35 { … … bool CNetClientSession::SendMessage(cons 166 169 ENSURE(m_Host && m_Server); 167 170 168 171 return CNetHost::SendMessage(message, m_Server, "server"); 169 172 } 170 173 174 u32 CNetClientSession::GetLastReceivedTime() const 175 { 176 if (!m_Server) 177 return 0; 178 179 return enet_time_get() - m_Server->lastReceiveTime; 180 } 181 182 u32 CNetClientSession::GetMeanRTT() const 183 { 184 if (!m_Server) 185 return 0; 186 187 return m_Server->roundTripTime; 188 } 189 171 190 172 191 173 192 CNetServerSession::CNetServerSession(CNetServerWorker& server, ENetPeer* peer) : 174 193 m_Server(server), m_FileTransferer(this), m_Peer(peer) 175 194 { … … CStr CNetServerSession::GetIPAddress() c 182 201 LOGMESSAGE("Could not get IP address of a client!"); 183 202 184 203 return ipAddress; 185 204 } 186 205 206 u32 CNetServerSession::GetLastReceivedTime() const 207 { 208 if (!m_Peer) 209 return 0; 210 211 return enet_time_get() - m_Peer->lastReceiveTime; 212 } 213 214 u32 CNetServerSession::GetMeanRTT() const 215 { 216 if (!m_Peer) 217 return 0; 218 219 return m_Peer->roundTripTime; 220 } 221 187 222 void CNetServerSession::Disconnect(u32 reason) 188 223 { 189 224 Update((uint)NMT_CONNECTION_LOST, NULL); 190 225 191 226 enet_peer_disconnect(m_Peer, reason); -
source/network/NetSession.h
1 /* Copyright (C) 201 5Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 5 * it under the terms of the GNU General Public License as published by 6 6 * the Free Software Foundation, either version 2 of the License, or … … 22 22 #include "network/NetFileTransfer.h" 23 23 #include "network/NetHost.h" 24 24 #include "ps/CStr.h" 25 25 #include "scriptinterface/ScriptVal.h" 26 26 27 /** 28 * Report the peer if we didn't receive a packet after this time (milliseconds). 29 */ 30 extern const u32 NETWORK_WARNING_TIMEOUT; 31 32 /** 33 * Report the peer if the mean RTT takes longer than this multiple of a turnlength. 34 */ 35 extern const float NETWORK_WARNING_LATENCY; 36 27 37 class CNetClient; 28 38 class CNetServerWorker; 29 39 30 40 class CNetStatsTable; 31 41 … … public: 81 91 /** 82 92 * Send a message to the server. 83 93 */ 84 94 virtual bool SendMessage(const CNetMessage* message); 85 95 96 /** 97 * Number of milliseconds since the most recent packet of the server was received. 98 */ 99 u32 GetLastReceivedTime() const; 100 101 /** 102 * Average round trip time to the server. 103 */ 104 u32 GetMeanRTT() const; 105 86 106 CNetFileTransferer& GetFileTransferer() { return m_FileTransferer; } 87 107 88 108 private: 89 109 CNetClient& m_Client; 90 110 … … public: 123 143 void SetHostID(u32 id) { m_HostID = id; } 124 144 125 145 CStr GetIPAddress() const; 126 146 127 147 /** 148 * Number of milliseconds since the latest packet of that client was received. 149 */ 150 u32 GetLastReceivedTime() const; 151 152 /** 153 * Average round trip time to the client. 154 */ 155 u32 GetMeanRTT() const; 156 157 /** 128 158 * Sends a disconnection notification to the client, 129 159 * and sends a NMT_CONNECTION_LOST message to the session FSM. 130 160 * The server will receive a disconnection notification after a while. 131 161 * The server will not receive any further messages sent via this session. 132 162 */ -
source/network/NetTurnManager.cpp
36 36 37 37 #include <sstream> 38 38 #include <fstream> 39 39 #include <iomanip> 40 40 41 staticconst int DEFAULT_TURN_LENGTH_MP = 500;42 staticconst int DEFAULT_TURN_LENGTH_SP = 200;41 const int DEFAULT_TURN_LENGTH_MP = 500; 42 const int DEFAULT_TURN_LENGTH_SP = 200; 43 43 44 44 static const int COMMAND_DELAY = 2; 45 45 46 46 #if 0 47 47 #define NETTURN_LOG(args) debug_printf args -
source/network/NetTurnManager.h
1 /* Copyright (C) 201 5Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 5 * it under the terms of the GNU General Public License as published by 6 6 * the Free Software Foundation, either version 2 of the License, or … … 24 24 25 25 #include <list> 26 26 #include <map> 27 27 #include <vector> 28 28 29 extern const int DEFAULT_TURN_LENGTH_MP; 30 extern const int DEFAULT_TURN_LENGTH_SP; 31 29 32 class CNetServerWorker; 30 33 class CNetClient; 31 34 class CSimulationMessage; 32 35 class CSimulation2; 33 36 class IReplayLogger;