00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "tMemManager.h"
00029 #include "eTimer.h"
00030 #include "eNetGameObject.h"
00031 #include "nSimulatePing.h"
00032 #include "tRecorder.h"
00033 #include "tMath.h"
00034 #include "tConfiguration.h"
00035 #include "eLagCompensation.h"
00036
00037 eTimer *se_mainGameTimer=NULL;
00038
00039
00040
00041
00042 eTimer::eTimer():nNetObject(), startTimeSmoothedOffset_(0){
00043
00044
00045 speed = 1.0;
00046
00047 Reset(0);
00048
00049 if (se_mainGameTimer)
00050 delete se_mainGameTimer;
00051 se_mainGameTimer=this;
00052 if (sn_GetNetState()==nSERVER)
00053 RequestSync();
00054
00055 averageSpf_.Reset();
00056 averageSpf_.Add(1/60.0,5);
00057
00058 creationSystemTime_ = tSysTimeFloat();
00059 }
00060
00061 eTimer::eTimer(nMessage &m):nNetObject(m), startTimeSmoothedOffset_(0){
00062
00063
00064 speed = 1.0;
00065
00066 Reset(0);
00067
00068 if (se_mainGameTimer)
00069 delete se_mainGameTimer;
00070 se_mainGameTimer=this;
00071
00072 averageSpf_.Reset();
00073 averageSpf_.Add(1/60.0,5);
00074
00075 creationSystemTime_ = tSysTimeFloat();
00076 }
00077
00078 eTimer::~eTimer(){
00079
00080 se_mainGameTimer=NULL;
00081 }
00082
00083
00084 static nVersionFeature se_clientLagCompensation( 14 );
00085
00086
00087 static REAL se_lagOffsetLegacy = 0.0f;
00088 static tSettingItem< REAL > se_lagOffsetLegacyConf( "LAG_OFFSET_LEGACY", se_lagOffsetLegacy );
00089
00090 void eTimer::WriteSync(nMessage &m){
00091 nNetObject::WriteSync(m);
00092 REAL time = Time();
00093
00094 if ( SyncedUser() > 0 && !se_clientLagCompensation.Supported( SyncedUser() ) )
00095 time += se_lagOffsetLegacy;
00096
00097 m << time;
00098 m << speed;
00099
00100
00101
00102 const REAL stopFast = 3;
00103 const REAL maxFast = 3;
00104 if ( time < stopFast )
00105 {
00106 nextSync_ = smoothedSystemTime_ + maxFast/(stopFast+maxFast-time);
00107 }
00108 else
00109 {
00110 nextSync_ = smoothedSystemTime_ + 1;
00111 }
00112 }
00113
00114 static REAL se_timerStartFudge = 0.0;
00115 static tSettingItem<REAL> se_timerStartFudgeConf("TIMER_SYNC_START_FUDGE",se_timerStartFudge);
00116 static REAL se_timerStartFudgeStop = 2.0;
00117 static tSettingItem<REAL> se_timerStartFudgeStopConf("TIMER_SYNC_START_FUDGE_STOP",se_timerStartFudgeStop);
00118
00119 void eTimer::ReadSync(nMessage &m){
00120 nNetObject::ReadSync(m);
00121
00122
00123
00124
00125
00126 REAL remoteStartTimeOffset = 0;
00127 REAL remoteTimeNonQuality = 0;
00128 {
00129
00130 REAL remote_currentTime, remoteSpeed;
00131 m >> remote_currentTime;
00132 m >> remoteSpeed;
00133
00134
00135 if ( fabs( speed - remoteSpeed ) > 10 * EPS )
00136 {
00137 qualityTester_.Timestep( 100 );
00138 startTimeOffset_.Reset();
00139 }
00140
00141 speed = remoteSpeed;
00142
00143
00144 nPingAverager & averager = sn_Connections[m.SenderID()].ping;
00145
00146 REAL ping = averager.GetPing();
00147
00148
00149 REAL real_remoteTime=remote_currentTime+ping*speed*.5;
00150
00151
00152 REAL min_remoteTime=remote_currentTime+ping*speed-
00153 sn_pingCharityServer*.001;
00154
00155 if (real_remoteTime<min_remoteTime)
00156 remote_currentTime=min_remoteTime;
00157 else
00158 remote_currentTime=real_remoteTime;
00159
00160
00161
00162 if ( remote_currentTime < se_timerStartFudgeStop )
00163 {
00164 remote_currentTime += ping * ( se_timerStartFudgeStop - remote_currentTime ) * se_timerStartFudge;
00165 }
00166
00167
00168 remoteTimeNonQuality = averager.GetFastAverager().GetAverageVariance();
00169
00170
00171 remoteStartTimeOffset = smoothedSystemTime_ - startTime_ - remote_currentTime;
00172
00173
00174 if ( remote_currentTime < 0 )
00175 {
00176 qualityTester_.Timestep( .2 );
00177 startTimeOffset_.Timestep( .2 );
00178 }
00179 }
00180
00181
00182 qualityTester_.Add( remoteStartTimeOffset );
00183
00184
00185 remoteTimeNonQuality += 0.00001 + 4 * qualityTester_.GetAverageVariance();
00186
00187
00188 startTimeOffset_.Add( remoteStartTimeOffset, 1/remoteTimeNonQuality );
00189 }
00190
00191 static nNOInitialisator<eTimer> eTimer_init(210,"eTimer");
00192
00193 nDescriptor &eTimer::CreatorDescriptor() const{
00194 return eTimer_init;
00195 }
00196
00197
00198 static bool se_SmoothTime()
00199 {
00200 bool smooth = 0;
00201
00202
00203 char const * section = "SMOOTHTIME";
00204 if ( !tRecorder::PlaybackStrict( section, smooth ) )
00205 {
00206
00207 smooth = !tTimerIsAccurate();
00208 }
00209
00210 tRecorder::Record( section, smooth );
00211
00212 return smooth;
00213 }
00214
00215 REAL eTimer::Time()
00216 {
00217 return ( smoothedSystemTime_ - startTime_ ) - startTimeSmoothedOffset_ + eLag::Current();
00218 }
00219
00220 void eTimer::SyncTime(){
00221
00222 {
00223 double newTime=tSysTimeFloat();
00224
00225 static bool smooth = se_SmoothTime();
00226
00227
00228 if ( !tRecorder::IsRunning() )
00229 {
00230 smooth = !tTimerIsAccurate();
00231 }
00232
00233 if ( !smooth )
00234 {
00235
00236 smoothedSystemTime_ = newTime;
00237 }
00238 else
00239 {
00240
00241 REAL smoothDecay = .2f;
00242 smoothedSystemTime_ = ( smoothedSystemTime_ + smoothDecay * newTime )/( 1 + smoothDecay );
00243 }
00244 }
00245
00246
00247 REAL timeStep=smoothedSystemTime_ - lastTime_;
00248 lastTime_ = smoothedSystemTime_;
00249
00250 #ifdef DEBUG
00251 #ifndef DEDICATED
00252
00253 if (timeStep > .1f && sn_GetNetState() == nSTANDALONE && !tRecorder::IsRunning() )
00254 {
00255 startTime_ += timeStep - .1f;
00256 timeStep = .1f;
00257 }
00258 #endif
00259 #endif
00260
00261
00262 eLag::Timestep( timeStep );
00263
00264
00265 spf_ = timeStep;
00266 if ( timeStep > 0 && speed > 0 )
00267 {
00268 averageSpf_.Add( timeStep );
00269 averageSpf_.Timestep( timeStep );
00270 }
00271
00272
00273 startTimeOffset_.Timestep( timeStep * .1 );
00274 qualityTester_ .Timestep( timeStep * .3 );
00275
00276
00277
00278 startTime_ += ( 1.0 - speed ) * timeStep;
00279
00280
00281 {
00282 REAL startTimeOffset = startTimeOffset_.GetAverage();
00283
00284
00285 REAL deviation = startTimeSmoothedOffset_ - startTimeOffset;
00286 REAL extraSmooth = deviation * deviation / ( startTimeOffset_.GetAverageVariance() + .0001 );
00287
00288
00289 REAL time = Time();
00290 if ( time < 0 )
00291 extraSmooth -= 4 * time;
00292
00293 REAL smooth = timeStep * ( .5 + extraSmooth );
00294 startTimeSmoothedOffset_ = ( startTimeSmoothedOffset_ + startTimeOffset * smooth )/(1 + smooth);
00295
00296 if ( !finite( startTimeSmoothedOffset_ ) )
00297 {
00298
00299 st_Breakpoint();
00300 startTimeSmoothedOffset_ = startTimeOffset;
00301 }
00302 }
00303
00304
00305 if (sn_GetNetState()==nSERVER && smoothedSystemTime_ >= nextSync_ )
00306 {
00307 #ifdef nSIMULATE_PING
00308 RequestSync();
00309 #else
00310 RequestSync(false);
00311 #endif
00312 }
00313 }
00314
00315 void eTimer::Reset(REAL t){
00316 if (sn_GetNetState()!=nCLIENT)
00317 speed=1;
00318
00319
00320 smoothedSystemTime_ = tSysTimeFloat();
00321 startTime_ = smoothedSystemTime_ - t;
00322
00323
00324 startTimeOffset_.Reset();
00325 startTimeOffset_.Add(100,EPS);
00326 startTimeOffset_.Add(-100,EPS);
00327
00328 qualityTester_.Reset();
00329 static const REAL qual = sqrt(1/EPS);
00330 qualityTester_.Add(qual,EPS);
00331 qualityTester_.Add(-qual,EPS);
00332
00333
00334 lastTime_ = nextSync_ = smoothedSystemTime_;
00335 startTimeSmoothedOffset_ = startTimeOffset_.GetAverage();
00336 }
00337
00338 bool eTimer::IsSynced() const
00339 {
00340
00341 if ( smoothedSystemTime_ - creationSystemTime_ > 10 || sn_GetNetState() != nCLIENT )
00342 return true;
00343
00344
00345 bool synced = startTimeOffset_.GetAverageVariance() < .01 &&
00346 fabs( startTimeOffset_.GetAverage() - startTimeSmoothedOffset_ ) < .01;
00347
00348 static char const * section = "TIMER_SYNCED";
00349
00350 if ( tRecorder::IsPlayingBack() ? tRecorder::Playback( section ) : synced )
00351 {
00352 tRecorder::Record( section );
00353
00354
00355 creationSystemTime_ = smoothedSystemTime_ - 11;
00356 return true;
00357 }
00358
00359 return false;
00360 }
00361
00362 void eTimer::pause(bool p){
00363 if (p){
00364 if(speed!=0){
00365 speed=0;
00366 if (sn_GetNetState()==nSERVER)
00367 RequestSync();
00368 }
00369 }
00370 else{
00371 if (speed!=1){
00372 speed=1;
00373
00374
00375 if (sn_GetNetState()==nSERVER)
00376 RequestSync();
00377 }
00378 }
00379 }
00380
00381 REAL se_GameTime(){
00382 if (se_mainGameTimer)
00383 return se_mainGameTimer->Time();
00384 else
00385 return 0;
00386 }
00387 REAL se_GameTimeNoSync(){
00388 if (se_mainGameTimer)
00389 return se_mainGameTimer->TimeNoSync();
00390 else
00391 return 0;
00392 }
00393
00394 void se_SyncGameTimer(){
00395 if (se_mainGameTimer)
00396 se_mainGameTimer->SyncTime();
00397 }
00398
00399 void se_MakeGameTimer(){
00400 tNEW(eTimer);
00401 }
00402
00403 void se_KillGameTimer(){
00404 if (se_mainGameTimer)
00405 delete se_mainGameTimer;
00406 se_mainGameTimer=NULL;
00407 }
00408
00409
00410 void se_ResetGameTimer(REAL t){
00411 if (se_mainGameTimer)
00412 se_mainGameTimer->Reset(t);
00413 }
00414
00415 void se_PauseGameTimer(bool p){
00416 if (se_mainGameTimer && sn_GetNetState()!=nCLIENT)
00417 se_mainGameTimer->pause(p);
00418 }
00419
00420 REAL se_AverageFrameTime(){
00421 return 1/se_AverageFPS();
00422 }
00423
00424 REAL se_AverageFPS(){
00425 if (se_mainGameTimer)
00426 return se_mainGameTimer->AverageFPS();
00427 else
00428 return (.2);
00429 }
00430
00431 REAL se_PredictTime(){
00432 return se_AverageFrameTime()*.5;
00433 }
00434
00435
00436
00437