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
00029 #include "eLagCompensation.h"
00030
00031 #include "tSysTime.h"
00032
00033 #include "nNetwork.h"
00034 #include "nConfig.h"
00035
00036 #ifdef DEBUG
00037 #define DEBUG_LAG
00038 #endif
00039
00040
00041 static REAL se_maxLagSpeedup=.2;
00042 static REAL se_lagSlowDecayTime=30.0;
00043 static REAL se_lagFastDecayTime=5.0;
00044 static REAL se_lagSlowWeight=.2f;
00045 static REAL se_lagFastWeight=1.0f;
00046
00047 static tSettingItem< REAL > se_maxLagSpeedupConf( "LAG_MAX_SPEEDUP_TIMER", se_maxLagSpeedup );
00048 static tSettingItem< REAL > se_lagSlowDecayTimeConf( "LAG_SLOW_TIME", se_lagSlowDecayTime );
00049 static tSettingItem< REAL > se_lagFastDecayTimeConf( "LAG_FAST_TIME", se_lagFastDecayTime );
00050 static tSettingItem< REAL > se_lagSlowWeightConf( "LAG_SLOW_WEIGHT", se_lagSlowWeight );
00051 static tSettingItem< REAL > se_lagFastWeightConf( "LAG_FAST_WEIGHT", se_lagFastWeight );
00052
00054 class nClientLag
00055 {public:
00056 nClientLag():lagLast_(0), lagSlow_(0), lagFast_(0), smoothLag_(0) {}
00057
00058 REAL SmoothLag(){ return smoothLag_; }
00059
00060 void ReportLag( REAL lag, REAL weight )
00061 {
00062 #ifdef DEBUG
00063 con << "Received message of " << lag << " seconds of lag, weight " << weight << "\n";
00064 #endif
00065
00066
00067 if ( weight > 1 )
00068 lagLast_ = tSysTimeFloat();
00069
00070 REAL slowWeight = weight * se_lagSlowWeight;
00071 slowWeight = slowWeight > 1 ? 1 : slowWeight;
00072 REAL fastWeight = weight * se_lagFastWeight;
00073 fastWeight = fastWeight > 1 ? 1 : fastWeight;
00074
00075 lagFast_ = smoothLag_ + lag * fastWeight;
00076 lagSlow_ = ( smoothLag_ > lagSlow_ ? lagSlow_ : smoothLag_ ) + lag * slowWeight;
00077 }
00078
00079 void Timestep(REAL dt)
00080 {
00081 if ( dt > .5 )
00082 dt = .5;
00083
00084
00085 REAL speedup = se_maxLagSpeedup * dt;
00086 smoothLag_ += speedup;
00087
00088
00089 if ( lagFast_ < lagSlow_ )
00090 lagFast_ = lagSlow_;
00091
00092
00093 if ( smoothLag_ > lagFast_ )
00094 smoothLag_ = lagFast_;
00095
00096
00097 REAL lastLag = tSysTimeFloat() - lagLast_;
00098
00099
00100 if ( lastLag > se_lagSlowDecayTime )
00101 lagSlow_ *= se_lagSlowDecayTime/( se_lagSlowDecayTime + dt );
00102 if ( lastLag > se_lagFastDecayTime )
00103 lagFast_ *= se_lagFastDecayTime/( se_lagFastDecayTime + dt );
00104 }
00105 private:
00106 REAL lagLast_;
00107 REAL lagSlow_;
00108 REAL lagFast_;
00109 REAL smoothLag_;
00110 };
00111
00112 static nClientLag se_clientLag;
00113
00114 static void se_receiveLagMessage( nMessage & m )
00115 {
00116 if ( sn_GetNetState() != nCLIENT )
00117 return;
00118
00119 REAL lag;
00120 m >> lag;
00121
00122 REAL weight;
00123 m >> weight;
00124
00125 se_clientLag.ReportLag( lag, weight );
00126 }
00127
00128 static nDescriptor se_receiveLagMessageDescriptor( 240, se_receiveLagMessage,"lag message" );
00129
00130
00131 static REAL se_lagCredit = .5f;
00132
00133
00134 static REAL se_lagCreditSingle = .1f;
00135
00136
00137 static REAL se_lagCreditSweetSpot = .5f;
00138
00139
00140 static REAL se_lagCreditTime = 600.0f;
00141
00142 static tSettingItem< REAL > se_lagCreditConf( "LAG_CREDIT", se_lagCredit );
00143 static tSettingItem< REAL > se_lagCreditSingleConf( "LAG_CREDIT_SINGLE", se_lagCreditSingle );
00144 static tSettingItem< REAL > se_lagCreditSweetSpotConf( "LAG_SWEET_SPOT", se_lagCreditSweetSpot );
00145 static tSettingItem< REAL > se_lagCreditTimeConf( "LAG_CREDIT_TIME", se_lagCreditTime );
00146
00147
00148 static REAL se_lagThreshold = 0.0f;
00149 static tSettingItem< REAL > se_lagThresholdConf( "LAG_THRESHOLD", se_lagThreshold );
00150
00151
00152 static nVersionFeature se_clientLagCompensation( 14 );
00153
00155 class nServerLag
00156 {
00157 public:
00158 nServerLag()
00159 {
00160 Reset();
00161 }
00162
00163 REAL Ping()
00164 {
00165 return sn_Connections[client_].ping.GetPing();
00166 }
00167
00168 REAL Credit()
00169 {
00170 return se_lagCredit;
00171 }
00172
00173 void Reset()
00174 {
00175 creditUsed_ = se_lagCreditSweetSpot * Credit();
00176 lastTime_ = lastLag_ = tSysTimeFloat();
00177 client_ = 0;
00178 }
00179
00180 void SetClient( int client )
00181 {
00182 tASSERT( 1 <= client && client <= MAXCLIENTS );
00183
00184 client_ = client;
00185 }
00186
00187 void Report( REAL lag )
00188 {
00189
00190 if ( ! se_clientLagCompensation.Supported( client_ ) )
00191 return;
00192
00193
00194 lag = lag > se_lagCreditSingle ? se_lagCreditSingle : lag;
00195
00196
00197 REAL credit = Credit();
00198 if ( credit < EPS )
00199 credit = EPS;
00200 REAL ping = Ping();
00201
00202
00203 double time = tSysTimeFloat();
00204 if ( time - lastLag_ < 4 * ping )
00205 return;
00206 lastLag_ = time;
00207
00208
00209 nMessage * mess = tNEW( nMessage )( se_receiveLagMessageDescriptor );
00210 *mess << lag;
00211
00212
00213 REAL weight = 1;
00214 if ( se_lagCreditSweetSpot > 0 )
00215 {
00216 weight = ( (creditUsed_+2*lag)/credit )/se_lagCreditSweetSpot;
00217 }
00218 *mess << weight;
00219
00220 mess->Send( client_ );
00221 }
00222
00223 REAL CreditLeft()
00224 {
00225 return Credit() - creditUsed_;
00226 }
00227
00228 REAL TakeCredit( REAL lag )
00229 {
00230 lag -= se_lagThreshold;
00231 if ( lag > 0 )
00232 {
00233 #ifdef DEBUG_LAG
00234 REAL lagBefore = lag;
00235 #endif
00236
00237
00238 Balance();
00239
00240
00241 lag = lag > se_lagCreditSingle ? se_lagCreditSingle : lag;
00242
00243
00244 REAL credit = Credit();
00245
00246
00247 if ( se_lagCreditTime < EPS )
00248 se_lagCreditTime = EPS;
00249
00250
00251 double time = tSysTimeFloat();
00252 REAL dt = time - lastTime_;
00253 lastTime_ = time;
00254 creditUsed_ -= dt * credit/se_lagCreditTime;
00255 if ( creditUsed_ < 0 )
00256 creditUsed_ = 0;
00257
00258
00259 REAL creditLeft = credit - creditUsed_;
00260 if ( lag > creditLeft )
00261 lag = creditLeft;
00262 if ( lag < 0 )
00263 lag = 0;
00264
00265
00266 creditUsed_ += lag;
00267
00268 #ifdef DEBUG_LAG
00269 {
00270 if ( lag > lagBefore )
00271 con << "Requesting " << lagBefore << " seconds of lag credit, granting " << lag << ".\n";
00272 else
00273 con << "Granting " << lag << " seconds of lag credit.\n";
00274 }
00275 #endif
00276
00277 lag += se_lagThreshold;
00278
00279 }
00280
00281 return lag;
00282 }
00283
00284 static void Balance();
00285 private:
00286 REAL creditUsed_;
00287 double lastTime_;
00288 double lastLag_;
00289 int client_;
00290 };
00291
00292 nServerLag se_serverLag[MAXCLIENTS+1];
00293
00294
00295 void nServerLag::Balance()
00296 {
00297 int i;
00298
00299
00300 if ( sn_NumUsers() <= 1 )
00301 return;
00302
00303
00304 REAL minCredit = se_lagCredit;
00305 for ( i = MAXCLIENTS; i>0; --i )
00306 {
00307 if ( sn_Connections[i].socket )
00308 {
00309 REAL credit = se_serverLag[i].creditUsed_;
00310 if ( credit < minCredit )
00311 minCredit = credit;
00312 }
00313 }
00314
00315
00316 REAL amnesty = minCredit - se_lagCredit * se_lagCreditSweetSpot;
00317
00318
00319 if ( amnesty > 0 )
00320 for ( i = MAXCLIENTS; i>0; --i )
00321 se_serverLag[i].creditUsed_ -= amnesty;
00322 }
00323
00324
00325 static void login_callback(){
00326 int user = nCallbackLoginLogout::User();
00327 if ( sn_GetNetState() != nSERVER || user == 0 || user > MAXCLIENTS )
00328 return;
00329
00330 se_serverLag[user].Reset();
00331 se_serverLag[user].SetClient(user);
00332 }
00333 static nCallbackLoginLogout nlc(&login_callback);
00334
00335
00336
00337
00338 static REAL se_lagOffsetClient = 0.0f;
00339 static REAL se_lagOffsetServer = 0.0f;
00340
00341 static tSettingItem< REAL > se_lagOffsetClientConf( "LAG_OFFSET_CLIENT", se_lagOffsetClient );
00342 static nSettingItem< REAL > se_lagOffsetServerConf( "LAG_OFFSET_SERVER", se_lagOffsetServer );
00343
00344
00345
00346
00347
00348
00354
00355
00356 void eLag::Report( int client, REAL lag )
00357 {
00358 tVERIFY( 1 <= client && client <= MAXCLIENTS );
00359
00360 se_serverLag[client].Report( lag );
00361 }
00362
00363
00364
00365
00366
00367
00373
00374
00375 REAL eLag::TakeCredit( int client, REAL lag )
00376 {
00377 tVERIFY( 1 <= client && client <= MAXCLIENTS );
00378
00379 return se_serverLag[client].TakeCredit( lag );
00380 }
00381
00382
00383
00384
00385
00386
00387
00392
00393
00394 REAL eLag::Credit( int client )
00395 {
00396
00397 if ( sn_GetNetState() != nSERVER )
00398 return 0;
00399
00400 tVERIFY( 1 <= client && client <= MAXCLIENTS );
00401
00402
00403 REAL credit = se_serverLag[client].CreditLeft();
00404
00405
00406 return credit > se_lagCreditSingle ? se_lagCreditSingle : credit;
00407 }
00408
00409
00410
00411
00412
00413
00417
00418
00419 REAL eLag::Threshold( void )
00420 {
00421 return se_lagThreshold;
00422 }
00423
00424
00425
00426
00427
00428
00432
00433
00434 REAL eLag::Current( void )
00435 {
00436 return se_clientLag.SmoothLag() + se_lagOffsetClient + se_lagOffsetServer;
00437 }
00438
00439
00440
00441
00442
00443
00447
00448
00449 void eLag::Timestep( REAL dt )
00450 {
00451 se_clientLag.Timestep( dt );
00452 }