2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 BFG Edition GPL Source Code
2012-11-28 15:47:07 +00:00
Copyright ( C ) 1993 - 2012 id Software LLC , a ZeniMax Media company .
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ( " Doom 3 BFG Edition Source Code " ) .
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition Source Code is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code . If not , see < http : //www.gnu.org/licenses/>.
In addition , the Doom 3 BFG Edition Source Code is also subject to certain additional terms . You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code . If not , please request a copy in writing from id Software at the address below .
If you have questions concerning this license or the applicable additional terms , you may contact in writing id Software LLC , c / o ZeniMax Media Inc . , Suite 120 , Rockville , Maryland 20850 USA .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# pragma hdrstop
2012-12-22 15:18:19 +00:00
# include "precompiled.h"
2012-11-26 18:58:24 +00:00
# include "sys_lobby.h"
idCVar net_snapshot_send_warntime ( " net_snapshot_send_warntime " , " 500 " , CVAR_INTEGER , " Print warning messages if we take longer than this to send a client a snapshot. " ) ;
idCVar net_queueSnapAcks ( " net_queueSnapAcks " , " 1 " , CVAR_BOOL , " " ) ;
idCVar net_peer_throttle_mode ( " net_peer_throttle_mode " , " 0 " , CVAR_INTEGER , " = 0 off, 1 = enable fixed, 2 = absolute, 3 = both " ) ;
idCVar net_peer_throttle_minSnapSeq ( " net_peer_throttle_minSnapSeq " , " 150 " , CVAR_INTEGER , " Minumum number of snapshot exchanges before throttling can be triggered " ) ;
idCVar net_peer_throttle_bps_peer_threshold_pct ( " net_peer_throttle_bps_peer_threshold_pct " , " 0.60 " , CVAR_FLOAT , " Min reported incoming bps % of sent from host that a peer must maintain before throttling kicks in " ) ;
idCVar net_peer_throttle_bps_host_threshold ( " net_peer_throttle_bps_host_threshold " , " 1024 " , CVAR_FLOAT , " Min outgoing bps of host for bps based throttling to be considered " ) ;
idCVar net_peer_throttle_bps_decay ( " net_peer_throttle_bps_decay " , " 0.25f " , CVAR_FLOAT , " If peer exceeds this number of queued snap deltas, then throttle his effective snap rate " ) ;
idCVar net_peer_throttle_bps_duration ( " net_peer_throttle_bps_duration " , " 3000 " , CVAR_INTEGER , " If peer exceeds this number of queued snap deltas, then throttle his effective snap rate " ) ;
idCVar net_peer_throttle_maxSnapRate ( " net_peer_throttle_maxSnapRate " , " 4 " , CVAR_INTEGER , " Highest factor of server base snapRate that a client can be throttled " ) ;
idCVar net_snap_bw_test_throttle_max_scale ( " net_snap_bw_test_throttle_max_scale " , " 0.80 " , CVAR_FLOAT , " When clamping bandwidth to reported values, scale reported value by this " ) ;
idCVar net_snap_redundant_resend_in_ms ( " net_snap_redundant_resend_in_ms " , " 800 " , CVAR_INTEGER , " Delay between redundantly sending snaps during initial snap exchange " ) ;
idCVar net_min_ping_in_ms ( " net_min_ping_in_ms " , " 1500 " , CVAR_INTEGER , " Ping has to be higher than this before we consider throttling to recover " ) ;
idCVar net_pingIncPercentBeforeRecover ( " net_pingIncPercentBeforeRecover " , " 1.3 " , CVAR_FLOAT , " Percentage change increase of ping before we try to recover " ) ;
idCVar net_maxFailedPingRecoveries ( " net_maxFailedPingRecoveries " , " 10 " , CVAR_INTEGER , " Max failed ping recoveries before we stop trying " ) ;
idCVar net_pingRecoveryThrottleTimeInSeconds ( " net_pingRecoveryThrottleTimeInSeconds " , " 3 " , CVAR_INTEGER , " Throttle snaps for this amount of time in seconds to recover from ping spike " ) ;
idCVar net_peer_timeout_loading ( " net_peer_timeout_loading " , " 90000 " , CVAR_INTEGER , " time in MS to disconnect clients during loading - production only " ) ;
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : UpdateSnaps
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : UpdateSnaps ( )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-26 18:58:24 +00:00
SCOPED_PROFILE_EVENT ( " UpdateSnaps " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
#if 0
uint64 startTimeMicroSec = Sys_Microseconds ( ) ;
# endif
haveSubmittedSnaps = false ;
2012-11-28 15:47:07 +00:00
if ( ! SendCompletedSnaps ( ) )
{
2012-11-26 18:58:24 +00:00
// If we weren't able to send all the submitted snaps, we need to wait till we can.
// We can't start new jobs until they are all sent out.
return ;
}
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
peer_t & peer = peers [ p ] ;
if ( ! peer . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( peer . needToSubmitPendingSnap )
{
2012-11-26 18:58:24 +00:00
// Submit the snap
2012-11-28 15:47:07 +00:00
if ( SubmitPendingSnap ( p ) )
{
2012-11-26 18:58:24 +00:00
peer . needToSubmitPendingSnap = false ; // only clear this if we actually submitted the snap
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
#if 0
uint64 endTimeMicroSec = Sys_Microseconds ( ) ;
2012-11-28 15:47:07 +00:00
if ( endTimeMicroSec - startTimeMicroSec > 200 ) // .2 ms
{
idLib : : Printf ( " NET: UpdateSnaps time in ms: %f \n " , ( float ) ( endTimeMicroSec - startTimeMicroSec ) / 1000.0f ) ;
2012-11-26 18:58:24 +00:00
}
# endif
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SendCompletedSnaps
This function will send send off any previously submitted pending snaps if they are ready
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : SendCompletedSnaps ( )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
bool sentAllSubmitted = true ;
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
peer_t & peer = peers [ p ] ;
if ( ! peer . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( peer . snapProc - > PendingSnapReadyToSend ( ) )
{
2012-11-26 18:58:24 +00:00
// Check to see if there are any snaps that were submitted that need to be sent out
SendCompletedPendingSnap ( p ) ;
}
2012-11-28 15:47:07 +00:00
else if ( IsHost ( ) )
{
NET_VERBOSESNAPSHOT_PRINT_LEVEL ( 7 , va ( " ^8Peer %d pendingSnap not ready to send \n " , p ) ) ;
}
if ( ! peer . IsConnected ( ) ) // peer may have been dropped in "SendCompletedPendingSnap". ugh.
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( peer . snapProc - > PendingSnapReadyToSend ( ) )
{
2012-11-26 18:58:24 +00:00
// If we still have a submitted snap, we know we're not done
sentAllSubmitted = false ;
2012-11-28 15:47:07 +00:00
if ( IsHost ( ) )
{
NET_VERBOSESNAPSHOT_PRINT_LEVEL ( 2 , va ( " ^2Peer %d did not send all submitted snapshots. \n " , p ) ) ;
2012-11-26 18:58:24 +00:00
}
}
}
return sentAllSubmitted ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SendResources
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : SendResources ( int p )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return false ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SubmitPendingSnap
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : SubmitPendingSnap ( int p )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
peer_t & peer = peers [ p ] ;
if ( ! peer . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If the peer doesn't have the latest resource list, send it to him before sending any new snapshots
2012-11-28 15:47:07 +00:00
if ( SendResources ( p ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( ! peer . loaded )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( ! peer . snapProc - > HasPendingSnap ( ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int time = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int timeFromLastSub = time - peer . lastSnapJobTime ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int forceResendTime = session - > GetTitleStorageInt ( " net_snap_redundant_resend_in_ms " , net_snap_redundant_resend_in_ms . GetInteger ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( timeFromLastSub < forceResendTime & & peer . snapProc - > IsBusyConfirmingPartialSnap ( ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
peer . lastSnapJobTime = time ;
2012-11-26 18:58:24 +00:00
assert ( ! peer . snapProc - > PendingSnapReadyToSend ( ) ) ;
// Submit snapshot delta to jobs
peer . snapProc - > SubmitPendingSnap ( p + 1 , objMemory , SNAP_OBJ_JOB_MEMORY , lzwData ) ;
2012-11-28 15:47:07 +00:00
NET_VERBOSESNAPSHOT_PRINT_LEVEL ( 2 , va ( " Submitted snapshot to jobList for peer %d. Since last jobsub: %d \n " , p , timeFromLastSub ) ) ;
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SendCompletedPendingSnap
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : SendCompletedPendingSnap ( int p )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int time = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
peer_t & peer = peers [ p ] ;
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( ! peer . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( peer . snapProc = = NULL | | ! peer . snapProc - > PendingSnapReadyToSend ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If we have a pending snap ready to send, we better have a pending snap
assert ( peer . snapProc - > HasPendingSnap ( ) ) ;
2012-11-28 15:47:07 +00:00
// Get the snap data blob now, even if we don't send it.
2012-11-26 18:58:24 +00:00
// This is somewhat wasteful, but we have to do this to keep the snap job pipe ready to keep doing work
// If we don't do this, this peer will cause other peers to be starved of snapshots, when they may very well be ready to send a snap
byte buffer [ MAX_SNAP_SIZE ] ;
int maxLength = sizeof ( buffer ) - peer . packetProc - > GetReliableDataSize ( ) - 128 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int size = peer . snapProc - > GetPendingSnapDelta ( buffer , maxLength ) ;
2012-11-28 15:47:07 +00:00
if ( ! CanSendMoreData ( p ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Can't send anymore snapshots until all fragments are sent
2012-11-28 15:47:07 +00:00
if ( peer . packetProc - > HasMoreFragments ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If the peer doesn't have the latest resource list, send it to him before sending any new snapshots
2012-11-28 15:47:07 +00:00
if ( SendResources ( p ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int timeFromJobSub = time - peer . lastSnapJobTime ;
int timeFromLastSend = time - peer . lastSnapTime ;
2012-11-28 15:47:07 +00:00
if ( timeFromLastSend > 0 )
{
peer . snapHz = 1000.0f / ( float ) timeFromLastSend ;
}
else
{
2012-11-26 18:58:24 +00:00
peer . snapHz = 0.0f ;
}
2012-11-28 15:47:07 +00:00
if ( net_snapshot_send_warntime . GetInteger ( ) > 0 & & peer . lastSnapTime ! = 0 & & net_snapshot_send_warntime . GetInteger ( ) < timeFromLastSend )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " NET: Took %d ms to send peer %d snapshot \n " , timeFromLastSend , p ) ;
}
2012-11-28 15:47:07 +00:00
if ( peer . throttleSnapsForXSeconds ! = 0 )
{
if ( time < peer . throttleSnapsForXSeconds )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If we were trying to recover ping, see if we succeeded
2012-11-28 15:47:07 +00:00
if ( peer . recoverPing ! = 0 )
{
if ( peer . lastPingRtt > = peer . recoverPing )
{
2012-11-26 18:58:24 +00:00
peer . failedPingRecoveries + + ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
const int peer_throttle_minSnapSeq = session - > GetTitleStorageInt ( " net_peer_throttle_minSnapSeq " , net_peer_throttle_minSnapSeq . GetInteger ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( peer . snapProc - > GetFullSnapBaseSequence ( ) > idSnapshotProcessor : : INITIAL_SNAP_SEQUENCE + peer_throttle_minSnapSeq )
{
2012-11-26 18:58:24 +00:00
// If throttling recovered the ping
int maxRate = common - > GetSnapRate ( ) * session - > GetTitleStorageInt ( " net_peer_throttle_maxSnapRate " , net_peer_throttle_maxSnapRate . GetInteger ( ) ) ;
peer . throttledSnapRate = idMath : : ClampInt ( common - > GetSnapRate ( ) , maxRate , peer . throttledSnapRate + common - > GetSnapRate ( ) ) ;
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
peer . throttleSnapsForXSeconds = 0 ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
peer . lastSnapTime = time ;
2012-11-28 15:47:07 +00:00
if ( size ! = 0 )
{
if ( size > 0 )
{
NET_VERBOSESNAPSHOT_PRINT_LEVEL ( 3 , va ( " NET: (peer %d) Sending snapshot %d delta'd against %d. Since JobSub: %d Since LastSend: %d. Size: %d \n " , p , peer . snapProc - > GetSnapSequence ( ) , peer . snapProc - > GetBaseSequence ( ) , timeFromJobSub , timeFromLastSend , size ) ) ;
ProcessOutgoingMsg ( p , buffer , size , false , 0 ) ;
}
else if ( size < 0 ) // Size < 0 indicates the delta buffer filled up
{
2012-11-26 18:58:24 +00:00
// There used to be code here that would disconnect peers if they were in game and filled up the buffer
// This was causing issues in the playtests we were running (Doom 4 MP) and after some conversation
// determined that it was not needed since a timeout mechanism has been added since
ProcessOutgoingMsg ( p , buffer , - size , false , 0 ) ;
2012-11-28 15:47:07 +00:00
if ( peer . snapProc ! = NULL )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSESNAPSHOT_PRINT ( " NET: (peerNum: %d - name: %s) Resending last snapshot delta %d because his delta list filled up. Since JobSub: %d Since LastSend: %d Delta Size: %d \n " , p , GetPeerName ( p ) , peer . snapProc - > GetSnapSequence ( ) , timeFromJobSub , timeFromLastSend , size ) ;
}
}
2012-11-28 15:47:07 +00:00
}
// We calculate what our outgoing rate was for each sequence, so we can have a relative comparison
2012-11-26 18:58:24 +00:00
// for when the client reports what his downstream was in the same timeframe
2012-11-28 15:47:07 +00:00
if ( IsHost ( ) & & peer . snapProc ! = NULL & & peer . snapProc - > GetSnapSequence ( ) > 0 )
{
2012-11-26 18:58:24 +00:00
//NET_VERBOSE_PRINT("^8 %i Rate: %.2f SnapSeq: %d GetBaseSequence: %d\n", lastAppendedSequence, peer.packetProc->GetOutgoingRateBytes(), peer.snapProc->GetSnapSequence(), peer.snapProc->GetBaseSequence() );
peer . sentBpsHistory [ peer . snapProc - > GetSnapSequence ( ) % MAX_BPS_HISTORY ] = peer . packetProc - > GetOutgoingRateBytes ( ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : CheckPeerThrottle
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : CheckPeerThrottle ( int p )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( ! verify ( p > = 0 & & p < peers . Num ( ) ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
peer_t & peer = peers [ p ] ;
if ( ! peer . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( ! IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( session - > GetTitleStorageInt ( " net_peer_throttle_mode " , net_peer_throttle_mode . GetInteger ( ) ) = = 0 )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( peer . receivedBps < 0.0f )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int time = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
if ( ! AllPeersHaveBaseState ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( verify ( peer . snapProc ! = NULL ) )
{
2012-11-26 18:58:24 +00:00
const int peer_throttle_minSnapSeq = session - > GetTitleStorageInt ( " net_peer_throttle_minSnapSeq " , net_peer_throttle_minSnapSeq . GetInteger ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( peer . snapProc - > GetFullSnapBaseSequence ( ) < = idSnapshotProcessor : : INITIAL_SNAP_SEQUENCE + peer_throttle_minSnapSeq )
{
2012-11-26 18:58:24 +00:00
return ;
2012-11-28 15:47:07 +00:00
}
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// This is bps throttling which compares the sent bytes per second to the reported received bps
float peer_throttle_bps_host_threshold = session - > GetTitleStorageFloat ( " net_peer_throttle_bps_host_threshold " , net_peer_throttle_bps_host_threshold . GetFloat ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( peer_throttle_bps_host_threshold > 0.0f )
{
2012-11-26 18:58:24 +00:00
int deltaT = idMath : : ClampInt ( 0 , 100 , time - peer . receivedThrottleTime ) ;
2012-11-28 15:47:07 +00:00
if ( deltaT > 0 & & peer . receivedThrottleTime > 0 & & peer . receivedBpsIndex > 0 )
{
2012-11-26 18:58:24 +00:00
bool throttled = false ;
float sentBps = peer . sentBpsHistory [ peer . receivedBpsIndex % MAX_BPS_HISTORY ] ;
// Min outgoing rate from server (don't throttle if we are sending < 1k)
2012-11-28 15:47:07 +00:00
if ( sentBps > peer_throttle_bps_host_threshold )
{
2012-11-26 18:58:24 +00:00
float pct = peer . receivedBps / idMath : : ClampFloat ( 0.01f , static_cast < float > ( BANDWIDTH_REPORTING_MAX ) , sentBps ) ; // note the receivedBps is implicitly clamped on client end to 10k/sec
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
/*
static int lastSeq = 0 ;
if ( peer . receivedBpsIndex ! = lastSeq ) {
NET_VERBOSE_PRINT ( " %ssentBpsHistory[%d] = %.2f received: %.2f PCT: %.2f \n " , ( pct > 1.0f ? " ^1 " : " " ) , peer . receivedBpsIndex , sentBps , peer . receivedBps , pct ) ;
}
lastSeq = peer . receivedBpsIndex ;
*/
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Increase throttle time if peer is < % of what we are sending him
2012-11-28 15:47:07 +00:00
if ( pct < session - > GetTitleStorageFloat ( " net_peer_throttle_bps_peer_threshold_pct " , net_peer_throttle_bps_peer_threshold_pct . GetFloat ( ) ) )
{
peer . receivedThrottle + = ( float ) deltaT ;
2012-11-26 18:58:24 +00:00
throttled = true ;
2012-11-28 15:47:07 +00:00
NET_VERBOSE_PRINT ( " NET: throttled... %.2f ....pct %.2f receivedBps %.2f outgoingBps %.2f, peer %i, seq %i \n " , peer . receivedThrottle , pct , peer . receivedBps , sentBps , p , peer . snapProc - > GetFullSnapBaseSequence ( ) ) ;
2012-11-26 18:58:24 +00:00
}
}
2012-11-28 15:47:07 +00:00
if ( ! throttled )
{
2012-11-26 18:58:24 +00:00
float decayRate = session - > GetTitleStorageFloat ( " net_peer_throttle_bps_decay " , net_peer_throttle_bps_decay . GetFloat ( ) ) ;
2012-11-28 15:47:07 +00:00
peer . receivedThrottle = Max < float > ( 0.0f , peer . receivedThrottle - ( ( ( float ) deltaT ) * decayRate ) ) ;
2012-11-26 18:58:24 +00:00
//NET_VERBOSE_PRINT("NET: !throttled... %.2f ....receivedBps %.2f outgoingBps %.2f\n", peer.receivedThrottle, peer.receivedBps, sentBps );
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float duration = session - > GetTitleStorageFloat ( " net_peer_throttle_bps_duration " , net_peer_throttle_bps_duration . GetFloat ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( peer . receivedThrottle > duration )
{
2012-11-26 18:58:24 +00:00
peer . maxSnapBps = peer . receivedBps * session - > GetTitleStorageFloat ( " net_snap_bw_test_throttle_max_scale " , net_snap_bw_test_throttle_max_scale . GetFloat ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int maxRate = common - > GetSnapRate ( ) * session - > GetTitleStorageInt ( " net_peer_throttle_maxSnapRate " , net_peer_throttle_maxSnapRate . GetInteger ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( peer . throttledSnapRate = = 0 )
{
2012-11-26 18:58:24 +00:00
peer . throttledSnapRate = common - > GetSnapRate ( ) * 2 ;
2012-11-28 15:47:07 +00:00
}
else if ( peer . throttledSnapRate < maxRate )
{
2012-11-26 18:58:24 +00:00
peer . throttledSnapRate = idMath : : ClampInt ( common - > GetSnapRate ( ) , maxRate , peer . throttledSnapRate + common - > GetSnapRate ( ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
peer . receivedThrottle = 0.0f ; // Start over, so we don't immediately throttle again
}
}
peer . receivedThrottleTime = time ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : ApplySnapshotDelta
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : ApplySnapshotDelta ( int p , int snapshotNumber )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( ! verify ( p > = 0 & & p < peers . Num ( ) ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
peer_t & peer = peers [ p ] ;
if ( ! peer . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( net_queueSnapAcks . GetBool ( ) & & AllPeersHaveBaseState ( ) )
{
2012-11-26 18:58:24 +00:00
// If we've reached our queue limit, force the oldest one out now
2012-11-28 15:47:07 +00:00
if ( snapDeltaAckQueue . Num ( ) = = snapDeltaAckQueue . Max ( ) )
{
2012-11-26 18:58:24 +00:00
ApplySnapshotDeltaInternal ( snapDeltaAckQueue [ 0 ] . p , snapDeltaAckQueue [ 0 ] . snapshotNumber ) ;
snapDeltaAckQueue . RemoveIndex ( 0 ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Queue up acks, so we can spread them out over frames to lighten the load when they all come in at once
snapDeltaAck_t snapDeltaAck ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
snapDeltaAck . p = p ;
snapDeltaAck . snapshotNumber = snapshotNumber ;
2012-11-28 15:47:07 +00:00
snapDeltaAckQueue . Append ( snapDeltaAck ) ;
}
else
{
2012-11-26 18:58:24 +00:00
ApplySnapshotDeltaInternal ( p , snapshotNumber ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : ApplySnapshotDeltaInternal
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : ApplySnapshotDeltaInternal ( int p , int snapshotNumber )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( ! verify ( p > = 0 & & p < peers . Num ( ) ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
peer_t & peer = peers [ p ] ;
if ( ! peer . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// on the server, player = peer number + 1, this only works as long as we don't support clients joining and leaving during game
// on the client, always 0
bool result = peer . snapProc - > ApplySnapshotDelta ( IsHost ( ) ? p + 1 : 0 , snapshotNumber ) ;
2012-11-28 15:47:07 +00:00
if ( result & & IsHost ( ) & & peer . snapProc - > HasPendingSnap ( ) )
{
2012-11-26 18:58:24 +00:00
// Send more of the pending snap if we have one for this peer.
// The reason we can do this, is because we know more about this peers base state now.
// And since we maxed out the optimal snap delta size, we'll now be able
2012-11-28 15:47:07 +00:00
// to send more data, since we assume we'll get better and better delta compression as
2012-11-26 18:58:24 +00:00
// our version of this peers base state approaches parity with the peers actual state.
// We don't send immediately, since we have to coordinate sending snaps for all peers in same place considering jobs.
peer . needToSubmitPendingSnap = true ;
NET_VERBOSESNAPSHOT_PRINT ( " NET: Sent more unsent snapshot data to peer %d for snapshot %d \n " , p , snapshotNumber ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return result ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SendSnapshotToPeer
= = = = = = = = = = = = = = = = = = = = = = = =
*/
idCVar net_forceDropSnap ( " net_forceDropSnap " , " 0 " , CVAR_BOOL , " wait on snaps " ) ;
2012-11-28 15:47:07 +00:00
void idLobby : : SendSnapshotToPeer ( idSnapShot & ss , int p )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
peer_t & peer = peers [ p ] ;
if ( net_forceDropSnap . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
net_forceDropSnap . SetBool ( false ) ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( peer . pauseSnapshots )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int time = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const int throttleMode = session - > GetTitleStorageInt ( " net_peer_throttle_mode " , net_peer_throttle_mode . GetInteger ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Real peer throttling based on performance
// -We throttle before sending to jobs rather than before sending
2012-11-28 15:47:07 +00:00
if ( ( throttleMode = = 1 | | throttleMode = = 3 ) & & peer . throttledSnapRate > 0 )
{
if ( time - peer . lastSnapJobTime < peer . throttledSnapRate / 1000 ) // fixme /1000
{
2012-11-26 18:58:24 +00:00
// This peer is throttled, skip his snap shot
NET_VERBOSESNAPSHOT_PRINT_LEVEL ( 2 , va ( " NET: Throttling peer %d.Skipping snapshot. Time elapsed: %d peer snap rate: %d \n " , p , ( time - peer . lastSnapJobTime ) , peer . throttledSnapRate ) ) ;
return ;
}
}
2012-11-28 15:47:07 +00:00
if ( throttleMode ! = 0 )
{
2012-11-26 18:58:24 +00:00
DetectSaturation ( p ) ;
}
2012-11-28 15:47:07 +00:00
if ( peer . maxSnapBps > = 0.0f & & ( throttleMode = = 2 | | throttleMode = = 3 ) )
{
if ( peer . packetProc - > GetOutgoingRateBytes ( ) > peer . maxSnapBps )
{
2012-11-26 18:58:24 +00:00
return ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// TrySetPendingSnapshot will try to set the new pending snap.
// TrySetPendingSnapshot won't do anything until the last snap set was fully sent out.
2012-11-28 15:47:07 +00:00
if ( peer . snapProc - > TrySetPendingSnapshot ( ss ) )
{
NET_VERBOSESNAPSHOT_PRINT_LEVEL ( 2 , va ( " ^8Set next pending snapshot peer %d \n " , 0 ) ) ;
2012-11-26 18:58:24 +00:00
peer . numSnapsSent + + ;
2012-11-28 15:47:07 +00:00
idSnapShot * baseState = peers [ p ] . snapProc - > GetBaseState ( ) ;
if ( verify ( baseState ! = NULL ) )
{
2012-11-26 18:58:24 +00:00
baseState - > UpdateExpectedSeq ( peers [ p ] . snapProc - > GetSnapSequence ( ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
else
{
NET_VERBOSESNAPSHOT_PRINT_LEVEL ( 2 , va ( " ^2FAILED Set next pending snapshot peer %d \n " , 0 ) ) ;
}
2012-11-26 18:58:24 +00:00
// We send out the pending snap, which could be the most recent, or an old one that hasn't fully been sent
// We don't send immediately, since we have to coordinate sending snaps for all peers in same place considering jobs.
peer . needToSubmitPendingSnap = true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : AllPeersHaveBaseState
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : AllPeersHaveBaseState ( )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < peers . Num ( ) ; + + i )
{
if ( ! peers [ i ] . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( peers [ i ] . snapProc - > GetFullSnapBaseSequence ( ) < idSnapshotProcessor : : INITIAL_SNAP_SEQUENCE )
{
2012-11-26 18:58:24 +00:00
return false ; // If a client hasn't ack'd his first full snap, then we are still sending base state to someone
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : ThrottleSnapsForXSeconds
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : ThrottleSnapsForXSeconds ( int p , int seconds , bool recoverPing )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( peers [ p ] . throttleSnapsForXSeconds ! = 0 )
{
2012-11-26 18:58:24 +00:00
return ; // Already throttling snaps
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " Throttling peer %i for %i seconds... \n " , p , seconds ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
peers [ p ] . throttleSnapsForXSeconds = Sys_Milliseconds ( ) + seconds * 1000 ;
peers [ p ] . recoverPing = recoverPing ? peers [ p ] . lastPingRtt : 0 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : FirstSnapHasBeenSent
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : FirstSnapHasBeenSent ( int p )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( ! verify ( p > = 0 & & p < peers . Num ( ) ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
peer_t & peer = peers [ p ] ;
if ( peer . numSnapsSent = = 0 )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( peer . snapProc = = NULL )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
idSnapShot * ss = peer . snapProc - > GetPendingSnap ( ) ;
if ( ss = = NULL )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( ss - > NumObjects ( ) = = 0 )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : EnsureAllPeersHaveBaseState
This function ensures all peers that started the match together ( they were in the lobby when it started ) start together .
Join in progress peers will be handled as they join .
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : EnsureAllPeersHaveBaseState ( )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int time = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < peers . Num ( ) ; + + i )
{
if ( ! peers [ i ] . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( ! FirstSnapHasBeenSent ( i ) )
{
2012-11-26 18:58:24 +00:00
continue ; // Must be join in progress peer
}
2012-11-28 15:47:07 +00:00
if ( peers [ i ] . snapProc - > GetFullSnapBaseSequence ( ) < idSnapshotProcessor : : INITIAL_SNAP_SEQUENCE )
{
if ( time - peers [ i ] . lastSnapTime > session - > GetTitleStorageInt ( " net_snap_redundant_resend_in_ms " , net_snap_redundant_resend_in_ms . GetInteger ( ) ) )
{
2012-11-26 18:58:24 +00:00
SendSnapshotToPeer ( * peers [ i ] . snapProc - > GetPendingSnap ( ) , i ) ;
}
return false ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : AllPeersHaveStaleSnapObj
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : AllPeersHaveStaleSnapObj ( int objId )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < peers . Num ( ) ; i + + )
{
if ( ! peers [ i ] . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
idSnapShot * baseState = peers [ i ] . snapProc - > GetBaseState ( ) ;
idSnapShot : : objectState_t * state = baseState - > FindObjectByID ( objId ) ;
if ( state = = NULL | | ! state - > stale )
{
2012-11-26 18:58:24 +00:00
return false ;
}
}
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : AllPeersHaveExpectedSnapObj
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : AllPeersHaveExpectedSnapObj ( int objId )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < peers . Num ( ) ; i + + )
{
if ( ! peers [ i ] . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
idSnapShot * baseState = peers [ i ] . snapProc - > GetBaseState ( ) ;
idSnapShot : : objectState_t * state = baseState - > FindObjectByID ( objId ) ;
if ( state = = NULL )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( state - > expectedSequence = = - 2 )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( state - > expectedSequence > 0 & & peers [ i ] . snapProc - > GetFullSnapBaseSequence ( ) < = state - > expectedSequence )
{
2012-11-26 18:58:24 +00:00
//idLib::Printf("^3Not ready to go stale. obj %d Base: %d expected: %d\n", objId, peers[i].snapProc->GetBaseSequence(), state->expectedSequence );
return false ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : MarkSnapObjDeleted
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : RefreshSnapObj ( int objId )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < peers . Num ( ) ; i + + )
{
if ( ! peers [ i ] . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
idSnapShot * baseState = peers [ i ] . snapProc - > GetBaseState ( ) ;
idSnapShot : : objectState_t * state = baseState - > FindObjectByID ( objId ) ;
if ( state ! = NULL )
{
2012-11-26 18:58:24 +00:00
// Setting to -2 will defer setting the expected sequence until the current snap is ready to send
state - > expectedSequence = - 2 ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : MarkSnapObjDeleted
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : MarkSnapObjDeleted ( int objId )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < peers . Num ( ) ; i + + )
{
if ( ! peers [ i ] . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
idSnapShot * baseState = peers [ i ] . snapProc - > GetBaseState ( ) ;
idSnapShot : : objectState_t * state = baseState - > FindObjectByID ( objId ) ;
if ( state ! = NULL )
{
2012-11-26 18:58:24 +00:00
state - > deleted = true ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : ResetBandwidthStats
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : ResetBandwidthStats ( )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lastSnapBspHistoryUpdateSequence = - 1 ;
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
2012-11-26 18:58:24 +00:00
peers [ p ] . maxSnapBps = - 1.0f ;
peers [ p ] . throttledSnapRate = 0 ;
peers [ p ] . rightBeforeSnapsPing = peers [ p ] . lastPingRtt ;
peers [ p ] . throttleSnapsForXSeconds = 0 ;
peers [ p ] . recoverPing = 0 ;
peers [ p ] . failedPingRecoveries = 0 ;
peers [ p ] . rightBeforeSnapsPing = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : DetectSaturation
See if the ping shot up , which indicates a previously saturated connection
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : DetectSaturation ( int p )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
peer_t & peer = peers [ p ] ;
if ( ! peer . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const float pingIncPercentBeforeThottle = session - > GetTitleStorageFloat ( " net_pingIncPercentBeforeRecover " , net_pingIncPercentBeforeRecover . GetFloat ( ) ) ;
const int pingThreshold = session - > GetTitleStorageInt ( " net_min_ping_in_ms " , net_min_ping_in_ms . GetInteger ( ) ) ;
const int maxFailedPingRecoveries = session - > GetTitleStorageInt ( " net_maxFailedPingRecoveries " , net_maxFailedPingRecoveries . GetInteger ( ) ) ;
const int pingRecoveryThrottleTimeInSeconds = session - > GetTitleStorageInt ( " net_pingRecoveryThrottleTimeInSeconds " , net_pingRecoveryThrottleTimeInSeconds . GetInteger ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( peer . lastPingRtt > peer . rightBeforeSnapsPing * pingIncPercentBeforeThottle & & peer . lastPingRtt > pingThreshold )
{
if ( peer . failedPingRecoveries < maxFailedPingRecoveries )
{
2012-11-26 18:58:24 +00:00
ThrottleSnapsForXSeconds ( p , pingRecoveryThrottleTimeInSeconds , true ) ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : AddSnapObjTemplate
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : AddSnapObjTemplate ( int objID , idBitMsg & msg )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If we are in the middle of a SS read, apply this state to what we
// just deserialized (the obj we just deserialized is a delta from the template object we are adding right now)
2012-11-28 15:47:07 +00:00
if ( localReadSS ! = NULL )
{
2012-11-26 18:58:24 +00:00
localReadSS - > ApplyToExistingState ( objID , msg ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Add the template to the snapshot proc for future snapshot processing
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
if ( ! peers [ p ] . IsConnected ( ) | | peers [ p ] . snapProc = = NULL )
{
2012-11-26 18:58:24 +00:00
continue ;
}
peers [ p ] . snapProc - > AddSnapObjTemplate ( objID , msg ) ;
}
}