Advertisement
Guest User

Untitled

a guest
May 10th, 2018
1,412
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.00 KB | None | 0 0
  1. class ClockSyncronizer
  2. {
  3. public:
  4.     void Reset();
  5.     bool AddDelta(float delta_seconds, float reported_error);
  6.     float Delta() const { return delta; }
  7.     float Error() const { return error; }
  8.     float Confidence() const { return confidence; }
  9.  
  10.     void FixDeltaError(float e) { delta += e; }
  11. private:
  12.     rde::vector<float> deltas;
  13.     rde::vector<float> errors;
  14.     float delta = 0;
  15.     float confidence = 0;
  16.     float error = 0;
  17. };
  18.  
  19. class ClockSyncClient
  20. {
  21. public:
  22.     ClockSyncClient() { Reset(); }
  23.     const ClockSyncronizer& Results() const { return m_sync; }
  24.     float Ping()             const { return m_ping; }
  25.     float ConfidenceGoal()   const { return m_threshold; }
  26.  
  27.     void FixDeltaError(float);
  28.  
  29.     bool Complete() const;
  30.  
  31.     void Receive( double time, const TimeRequestMessage& );
  32.     bool Send( double time, NetClient& );
  33.     void Reset();
  34. private:
  35.     ClockSyncronizer m_sync;
  36.     float m_threshold = 1;
  37.     double m_lastSendTime = -1;
  38.     float m_ping = 0;
  39. };
  40. class ClockSyncServer
  41. {
  42. public:
  43.     static void Respond( uint clientIndex, double time, NetServer&, const TimeRequestMessage& );
  44. };
  45.  
  46. //------------------------------------------------------------------------------
  47. //------------------------------------------------------------------------------
  48.  
  49. void ClockSyncClient::Reset()
  50. {
  51.     m_threshold = 0.98f;
  52.     m_lastSendTime = -1;
  53.     m_ping = 0;
  54.     m_sync.Reset();
  55. }
  56.  
  57. void ClockSyncClient::Receive( double time, const TimeRequestMessage& msg )
  58. {
  59.     u64 micros_now = (u64)round(time * 1000 * 1000);
  60.     const TimeRequestMessage::Data& data = msg.GetData();
  61.     eiASSERT( data.your_microseconds < micros_now );
  62.     u64 rtt = micros_now - data.your_microseconds;
  63.     m_ping = (float)(rtt / (1000.0*1000.0));
  64.     u64 server_now = data.my_microseconds + rtt/2;
  65.     s64 delta = (s64)server_now - (s64)micros_now;
  66.     float delta_seconds = delta / (1000.0f*1000.0f);
  67.     float reported_error = ((s64)data.your_guess_error) / (1000.0f*1000.0f);
  68.     if( !m_sync.AddDelta(delta_seconds, reported_error) )
  69.         m_threshold = max( 0.1f, m_threshold - 0.05f );//if it's struggling, drop our confidence goal by 5%, to a minimum of 10% confidence...
  70. }
  71.  
  72. bool ClockSyncClient::Complete() const
  73. {
  74.     return m_sync.Confidence() >= m_threshold;
  75. }
  76.  
  77. void ClockSyncClient::FixDeltaError(float e)
  78. {
  79.     eiASSERT( e > 0 );
  80.     m_sync.FixDeltaError(e);
  81. }
  82.  
  83. bool ClockSyncClient::Send( double time, NetClient& client )
  84. {
  85.     const static float sendInterval = 0.35f;
  86.     if( Complete() || time <= m_lastSendTime + sendInterval )
  87.         return false;
  88.     TimeRequestMessage msg;
  89.     if( client.AllocateMessage( msg ) )
  90.     {
  91.         u64 micros_now = (u64)round(time * 1000 * 1000);
  92.         TimeRequestMessage::Data& data = msg.GetData();
  93.         data.my_microseconds = micros_now;
  94.         data.your_microseconds = micros_now + (u64)(m_sync.Delta()*1000.0*1000.0) + (u64)((m_ping/2)*1000.0*1000.0);
  95.         if( client.SendMessage(msg, NetChannel::UnreliableUnordered) )
  96.             m_lastSendTime = time;
  97.         else
  98.             client.ReleaseMessage(msg);
  99.     }
  100.     return true;
  101. }
  102. //------------------------------------------------------------------------------
  103. void ClockSyncServer::Respond( uint clientIndex, double time, NetServer& server, const TimeRequestMessage& msg )
  104. {
  105.     const TimeRequestMessage::Data& in = msg.GetData();
  106.                        
  107.     TimeRequestMessage response;
  108.     if( server.AllocateMessage(clientIndex, response) )
  109.     {
  110.         TimeRequestMessage::Data& out = response.GetData();
  111.         u64 micros_now = (u64)round(time * 1000 * 1000);
  112.         out.my_microseconds = micros_now;
  113.         out.your_microseconds = in.my_microseconds;
  114.         out.your_guess_error = (s64)micros_now - (s64)in.your_microseconds;
  115.         if( !server.SendMessage(clientIndex, response, NetChannel::UnreliableUnordered) )
  116.             server.ReleaseMessage(clientIndex, response);
  117.     }
  118. }
  119. //------------------------------------------------------------------------------
  120. //------------------------------------------------------------------------------
  121. void ClockSyncronizer::Reset()
  122. {
  123.     deltas.clear();
  124.     errors.clear();
  125.     delta = 0;
  126.     confidence = 0;
  127.     error = 0;
  128. }
  129.  
  130. bool ClockSyncronizer::AddDelta(float delta_seconds, float reported_error)
  131. {
  132.     deltas.push_back(delta_seconds);
  133.     if( Abs(reported_error) < 1 )
  134.         errors.push_back(reported_error);
  135.    
  136.     if( !errors.empty() )
  137.         error = FilteredMean(errors.begin(), errors.end());
  138.    
  139.     std::sort(deltas.begin(), deltas.end());
  140.     float median = Median(deltas.begin(), deltas.end());
  141.     float stdDev = StandardDeviation(deltas.begin(), deltas.end());
  142.  
  143.     double filteredLogSum = 0;
  144.     double filteredSum = 0;
  145.     uint numValidSamples = 0;
  146.     double filteredProduct = 1;
  147.     for( auto& n : deltas )
  148.     {
  149.         if( Abs(n - median) > stdDev )// filter outliers
  150.             continue;
  151.         ++numValidSamples;
  152.         filteredProduct *= abs(n);
  153.         filteredLogSum += log(abs(n));
  154.         filteredSum += n;
  155.     }
  156.     double geometricMean  = Exp(filteredLogSum / numValidSamples)     * SignBit(filteredSum);
  157.     double geometricMean2 = Pow(filteredProduct, 1.0/numValidSamples) * SignBit(filteredSum);
  158.     double linearMean     = filteredSum / numValidSamples;
  159.    
  160.     float delta1 = (float)linearMean;
  161.     float delta2 = (float)geometricMean;
  162.     float delta3 = (float)geometricMean2;
  163.     if( isinf(delta1) ) delta1 = 0;
  164.     if( isinf(delta2) ) delta2 = delta1;
  165.     if( isinf(delta3) ) delta3 = delta2;
  166.     delta = (delta1 + delta2 + delta3)/3.0f;
  167.  
  168.     //magic numbers, ahoy!
  169.     confidence = Saturate(numValidSamples / 10.0f)*0.35f                  //use a decent number of samples to reach a conclusion
  170.                 + Saturate(numValidSamples / (float)deltas.size())*0.35f  //the less outliers the better
  171.                 + (1-Saturate(fabs(error)*100))*0.3f;                     //and below 10ms reported error would be nice
  172.     if( errors.empty() )                                                  //and at least one reported error value recieved
  173.         confidence = 0;
  174.  
  175.     bool onTrack = true;
  176.     if( deltas.size() > 20 ) // if still trying after too many samples, clear the arrays and signal that we're struggling
  177.     {
  178.         deltas.clear();
  179.         errors.clear();
  180.         errors.push_back(error);
  181.         deltas.push_back(delta);
  182.         onTrack = false;
  183.     }
  184.     return onTrack;
  185. }
  186. //------------------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement