Index: source/network/NetClient.cpp =================================================================== --- source/network/NetClient.cpp +++ source/network/NetClient.cpp @@ -476,6 +476,8 @@ JS::RootedValue msg(cx); GetScriptInterface().Eval("({'type':'netstatus','status':'waiting_for_players'})", &msg); PushGuiMessage(msg); + // We allowed longer timeouts during loading, so now return them to normal. + m_Session->SetLongTimeout(false); } CLoadedGameMessage loaded; @@ -680,6 +682,9 @@ JSContext* cx = client->GetScriptInterface().GetContext(); JSAutoRequest rq(cx); + // Prevent player drops during loading. + client->m_Session->SetLongTimeout(true); + // Find the player assigned to our GUID int player = -1; if (client->m_PlayerAssignments.find(client->m_GUID) != client->m_PlayerAssignments.end()) @@ -704,6 +709,9 @@ CNetClient* client = (CNetClient*)context; + // Prevent player drops during loading. + client->m_Session->SetLongTimeout(true); + // The server wants us to start downloading the game state from it, so do so client->m_Session->GetFileTransferer().StartTask( shared_ptr(new CNetFileReceiveTask_ClientRejoin(*client)) @@ -879,8 +887,13 @@ // If we have rejoined an in progress game, send the rejoined message to the server. if (client->m_Rejoin) + { client->SendRejoinedMessage(); + // We allowed longer timeouts during loading, so now return them to normal. + client->m_Session->SetLongTimeout(false); + } + return true; } Index: source/network/NetServer.cpp =================================================================== --- source/network/NetServer.cpp +++ source/network/NetServer.cpp @@ -1101,6 +1101,8 @@ ); session->SetNextState(NSS_JOIN_SYNCING); + // Prevent player drops during loading. + session->SetLongTimeout(true); } return true; @@ -1249,6 +1251,9 @@ if (session->GetGUID() == server.m_HostGUID) server.StartGame(); + // Prevent player drops during game loading. + session->SetLongTimeout(true); + return true; } @@ -1280,6 +1285,9 @@ loadedSession->SendMessage(&message); server.Broadcast(&message, { NSS_INGAME }); + // The client has loaded, so no longer needs a long timeout. + loadedSession->SetLongTimeout(false); + return true; } @@ -1356,6 +1364,9 @@ session->SendMessage(&pausedMessage); } + // The client has loaded, so no longer needs a long timeout to prevent drops. + session->SetLongTimeout(false); + return true; } Index: source/network/NetSession.h =================================================================== --- source/network/NetSession.h +++ source/network/NetSession.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -105,6 +105,12 @@ */ u32 GetMeanRTT() const; + /** + * Allows increasing the timeout to prevent drops during an expensive operation, + * and decreasing it back to normal afterwards. + */ + void SetLongTimeout(bool longTimeout); + CNetFileTransferer& GetFileTransferer() { return m_FileTransferer; } private: @@ -182,6 +188,12 @@ void SetLocalClient(bool isLocalClient); /** + * Allows increasing the timeout to prevent drops during an expensive operation, + * and decreasing it back to normal afterwards. + */ + void SetLongTimeout(bool longTimeout); + + /** * Send a message to the client. */ virtual bool SendMessage(const CNetMessage* message); Index: source/network/NetSession.cpp =================================================================== --- source/network/NetSession.cpp +++ source/network/NetSession.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -27,11 +27,21 @@ #include "scriptinterface/ScriptInterface.h" const u32 NETWORK_WARNING_TIMEOUT = 2000; - +const u32 NETWORK_GAMESTART_TIMEOUT = 80000; const u32 MAXIMUM_HOST_TIMEOUT = std::numeric_limits::max(); static const int CHANNEL_COUNT = 1; +void LongTimeout(ENetPeer* peer, bool longTimeout) +{ +#if (ENET_VERSION >= ENET_VERSION_CREATE(1, 3, 4)) + if (longTimeout) + enet_peer_timeout(peer, 0, NETWORK_GAMESTART_TIMEOUT, NETWORK_GAMESTART_TIMEOUT); + else + enet_peer_timeout(peer, 0, 0, 0); +#endif +} + CNetClientSession::CNetClientSession(CNetClient& client) : m_Client(client), m_FileTransferer(this), m_Host(NULL), m_Server(NULL), m_Stats(NULL) { @@ -200,7 +210,10 @@ return m_Server->roundTripTime; } - +void CNetClientSession::SetLongTimeout(bool longTimeout) +{ + LongTimeout(m_Server, longTimeout); +} CNetServerSession::CNetServerSession(CNetServerWorker& server, ENetPeer* peer) : m_Server(server), m_FileTransferer(this), m_Peer(peer) @@ -262,3 +275,11 @@ enet_peer_timeout(m_Peer, 0, MAXIMUM_HOST_TIMEOUT, MAXIMUM_HOST_TIMEOUT); #endif } + +void CNetServerSession::SetLongTimeout(bool longTimeout) +{ + // Don't change the timeout if the client is local, since that is handled by SetLocalClient. + if (m_IsLocalClient) + return; + LongTimeout(m_Peer, longTimeout); +}