1 // 2 // SuperTuxKart - a fun racing game with go-kart 3 // Copyright (C) 2018 SuperTuxKart-Team 4 // 5 // This program is free software; you can redistribute it and/or 6 // modify it under the terms of the GNU General Public License 7 // as published by the Free Software Foundation; either version 3 8 // of the License, or (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with this program; if not, write to the Free Software 17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 #ifndef HEADER_NETWORK_TIMER_SYNCHRONIZER_HPP 20 #define HEADER_NETWORK_TIMER_SYNCHRONIZER_HPP 21 22 #include "network/stk_host.hpp" 23 #include "utils/log.hpp" 24 #include "utils/time.hpp" 25 #include "utils/types.hpp" 26 27 #include <atomic> 28 #include <cstdlib> 29 #include <deque> 30 #include <numeric> 31 #include <tuple> 32 33 class NetworkTimerSynchronizer 34 { 35 private: 36 std::deque<std::tuple<uint32_t, uint64_t, uint64_t> > m_times; 37 38 std::atomic_bool m_synchronised, m_force_set_timer; 39 40 public: NetworkTimerSynchronizer()41 NetworkTimerSynchronizer() 42 { 43 m_synchronised.store(false); 44 m_force_set_timer.store(false); 45 } 46 // ------------------------------------------------------------------------ isSynchronised() const47 bool isSynchronised() const { return m_synchronised.load(); } 48 // ------------------------------------------------------------------------ enableForceSetTimer()49 void enableForceSetTimer() 50 { 51 if (m_synchronised.load() == true) 52 return; 53 m_force_set_timer.store(true); 54 } 55 // ------------------------------------------------------------------------ resynchroniseTimer()56 void resynchroniseTimer() { m_synchronised.store(false); } 57 // ------------------------------------------------------------------------ addAndSetTime(uint32_t ping,uint64_t server_time)58 void addAndSetTime(uint32_t ping, uint64_t server_time) 59 { 60 if (m_synchronised.load() == true) 61 return; 62 63 if (m_force_set_timer.load() == true) 64 { 65 m_force_set_timer.store(false); 66 m_synchronised.store(true); 67 STKHost::get()->setNetworkTimer(server_time + (uint64_t)(ping / 2)); 68 return; 69 } 70 71 const uint64_t cur_time = StkTime::getMonoTimeMs(); 72 // Discard too close time compared to last ping 73 // (due to resend when packet loss) 74 // 10 packets per second as seen in STKHost 75 const uint64_t frequency = (uint64_t)((1.0f / 10.0f) * 1000.0f) / 2; 76 if (!m_times.empty() && 77 cur_time - std::get<2>(m_times.back()) < frequency) 78 return; 79 80 // Take max 20 averaged samples from m_times, the next addAndGetTime 81 // is used to determine that server_time if it's correct, if not 82 // clear half in m_times until it's correct 83 if (m_times.size() >= 20) 84 { 85 uint64_t sum = std::accumulate(m_times.begin(), m_times.end(), 86 (uint64_t)0, [cur_time](const uint64_t previous, 87 const std::tuple<uint32_t, uint64_t, uint64_t>& b)->uint64_t 88 { 89 return previous + (uint64_t)(std::get<0>(b) / 2) + 90 std::get<1>(b) + cur_time - std::get<2>(b); 91 }); 92 const int64_t averaged_time = sum / 20; 93 const int64_t server_time_now = server_time + (uint64_t)(ping / 2); 94 int difference = (int)std::abs(averaged_time - server_time_now); 95 if (std::abs(averaged_time - server_time_now) < 96 UserConfigParams::m_timer_sync_difference_tolerance) 97 { 98 STKHost::get()->setNetworkTimer(averaged_time); 99 m_times.clear(); 100 m_force_set_timer.store(false); 101 m_synchronised.store(true); 102 Log::info("NetworkTimerSynchronizer", "Network " 103 "timer synchronized, difference: %dms", difference); 104 return; 105 } 106 m_times.erase(m_times.begin(), m_times.begin() + 10); 107 } 108 m_times.emplace_back(ping, server_time, cur_time); 109 } 110 }; 111 112 #endif // HEADER_NETWORK_TIMER_SYNCHRONIZER_HPP 113