SuperTuxKart
Loading...
Searching...
No Matches
network_timer_synchronizer.hpp
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
34{
35private:
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
40public:
42 {
43 m_synchronised.store(false);
44 m_force_set_timer.store(false);
45 }
46 // ------------------------------------------------------------------------
47 bool isSynchronised() const { return m_synchronised.load(); }
48 // ------------------------------------------------------------------------
49 void enableForceSetTimer()
50 {
51 if (m_synchronised.load() == true)
52 return;
53 m_force_set_timer.store(true);
54 }
55 // ------------------------------------------------------------------------
56 void resynchroniseTimer() { m_synchronised.store(false); }
57 // ------------------------------------------------------------------------
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
Definition: network_timer_synchronizer.hpp:34
static STKHost * get()
Returns the instance of STKHost.
Definition: stk_host.hpp:185
static uint64_t getMonoTimeMs()
Returns a time based since the starting of stk (monotonic clock).
Definition: time.hpp:106
Defines an interface to use network low-level functions easily.
Declares the general types that are used by the network.