void Application::UpdateFrame() { // Don't pump the QEvents to QApplication if we are exiting // also don't process our mainloop frames. if (framework->IsExiting()) return; try { const tick_t frameStartTime = GetCurrentClockTime(); QApplication::processEvents(QEventLoop::AllEvents, 1); QApplication::sendPostedEvents(); framework->ProcessOneFrame(); tick_t timeNow = GetCurrentClockTime(); static tick_t timerFrequency = GetCurrentClockFreq(); double msecsSpentInFrame = (double)(timeNow - frameStartTime) * 1000.0 / timerFrequency; const double msecsPerFrame = 1000.0 / (targetFpsLimit <= 1.0 ? 1000.0 : targetFpsLimit); double msecsPerFrameWhenInactive = 1000.0 / (targetFpsLimitWhenInactive <= 1.0 ? 1000.0 : targetFpsLimitWhenInactive); ///\note Ideally we should sleep 0 msecs when running at a high fps rate, /// but need to avoid QTimer::start() with 0 msecs, since that will cause the timer to immediately fire, /// which can cause the Win32 message loop inside Qt to starve. (Qt keeps spinning the timer.start(0) loop for Tundra mainloop and neglects Win32 API). double msecsToSleep = std::min(std::max(1.0, msecsPerFrame - msecsSpentInFrame), msecsPerFrame); double msecsToSleepWhenInactive = std::min(std::max(1.0, msecsPerFrameWhenInactive - msecsSpentInFrame), msecsPerFrameWhenInactive); // Reduce frame rate when unfocused if (!frameUpdateTimer.isActive()) { if (appActivated || framework->IsHeadless()) frameUpdateTimer.start((int)msecsToSleep); else frameUpdateTimer.start((int)(msecsToSleepWhenInactive)); // Cap FPS when window is inactive } } catch(const std::exception &e) { std::string error("Application::UpdateFrame caught an exception: " + std::string(e.what() ? e.what() : "(null)")); std::cout << error << std::endl; LogError(error); throw; } catch(...) { std::string error("Application::UpdateFrame caught an unknown exception!"); std::cout << error << std::endl; LogError(error); throw; } }
/// Polls the inbound socket until the message queue is empty. Also resends any timed out reliable messages. void NetMessageManager::ProcessMessages() { PROFILE (NetMessageManager_ProcessMessages); if (!connection) return; if (!ResendQueueIsEmpty()) ProcessResendQueue(); // Process network messages for max. 0.1 seconds, to prevent lack of rendering/mainloop execution during heavy processing static const double MAX_PROCESS_TIME = 0.1; boost::timer timer; PROFILE(NetMessageManager_WhilePacketsAvailable); while(connection->PacketsAvailable() && timer.elapsed() < MAX_PROCESS_TIME) { const int cMaxPayload = 2048; std::vector<uint8_t> data(cMaxPayload, 0); int numBytes = connection->ReceiveBytes(&data[0], cMaxPayload); if (numBytes == 0) break; data.resize(numBytes); tick_t now = GetCurrentClockTime(); lastHeardSince = (double)(now - lastHeardSinceTick) / GetCurrentClockFreq() * 1000; lastHeardSinceTick = now; #ifdef PROTOCOL_STRESS_TEST const int numDuplications = 10; const double bitErrorRate = 0.05; for(int i = 0; i < numDuplications; ++i) { #endif HandleInboundBytes(data); #ifdef PROTOCOL_STRESS_TEST FlipBits(data, (int)ceil(data.size() * bitErrorRate)); } #endif } if (!connection->Open()) connection.reset(); // To keep memory footprint down and to defend against memory attacks, keep the list of seen sequence numbers to a fixed size. const size_t cMaxSeqNumMemorySize = 300; while(receivedSequenceNumbers.size() > cMaxSeqNumMemorySize) receivedSequenceNumbers.erase(receivedSequenceNumbers.begin()); // We remove from the front to guarantee the smallest(oldest) are removed first. // Acknowledge all the new accumulated packets that the server sent as reliable. SendPendingACKs(); ManagePingSends(); }
void NetMessageManager::HandleCompletePingCheck(NetInMessage *msg) { msg->ResetReading(); uint8_t id = msg->ReadU8(); std::map<uint8_t, tick_t>::iterator it = pendingPings.find(id); if (it == pendingPings.end()) { std::cout << "Reveiced CompletePingCheck with false ID" << std::endl; return; } tick_t timeNow = GetCurrentClockTime(); lastRoundTripTime = (double)(timeNow - it->second) / GetCurrentClockFreq() * 1000; const float alpha = 3.f/4.f; smoothenedRoundTripTime = smoothenedRoundTripTime * alpha + (1.f - alpha) * lastRoundTripTime; pendingPings.erase(it); }