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"
extern idCVar net_connectTimeoutInSeconds ;
extern idCVar net_headlessServer ;
idCVar net_checkVersion ( " net_checkVersion " , " 0 " , CVAR_INTEGER , " Check for matching version when clients connect. 0: normal rules, 1: force check, otherwise no check (pass always) " ) ;
idCVar net_peerTimeoutInSeconds ( " net_peerTimeoutInSeconds " , " 30 " , CVAR_INTEGER , " If the host hasn't received a response from a peer in this amount of time (in seconds) , the peer will be disconnected . " ) ;
idCVar net_peerTimeoutInSeconds_Lobby ( " net_peerTimeoutInSeconds_Lobby " , " 20 " , CVAR_INTEGER , " If the host hasn't received a response from a peer in this amount of time (in seconds) , the peer will be disconnected . " ) ;
// NOTE - The snapshot exchange does the bandwidth challenge
2012-11-28 15:47:07 +00:00
idCVar net_bw_challenge_enable ( " net_bw_challenge_enable " , " 0 " , CVAR_BOOL , " Enable pre game bandwidth challenge for throttling snap rate " ) ;
2012-11-26 18:58:24 +00:00
idCVar net_bw_test_interval ( " net_bw_test_interval " , " 33 " , CVAR_INTEGER , " MS - how often to send packets in bandwidth test " ) ;
idCVar net_bw_test_numPackets ( " net_bw_test_numPackets " , " 30 " , CVAR_INTEGER , " Number of bandwidth challenge packets to send " ) ;
idCVar net_bw_test_packetSizeBytes ( " net_bw_test_packetSizeBytes " , " 1024 " , CVAR_INTEGER , " Size of each packet to send out " ) ;
idCVar net_bw_test_timeout ( " net_bw_test_timeout " , " 500 " , CVAR_INTEGER , " MS after receiving a bw test packet that client will time out " ) ;
idCVar net_bw_test_host_timeout ( " net_bw_test_host_timeout " , " 3000 " , CVAR_INTEGER , " How long host will wait in MS to hear bw results from peers " ) ;
idCVar net_bw_test_throttle_rate_pct ( " net_bw_test_throttle_rate_pct " , " 0.80 " , CVAR_FLOAT , " Min rate % a peer must match in bandwidth challenge before being throttled. 1.0=perfect, 0.0=received nothing " ) ;
idCVar net_bw_test_throttle_byte_pct ( " net_bw_test_throttle_byte_pct " , " 0.80 " , CVAR_FLOAT , " Min byte % a peer must match in bandwidth challenge before being throttled. 1.0=perfect (received everything) 0.0 = Received nothing " ) ;
idCVar net_bw_test_throttle_seq_pct ( " net_bw_test_throttle_seq_pct " , " 0.80 " , CVAR_FLOAT , " Min sequence % a peer must match in bandwidth test before being throttled. 1.0=perfect. This score will be more adversely affected by packet loss than byte % " ) ;
idCVar net_ignoreConnects ( " net_ignoreConnects " , " 0 " , CVAR_INTEGER , " Test as if no one can connect to me. 0 = off, 1 = ignore with no reply, 2 = send goodbye " ) ;
2012-11-28 15:47:07 +00:00
idCVar net_skipGoodbye ( " net_skipGoodbye " , " 0 " , CVAR_BOOL , " " ) ;
2012-11-26 18:58:24 +00:00
2012-12-12 11:11:55 +00:00
// RB: 64 bit fixes, changed long to int
extern unsigned int NetGetVersionChecksum ( ) ;
// RB end
2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : idLobby
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idLobby : : idLobby ( )
{
2012-11-26 18:58:24 +00:00
lobbyType = TYPE_INVALID ;
sessionCB = NULL ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
localReadSS = NULL ;
objMemory = NULL ;
haveSubmittedSnaps = false ;
2012-11-28 15:47:07 +00:00
state = STATE_IDLE ;
2012-11-26 18:58:24 +00:00
failedReason = FAILED_UNKNOWN ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
host = - 1 ;
peerIndexOnHost = - 1 ;
isHost = false ;
needToDisplayMigrateMsg = false ;
migrateMsgFlags = 0 ;
partyToken = 0 ; // will be initialized later
loaded = false ;
respondToArbitrate = false ;
waitForPartyOk = false ;
startLoadingFromHost = false ;
nextSendPingValuesTime = 0 ;
lastPingValuesRecvTime = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
nextSendMigrationGameTime = 0 ;
nextSendMigrationGamePeer = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bandwidthChallengeStartTime = 0 ;
bandwidthChallengeEndTime = 0 ;
bandwidthChallengeFinished = false ;
bandwidthChallengeNumGoodSeq = 0 ;
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
2012-11-26 18:58:24 +00:00
assert ( userList . Max ( ) = = freeUsers . Max ( ) ) ;
assert ( userList . Max ( ) = = userPool . Max ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
userPool . SetNum ( userPool . Max ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
assert ( freeUsers . Num ( ) = = 0 ) ;
assert ( freeUsers . Num ( ) = = 0 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Initialize free user list
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < userPool . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
freeUsers . Append ( & userPool [ i ] ) ;
}
showHostLeftTheSession = false ;
connectIsFromInvite = false ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : Initialize
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : Initialize ( lobbyType_t sessionType_ , idSessionCallbacks * callbacks )
{
2012-11-26 18:58:24 +00:00
assert ( callbacks ! = NULL ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lobbyType = sessionType_ ;
sessionCB = callbacks ;
2012-11-28 15:47:07 +00:00
if ( lobbyType = = GetActingGameStateLobbyType ( ) )
{
2012-11-26 18:58:24 +00:00
// only needed in multiplayer mode
2012-11-28 15:47:07 +00:00
objMemory = ( uint8 * ) Mem_Alloc ( SNAP_OBJ_JOB_MEMORY , TAG_NETWORKING ) ;
lzwData = ( lzwCompressionData_t * ) Mem_Alloc ( sizeof ( lzwCompressionData_t ) , TAG_NETWORKING ) ;
2012-11-26 18:58:24 +00:00
}
}
//===============================================================================
// ** BEGIN PUBLIC INTERFACE ***
//===============================================================================
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : StartHosting
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : StartHosting ( const idMatchParameters & parms_ )
{
2012-11-26 18:58:24 +00:00
parms = parms_ ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Allow common to modify the parms
common - > OnStartHosting ( parms ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
Shutdown ( ) ; // Make sure we're in a shutdown state before proceeding
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
assert ( GetNumLobbyUsers ( ) = = 0 ) ;
assert ( lobbyBackend = = NULL ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Get the skill level of all the players that will eventually go into the lobby
StartCreating ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : StartFinding
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : StartFinding ( const idMatchParameters & parms_ )
{
2012-11-26 18:58:24 +00:00
parms = parms_ ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
Shutdown ( ) ; // Make sure we're in a shutdown state before proceeding
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
assert ( GetNumLobbyUsers ( ) = = 0 ) ;
assert ( lobbyBackend = = NULL ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Clear search results
searchResults . Clear ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lobbyBackend = sessionCB - > FindLobbyBackend ( parms , sessionCB - > GetPartyLobby ( ) . GetNumLobbyUsers ( ) , sessionCB - > GetPartyLobby ( ) . GetAverageSessionLevel ( ) , idLobbyBackend : : TYPE_GAME ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
SetState ( STATE_SEARCHING ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : Pump
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : Pump ( )
{
2012-11-26 18:58:24 +00:00
// Check the heartbeat of all our peers, make sure we shouldn't disconnect from peers that haven't sent a heartbeat in awhile
CheckHeartBeats ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
UpdateHostMigration ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
UpdateLocalSessionUsers ( ) ;
2012-11-28 15:47:07 +00:00
switch ( state )
{
case STATE_IDLE :
State_Idle ( ) ;
break ;
case STATE_CREATE_LOBBY_BACKEND :
State_Create_Lobby_Backend ( ) ;
break ;
case STATE_SEARCHING :
State_Searching ( ) ;
break ;
case STATE_OBTAINING_ADDRESS :
State_Obtaining_Address ( ) ;
break ;
case STATE_CONNECT_HELLO_WAIT :
State_Connect_Hello_Wait ( ) ;
break ;
case STATE_FINALIZE_CONNECT :
State_Finalize_Connect ( ) ;
break ;
case STATE_FAILED :
break ;
default :
2012-11-26 18:58:24 +00:00
idLib : : Error ( " idLobby::Pump: Unknown state. " ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : ProcessSnapAckQueue
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : ProcessSnapAckQueue ( )
{
2012-11-26 18:58:24 +00:00
SCOPED_PROFILE_EVENT ( " ProcessSnapAckQueue " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const int SNAP_ACKS_TO_PROCESS_PER_FRAME = 1 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int numProcessed = 0 ;
2012-11-28 15:47:07 +00:00
while ( snapDeltaAckQueue . Num ( ) > 0 & & numProcessed < SNAP_ACKS_TO_PROCESS_PER_FRAME )
{
if ( ApplySnapshotDeltaInternal ( snapDeltaAckQueue [ 0 ] . p , snapDeltaAckQueue [ 0 ] . snapshotNumber ) )
{
2012-11-26 18:58:24 +00:00
numProcessed + + ;
}
snapDeltaAckQueue . RemoveIndex ( 0 ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : Shutdown
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : Shutdown ( bool retainMigrationInfo , bool skipGoodbye )
{
2012-11-26 18:58:24 +00:00
// Cancel host migration if we were in the process of it and this is the session type that was migrating
2012-11-28 15:47:07 +00:00
if ( ! retainMigrationInfo & & migrationInfo . state ! = MIGRATE_NONE )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " Cancelling host migration on %s. \n " , GetLobbyName ( ) ) ;
EndMigration ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
failedReason = FAILED_UNKNOWN ;
2012-11-28 15:47:07 +00:00
if ( lobbyBackend = = NULL )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: ShutdownLobby (already shutdown) (%s) \n " , GetLobbyName ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If we don't have this lobbyBackend type, we better be properly shutdown for this lobby
assert ( GetNumLobbyUsers ( ) = = 0 ) ;
assert ( host = = - 1 ) ;
assert ( peerIndexOnHost = = - 1 ) ;
assert ( ! isHost ) ;
assert ( lobbyType ! = GetActingGameStateLobbyType ( ) | | ! loaded ) ;
assert ( lobbyType ! = GetActingGameStateLobbyType ( ) | | ! respondToArbitrate ) ;
assert ( snapDeltaAckQueue . Num ( ) = = 0 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Make sure we don't have old peers connected to this lobby
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
2012-11-26 18:58:24 +00:00
assert ( peers [ p ] . GetConnectionState ( ) = = CONNECTION_FREE ) ;
}
2012-11-28 15:47:07 +00:00
state = STATE_IDLE ;
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
NET_VERBOSE_PRINT ( " NET: ShutdownLobby (%s) \n " , GetLobbyName ( ) ) ;
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
if ( peers [ p ] . GetConnectionState ( ) ! = CONNECTION_FREE )
{
2012-11-26 18:58:24 +00:00
SetPeerConnectionState ( p , CONNECTION_FREE , skipGoodbye ) ; // This will send goodbye's
}
}
// Remove any users that weren't handled in ResetPeers
// (this will happen as a client, because we won't get the reliable msg from the server since we are severing the connection)
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < GetNumLobbyUsers ( ) ; i + + )
{
lobbyUser_t * user = GetLobbyUser ( i ) ;
2012-11-26 18:58:24 +00:00
UnregisterUser ( user ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
FreeAllUsers ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
host = - 1 ;
peerIndexOnHost = - 1 ;
isHost = false ;
needToDisplayMigrateMsg = false ;
migrationDlg = GDM_INVALID ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
partyToken = 0 ; // Reset our party token so we recompute
loaded = false ;
respondToArbitrate = false ;
waitForPartyOk = false ;
startLoadingFromHost = false ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
snapDeltaAckQueue . Clear ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Shutdown the lobbyBackend
2012-11-28 15:47:07 +00:00
if ( ! retainMigrationInfo )
{
2012-11-26 18:58:24 +00:00
sessionCB - > DestroyLobbyBackend ( lobbyBackend ) ;
lobbyBackend = NULL ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
state = STATE_IDLE ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : HandlePacket
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : HandlePacket ( lobbyAddress_t & remoteAddress , idBitMsg fragMsg , idPacketProcessor : : sessionId_t sessionID )
{
2012-11-26 18:58:24 +00:00
SCOPED_PROFILE_EVENT ( " HandlePacket " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// msg will hold a fully constructed msg using the packet processor
byte msgBuffer [ idPacketProcessor : : MAX_MSG_SIZE ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idBitMsg msg ;
msg . InitWrite ( msgBuffer , sizeof ( msgBuffer ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int peerNum = FindPeer ( remoteAddress , sessionID ) ;
int type = idPacketProcessor : : RETURN_TYPE_NONE ;
int userData = 0 ;
2012-11-28 15:47:07 +00:00
if ( peerNum > = 0 )
{
if ( ! peers [ peerNum ] . IsActive ( ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " NET: Received in-band packet from peer %s with no active connection. \n " , remoteAddress . ToString ( ) ) ;
return ;
}
type = peers [ peerNum ] . packetProc - > ProcessIncoming ( Sys_Milliseconds ( ) , peers [ peerNum ] . sessionID , fragMsg , msg , userData , peerNum ) ;
2012-11-28 15:47:07 +00:00
}
else
{
if ( ! idPacketProcessor : : ProcessConnectionlessIncoming ( fragMsg , msg , userData ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " ProcessConnectionlessIncoming FAILED from %s. \n " , remoteAddress . ToString ( ) ) ;
// Not a valid connectionless packet
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Valid connectionless packets are always RETURN_TYPE_OOB
type = idPacketProcessor : : RETURN_TYPE_OOB ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Find the peer this connectionless msg should go to
peerNum = FindPeer ( remoteAddress , sessionID , true ) ;
}
2012-11-28 15:47:07 +00:00
if ( type = = idPacketProcessor : : RETURN_TYPE_NONE )
{
2012-11-26 18:58:24 +00:00
// This packet is not necessarily invalid, it could be a start or middle of a fragmented packet that's not fully constructed.
return ;
}
2012-11-28 15:47:07 +00:00
if ( peerNum > = 0 )
{
2012-11-26 18:58:24 +00:00
// Update their heart beat (only if we've received a valid packet (we've checked type == idPacketProcessor::RETURN_TYPE_NONE))
2012-11-28 15:47:07 +00:00
peers [ peerNum ] . lastHeartBeat = Sys_Milliseconds ( ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Handle server query requests. We do this before the STATE_IDLE check. This is so we respond.
// We may want to change this to just ignore the request if we are idle, and change the timeout time
// on the requesters part to just timeout faster.
2012-11-28 15:47:07 +00:00
if ( type = = idPacketProcessor : : RETURN_TYPE_OOB )
{
if ( userData = = OOB_MATCH_QUERY | | userData = = OOB_SYSTEMLINK_QUERY )
{
2012-11-26 18:58:24 +00:00
sessionCB - > HandleServerQueryRequest ( remoteAddress , msg , userData ) ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( userData = = OOB_MATCH_QUERY_ACK )
{
2012-11-26 18:58:24 +00:00
sessionCB - > HandleServerQueryAck ( remoteAddress , msg ) ;
return ;
}
2012-11-28 15:47:07 +00:00
}
if ( type = = idPacketProcessor : : RETURN_TYPE_OOB )
{
if ( userData = = OOB_VOICE_AUDIO )
{
2012-11-26 18:58:24 +00:00
sessionCB - > HandleOobVoiceAudio ( remoteAddress , msg ) ;
2012-11-28 15:47:07 +00:00
}
else if ( userData = = OOB_HELLO )
{
2012-11-26 18:58:24 +00:00
// Handle new peer connect request
peerNum = HandleInitialPeerConnection ( msg , remoteAddress , peerNum ) ;
return ;
2012-11-28 15:47:07 +00:00
}
else if ( userData = = OOB_MIGRATE_INVITE )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Migration invite for session %s from %s (state = %s) \n " , GetLobbyName ( ) , remoteAddress . ToString ( ) , session - > GetStateString ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Get connection info
lobbyConnectInfo_t connectInfo ;
connectInfo . ReadFromMsg ( msg ) ;
2012-11-28 15:47:07 +00:00
if ( lobbyBackend ! = NULL & & lobbyBackend - > GetState ( ) ! = idLobbyBackend : : STATE_FAILED & & lobbyBackend - > IsOwnerOfConnectInfo ( connectInfo ) ) // Ignore duplicate invites
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " NET: Already migrated to %s. \n " , remoteAddress . ToString ( ) ) ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( migrationInfo . state = = MIGRATE_NONE )
{
if ( IsPeer ( ) & & host > = 0 & & host < peers . Num ( ) & & Sys_Milliseconds ( ) - peers [ host ] . lastHeartBeat > 8 * 1000 )
{
2012-11-26 18:58:24 +00:00
// Force migration early if we get an invite, and it has been some time since we've heard from the host
PickNewHost ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " NET: Ignoring migration invite because we are not migrating %s \n " , remoteAddress . ToString ( ) ) ;
SendGoodbye ( remoteAddress ) ; // So they can remove us from their invite list
return ;
}
}
2012-11-28 15:47:07 +00:00
if ( ! sessionCB - > PreMigrateInvite ( * this ) )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: sessionCB->PreMigrateInvite( *this ) failed from %s \n " , remoteAddress . ToString ( ) ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If we are also becoming a new host, see who wins
2012-11-28 15:47:07 +00:00
if ( migrationInfo . state = = MIGRATE_BECOMING_HOST )
{
2012-11-26 18:58:24 +00:00
int inviteIndex = FindMigrationInviteIndex ( remoteAddress ) ;
2012-11-28 15:47:07 +00:00
if ( inviteIndex ! = - 1 )
{
2012-11-26 18:58:24 +00:00
// We found them in our list, check to make sure our ping is better
int ping1 = migrationInfo . ourPingMs ;
lobbyUserID_t userId1 = migrationInfo . ourUserId ;
int ping2 = migrationInfo . invites [ inviteIndex ] . pingMs ;
lobbyUserID_t userId2 = migrationInfo . invites [ inviteIndex ] . userId ;
2012-11-28 15:47:07 +00:00
if ( IsBetterHost ( ping1 , userId1 , ping2 , userId2 ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " NET: Ignoring migration invite from %s, since our ping is better (%i / %i). \n " , remoteAddress . ToString ( ) , ping1 , ping2 ) ;
return ;
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bool fromGame = msg . ReadBool ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Kill the current lobbyBackend
Shutdown ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Connect to the lobby
ConnectTo ( connectInfo , true ) ; // Pass in true for the invite flag, so we can connect to invite only lobby if we need to
2012-11-28 15:47:07 +00:00
if ( verify ( sessionCB ! = NULL ) )
{
if ( sessionCB - > BecomingPeer ( * this ) )
{
2012-11-26 18:58:24 +00:00
migrationInfo . persistUntilGameEndsData . wasMigratedJoin = true ;
migrationInfo . persistUntilGameEndsData . wasMigratedGame = fromGame ;
}
}
2012-11-28 15:47:07 +00:00
}
else if ( userData = = OOB_GOODBYE | | userData = = OOB_GOODBYE_W_PARTY | | userData = = OOB_GOODBYE_FULL )
{
2012-11-26 18:58:24 +00:00
HandleGoodbyeFromPeer ( peerNum , remoteAddress , userData ) ;
return ;
2012-11-28 15:47:07 +00:00
}
else if ( userData = = OOB_RESOURCE_LIST )
{
if ( ! verify ( lobbyType = = GetActingGameStateLobbyType ( ) ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( peerNum ! = host )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Resource list from non-host %i, %s \n " , peerNum , remoteAddress . ToString ( ) ) ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( peerNum > = 0 & & ! peers [ peerNum ] . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Resource list from host with no game connection: %i, %s \n " , peerNum , remoteAddress . ToString ( ) ) ;
return ;
}
2012-11-28 15:47:07 +00:00
}
else if ( userData = = OOB_BANDWIDTH_TEST )
{
2012-11-26 18:58:24 +00:00
int seqNum = msg . ReadLong ( ) ;
// TODO: We should read the random data and verify the MD5 checksum
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int time = Sys_Milliseconds ( ) ;
bool inOrder = ( seqNum = = 0 | | peers [ peerNum ] . bandwidthSequenceNum + 1 = = seqNum ) ;
int timeSinceLast = 0 ;
2012-11-28 15:47:07 +00:00
if ( bandwidthChallengeStartTime < = 0 )
{
2012-11-26 18:58:24 +00:00
// Reset the test
NET_VERBOSE_PRINT ( " \n NET: Starting bandwidth test @ %d \n " , time ) ;
bandwidthChallengeStartTime = time ;
peers [ peerNum ] . bandwidthSequenceNum = 0 ;
peers [ peerNum ] . bandwidthTestBytes = peers [ peerNum ] . packetProc - > GetIncomingBytes ( ) ;
}
2012-11-28 15:47:07 +00:00
else
{
timeSinceLast = time - ( bandwidthChallengeEndTime - session - > GetTitleStorageInt ( " net_bw_test_timeout " , net_bw_test_timeout . GetInteger ( ) ) ) ;
}
if ( inOrder )
{
2012-11-26 18:58:24 +00:00
bandwidthChallengeNumGoodSeq + + ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bandwidthChallengeEndTime = time + session - > GetTitleStorageInt ( " net_bw_test_timeout " , net_bw_test_timeout . GetInteger ( ) ) ;
NET_VERBOSE_PRINT ( " NET: %sRecevied OOB bandwidth test %d delta time: %d incoming rate: %.2f incoming rate 2: %d \n " , inOrder ? " ^2 " : " ^1 " , seqNum , timeSinceLast , peers [ peerNum ] . packetProc - > GetIncomingRateBytes ( ) , peers [ peerNum ] . packetProc - > GetIncomingRate2 ( ) ) ;
peers [ peerNum ] . bandwidthSequenceNum = seqNum ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Unknown oob packet %d from %s (%d) \n " , userData , remoteAddress . ToString ( ) , peerNum ) ;
}
2012-11-28 15:47:07 +00:00
}
else if ( type = = idPacketProcessor : : RETURN_TYPE_INBAND )
{
2012-11-26 18:58:24 +00:00
// Process in-band message
2012-11-28 15:47:07 +00:00
if ( peerNum < 0 )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " NET: In-band message from unknown peer: %s \n " , remoteAddress . ToString ( ) ) ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( ! verify ( peers [ peerNum ] . address . Compare ( remoteAddress ) ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " NET: Peer with wrong address: %i, %s \n " , peerNum , remoteAddress . ToString ( ) ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Handle reliable
int numReliable = peers [ peerNum ] . packetProc - > GetNumReliables ( ) ;
2012-11-28 15:47:07 +00:00
for ( int r = 0 ; r < numReliable ; r + + )
{
2012-11-26 18:58:24 +00:00
// Just in case one of the reliable msg's cause this peer to disconnect
// (this can happen when our party/game host is the same, he quits the game lobby, and sends a reliable msg for us to leave the game)
peerNum = FindPeer ( remoteAddress , sessionID ) ;
2012-11-28 15:47:07 +00:00
if ( peerNum = = - 1 )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " NET: Dropped peer while processing reliable msg's: %i, %s \n " , peerNum , remoteAddress . ToString ( ) ) ;
break ;
}
2012-11-28 15:47:07 +00:00
const byte * reliableData = peers [ peerNum ] . packetProc - > GetReliable ( r ) ;
2012-11-26 18:58:24 +00:00
int reliableSize = peers [ peerNum ] . packetProc - > GetReliableSize ( r ) ;
idBitMsg reliableMsg ( reliableData , reliableSize ) ;
reliableMsg . SetSize ( reliableSize ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
HandleReliableMsg ( peerNum , reliableMsg ) ;
}
2012-11-28 15:47:07 +00:00
if ( peerNum = = - 1 | | ! peers [ peerNum ] . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
// If the peer still has no connection after HandleReliableMsg, then something is wrong.
// (We could have been in CONNECTION_CONNECTING state for this session type, but the first message
// we should receive from the server is the ack, otherwise, something went wrong somewhere)
idLib : : Printf ( " NET: In-band message from host with no active connection: %i, %s \n " , peerNum , remoteAddress . ToString ( ) ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Handle unreliable part (if any)
2012-11-28 15:47:07 +00:00
if ( msg . GetRemainingData ( ) > 0 & & loaded )
{
if ( ! verify ( lobbyType = = GetActingGameStateLobbyType ( ) ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " NET: Snapshot msg for non game session lobby %s \n " , remoteAddress . ToString ( ) ) ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( peerNum = = host )
{
2012-11-26 18:58:24 +00:00
idSnapShot localSnap ;
int sequence = - 1 ;
int baseseq = - 1 ;
bool fullSnap = false ;
localReadSS = & localSnap ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If we are the peer, we assume we only receive snapshot data on the in-band channel
2012-11-28 15:47:07 +00:00
const byte * deltaData = msg . GetReadData ( ) + msg . GetReadCount ( ) ;
2012-11-26 18:58:24 +00:00
int deltaLength = msg . GetRemainingData ( ) ;
2012-11-28 15:47:07 +00:00
if ( peers [ peerNum ] . snapProc - > ReceiveSnapshotDelta ( deltaData , deltaLength , 0 , sequence , baseseq , localSnap , fullSnap ) )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSESNAPSHOT_PRINT_LEVEL ( 2 , va ( " NET: Got %s snapshot %d delta'd against %d. SS Time: %d \n " , ( fullSnap ? " partial " : " full " ) , sequence , baseseq , localSnap . GetTime ( ) ) ) ;
2012-11-28 15:47:07 +00:00
if ( sessionCB - > GetState ( ) ! = idSession : : INGAME & & sequence ! = - 1 )
{
2012-11-26 18:58:24 +00:00
int seq = peers [ peerNum ] . snapProc - > GetLastAppendedSequence ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// When we aren't in the game, we need to send this as reliable msg's, since usercmds won't be taking care of it for us
byte ackbuffer [ 32 ] ;
idBitMsg ackmsg ( ackbuffer , sizeof ( ackbuffer ) ) ;
ackmsg . WriteLong ( seq ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Add incoming BPS for QoS
float incomingBPS = peers [ peerNum ] . receivedBps ;
2012-11-28 15:47:07 +00:00
if ( peers [ peerNum ] . receivedBpsIndex ! = seq )
{
2012-11-26 18:58:24 +00:00
incomingBPS = idMath : : ClampFloat ( 0.0f , static_cast < float > ( idLobby : : BANDWIDTH_REPORTING_MAX ) , peers [ host ] . packetProc - > GetIncomingRateBytes ( ) ) ;
peers [ peerNum ] . receivedBpsIndex = seq ;
peers [ peerNum ] . receivedBps = incomingBPS ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
ackmsg . WriteQuantizedUFloat < idLobby : : BANDWIDTH_REPORTING_MAX , idLobby : : BANDWIDTH_REPORTING_BITS > ( incomingBPS ) ;
QueueReliableMessage ( host , RELIABLE_SNAPSHOT_ACK , ackbuffer , sizeof ( ackbuffer ) ) ;
2012-11-28 15:47:07 +00:00
}
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
if ( fullSnap )
{
2012-11-26 18:58:24 +00:00
sessionCB - > ReceivedFullSnap ( ) ;
common - > NetReceiveSnapshot ( localSnap ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
localReadSS = NULL ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// If we are the host, we assume we only receive usercmds on the inband channel
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int snapNum = 0 ;
uint16 receivedBps_quantized = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
byte usercmdBuffer [ idPacketProcessor : : MAX_FINAL_PACKET_SIZE ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lzwCompressionData_t lzwData ;
idLZWCompressor lzwCompressor ( & lzwData ) ;
2012-11-28 15:47:07 +00:00
lzwCompressor . Start ( const_cast < byte * > ( msg . GetReadData ( ) ) + msg . GetReadCount ( ) , msg . GetRemainingData ( ) ) ;
2012-11-26 18:58:24 +00:00
lzwCompressor . ReadAgnostic ( snapNum ) ;
lzwCompressor . ReadAgnostic ( receivedBps_quantized ) ;
int usercmdSize = lzwCompressor . Read ( usercmdBuffer , sizeof ( usercmdBuffer ) , true ) ;
lzwCompressor . End ( ) ;
2012-11-28 15:47:07 +00:00
float receivedBps = ( receivedBps_quantized / ( float ) ( BIT ( idLobby : : BANDWIDTH_REPORTING_BITS ) - 1 ) ) * ( float ) idLobby : : BANDWIDTH_REPORTING_MAX ;
if ( peers [ peerNum ] . receivedBpsIndex ! = snapNum )
{
2012-11-26 18:58:24 +00:00
peers [ peerNum ] . receivedBps = receivedBps ;
peers [ peerNum ] . receivedBpsIndex = snapNum ;
}
2012-11-28 15:47:07 +00:00
if ( snapNum < 50 )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: peer %d ack'd snapNum %d \n " , peerNum , snapNum ) ;
}
ApplySnapshotDelta ( peerNum , snapNum ) ;
2012-11-28 15:47:07 +00:00
idBitMsg usercmdMsg ( ( const byte * ) usercmdBuffer , usercmdSize ) ;
2012-11-26 18:58:24 +00:00
common - > NetReceiveUsercmds ( peerNum , usercmdMsg ) ;
}
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : HasActivePeers
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : HasActivePeers ( ) const
{
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
if ( peers [ p ] . GetConnectionState ( ) ! = CONNECTION_FREE )
{
2012-11-26 18:58:24 +00:00
return true ;
}
}
return false ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : NumFreeSlots
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : NumFreeSlots ( ) const
{
if ( parms . matchFlags & MATCH_JOIN_IN_PROGRESS )
{
2012-11-26 18:58:24 +00:00
return parms . numSlots - GetNumConnectedUsers ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
return parms . numSlots - GetNumLobbyUsers ( ) ;
}
}
//===============================================================================
// ** END PUBLIC INTERFACE ***
//===============================================================================
//===============================================================================
// ** BEGIN STATE CODE ***
//===============================================================================
2012-11-28 15:47:07 +00:00
const char * idLobby : : stateToString [ NUM_STATES ] =
{
2012-11-26 18:58:24 +00:00
ASSERT_ENUM_STRING ( STATE_IDLE , 0 ) ,
ASSERT_ENUM_STRING ( STATE_CREATE_LOBBY_BACKEND , 1 ) ,
ASSERT_ENUM_STRING ( STATE_SEARCHING , 2 ) ,
ASSERT_ENUM_STRING ( STATE_OBTAINING_ADDRESS , 3 ) ,
ASSERT_ENUM_STRING ( STATE_CONNECT_HELLO_WAIT , 4 ) ,
ASSERT_ENUM_STRING ( STATE_FINALIZE_CONNECT , 5 ) ,
ASSERT_ENUM_STRING ( STATE_FAILED , 6 ) ,
} ;
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : State_Idle
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : State_Idle ( )
{
2012-11-26 18:58:24 +00:00
// If lobbyBackend is in a failed state, shutdown, go to a failed state ourself, and return
2012-11-28 15:47:07 +00:00
if ( lobbyBackend ! = NULL & & lobbyBackend - > GetState ( ) = = idLobbyBackend : : STATE_FAILED )
{
2012-11-26 18:58:24 +00:00
HandleConnectionAttemptFailed ( ) ;
common - > Dialog ( ) . ClearDialog ( GDM_MIGRATING ) ;
common - > Dialog ( ) . ClearDialog ( GDM_MIGRATING_WAITING ) ;
common - > Dialog ( ) . ClearDialog ( GDM_MIGRATING_RELAUNCHING ) ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( migrationInfo . persistUntilGameEndsData . hasGameData & & sessionCB - > GetState ( ) < = idSession : : IDLE )
{
2012-11-26 18:58:24 +00:00
// This can happen with 'leaveGame' or 'disconnect' since those paths don't go through endMatch
// This seems like an ok catch all place but there may be a better way to handle this
ResetAllMigrationState ( ) ;
common - > Dialog ( ) . ClearDialog ( GDM_MIGRATING ) ;
common - > Dialog ( ) . ClearDialog ( GDM_MIGRATING_WAITING ) ;
common - > Dialog ( ) . ClearDialog ( GDM_MIGRATING_RELAUNCHING ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : State_Create_Lobby_Backend
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : State_Create_Lobby_Backend ( )
{
if ( ! verify ( lobbyBackend ! = NULL ) )
{
2012-11-26 18:58:24 +00:00
SetState ( STATE_FAILED ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
assert ( lobbyBackend ! = NULL ) ;
2012-11-28 15:47:07 +00:00
if ( migrationInfo . state = = MIGRATE_BECOMING_HOST )
{
2012-11-26 18:58:24 +00:00
const int DETECT_SERVICE_DISCONNECT_TIMEOUT_IN_SECONDS = session - > GetTitleStorageInt ( " DETECT_SERVICE_DISCONNECT_TIMEOUT_IN_SECONDS " , 30 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If we are taking too long, cancel the connection
2012-11-28 15:47:07 +00:00
if ( DETECT_SERVICE_DISCONNECT_TIMEOUT_IN_SECONDS > 0 )
{
if ( Sys_Milliseconds ( ) - migrationInfo . migrationStartTime > 1000 * DETECT_SERVICE_DISCONNECT_TIMEOUT_IN_SECONDS )
{
2012-11-26 18:58:24 +00:00
SetState ( STATE_FAILED ) ;
return ;
}
}
}
2012-11-28 15:47:07 +00:00
if ( lobbyBackend - > GetState ( ) = = idLobbyBackend : : STATE_CREATING )
{
2012-11-26 18:58:24 +00:00
return ; // Busy but valid
}
2012-11-28 15:47:07 +00:00
if ( lobbyBackend - > GetState ( ) ! = idLobbyBackend : : STATE_READY )
{
2012-11-26 18:58:24 +00:00
SetState ( STATE_FAILED ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Success
InitStateLobbyHost ( ) ;
// Set state to idle to signify to session we are done creating
SetState ( STATE_IDLE ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : State_Searching
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : State_Searching ( )
{
if ( ! verify ( lobbyBackend ! = NULL ) )
{
2012-11-26 18:58:24 +00:00
SetState ( STATE_FAILED ) ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( lobbyBackend - > GetState ( ) = = idLobbyBackend : : STATE_SEARCHING )
{
2012-11-26 18:58:24 +00:00
return ; // Busy but valid
}
2012-11-28 15:47:07 +00:00
if ( lobbyBackend - > GetState ( ) ! = idLobbyBackend : : STATE_READY )
{
2012-11-26 18:58:24 +00:00
SetState ( STATE_FAILED ) ; // Any other lobbyBackend state is invalid
return ;
}
// Done searching, get results from lobbyBackend
lobbyBackend - > GetSearchResults ( searchResults ) ;
2012-11-28 15:47:07 +00:00
if ( searchResults . Num ( ) = = 0 )
{
2012-11-26 18:58:24 +00:00
// If we didn't get any results, set state to failed
SetState ( STATE_FAILED ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
extern idCVar net_maxSearchResultsToTry ;
const int maxSearchResultsToTry = session - > GetTitleStorageInt ( " net_maxSearchResultsToTry " , net_maxSearchResultsToTry . GetInteger ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( searchResults . Num ( ) > maxSearchResultsToTry )
{
2012-11-26 18:58:24 +00:00
searchResults . SetNum ( maxSearchResultsToTry ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Set state to idle to signify we are done searching
SetState ( STATE_IDLE ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : State_Obtaining_Address
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : State_Obtaining_Address ( )
{
if ( lobbyBackend - > GetState ( ) = = idLobbyBackend : : STATE_OBTAINING_ADDRESS )
{
2012-11-26 18:58:24 +00:00
return ; // Valid but not ready
}
2012-11-28 15:47:07 +00:00
if ( lobbyBackend - > GetState ( ) ! = idLobbyBackend : : STATE_READY )
{
2012-11-26 18:58:24 +00:00
// There was an error, signify to caller
failedReason = migrationInfo . persistUntilGameEndsData . wasMigratedJoin ? FAILED_MIGRATION_CONNECT_FAILED : FAILED_CONNECT_FAILED ;
2012-11-28 15:47:07 +00:00
NET_VERBOSE_PRINT ( " idLobby::State_Obtaining_Address: the lobby backend failed. " ) ;
2012-11-26 18:58:24 +00:00
SetState ( STATE_FAILED ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//
// We have the address of the lobbyBackend, we can now send a hello packet
//
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// This will be the host for this lobby type
host = AddPeer ( hostAddress , GenerateSessionID ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Record start time of connection attempt to the host
helloStartTime = Sys_Milliseconds ( ) ;
lastConnectRequest = helloStartTime ;
connectionAttempts = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Change state to connecting
SetState ( STATE_CONNECT_HELLO_WAIT ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Send first connect attempt now (we'll send more periodically if we fail to receive an ack)
// (we do this after changing state, since the function expects we're in the right state)
SendConnectionRequest ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : State_Finalize_Connect
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : State_Finalize_Connect ( )
{
if ( lobbyBackend - > GetState ( ) = = idLobbyBackend : : STATE_CREATING )
{
2012-11-26 18:58:24 +00:00
// Valid but busy
return ;
}
2012-11-28 15:47:07 +00:00
if ( lobbyBackend - > GetState ( ) ! = idLobbyBackend : : STATE_READY )
{
2012-11-26 18:58:24 +00:00
// Any other state not valid, failed
SetState ( STATE_FAILED ) ;
return ;
}
// Success
SetState ( STATE_IDLE ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Tell session mgr if this was a migration
2012-11-28 15:47:07 +00:00
if ( migrationInfo . persistUntilGameEndsData . wasMigratedJoin )
{
2012-11-26 18:58:24 +00:00
sessionCB - > BecamePeer ( * this ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : State_Connect_Hello_Wait
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : State_Connect_Hello_Wait ( )
{
if ( lobbyBackend - > GetState ( ) ! = idLobbyBackend : : STATE_READY )
{
2012-11-26 18:58:24 +00:00
// If the lobbyBackend is in an error state, shut everything down
NET_VERBOSE_PRINT ( " NET: Lobby is no longer ready while waiting for lobbyType %s hello. \n " , GetLobbyName ( ) ) ;
HandleConnectionAttemptFailed ( ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int time = Sys_Milliseconds ( ) ;
const int timeoutMs = session - > GetTitleStorageInt ( " net_connectTimeoutInSeconds " , net_connectTimeoutInSeconds . GetInteger ( ) ) * 1000 ;
2012-11-28 15:47:07 +00:00
if ( timeoutMs ! = 0 & & time - helloStartTime > timeoutMs )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Timeout waiting for lobbyType %s for party hello. \n " , GetLobbyName ( ) ) ;
HandleConnectionAttemptFailed ( ) ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( connectionAttempts < MAX_CONNECT_ATTEMPTS )
{
2012-11-26 18:58:24 +00:00
assert ( connectionAttempts > = 1 ) ; // Should have at least the initial connection attempt
2012-11-28 15:47:07 +00:00
// See if we need to send another hello request
2012-11-26 18:58:24 +00:00
// (keep getting more frequent to increase chance due to possible packet loss, but clamp to MIN_CONNECT_FREQUENCY seconds)
// TODO: We could eventually make timing out a function of actual number of attempts rather than just plain time.
int resendTime = Max ( MIN_CONNECT_FREQUENCY_IN_SECONDS , CONNECT_REQUEST_FREQUENCY_IN_SECONDS / connectionAttempts ) * 1000 ;
2012-11-28 15:47:07 +00:00
if ( time - lastConnectRequest > resendTime )
{
2012-11-26 18:58:24 +00:00
SendConnectionRequest ( ) ;
lastConnectRequest = time ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SetState
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : SetState ( lobbyState_t newState )
{
2012-11-26 18:58:24 +00:00
assert ( newState < NUM_STATES ) ;
assert ( state < NUM_STATES ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
verify_array_size ( stateToString , NUM_STATES ) ;
2012-11-28 15:47:07 +00:00
if ( state = = newState )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: idLobby::SetState: State SAME %s for session %s \n " , stateToString [ newState ] , GetLobbyName ( ) ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Set the current state
NET_VERBOSE_PRINT ( " NET: idLobby::SetState: State changing from %s to %s for session %s \n " , stateToString [ state ] , stateToString [ newState ] , GetLobbyName ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
state = newState ;
}
//===============================================================================
// ** END STATE CODE ***
//===============================================================================
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : StartCreating
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : StartCreating ( )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyBackend = = NULL ) ;
assert ( state = = STATE_IDLE ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float skillLevel = GetAverageLocalUserLevel ( true ) ;
2012-11-28 15:47:07 +00:00
lobbyBackend = sessionCB - > CreateLobbyBackend ( parms , skillLevel , ( idLobbyBackend : : lobbyBackendType_t ) lobbyType ) ;
SetState ( STATE_CREATE_LOBBY_BACKEND ) ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : FindPeer
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : FindPeer ( const lobbyAddress_t & remoteAddress , idPacketProcessor : : sessionId_t sessionID , bool ignoreSessionID )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
bool connectionless = ( sessionID = = idPacketProcessor : : SESSION_ID_CONNECTIONLESS_PARTY | |
sessionID = = idPacketProcessor : : SESSION_ID_CONNECTIONLESS_GAME | |
2012-11-26 18:58:24 +00:00
sessionID = = idPacketProcessor : : SESSION_ID_CONNECTIONLESS_GAME_STATE ) ;
2012-11-28 15:47:07 +00:00
if ( connectionless & & ! ignoreSessionID )
{
2012-11-26 18:58:24 +00:00
return - 1 ; // This was meant to be connectionless. FindPeer is meant for connected (or connecting) peers
}
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
if ( peers [ p ] . GetConnectionState ( ) = = CONNECTION_FREE )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( peers [ p ] . address . Compare ( remoteAddress ) )
{
if ( connectionless & & ignoreSessionID )
{
2012-11-26 18:58:24 +00:00
return p ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Using a rolling check, so that we account for possible packet loss, and out of order issues
2012-11-28 15:47:07 +00:00
if ( IsPeer ( ) )
{
2012-11-26 18:58:24 +00:00
idPacketProcessor : : sessionId_t searchStart = peers [ p ] . sessionID ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Since we only roll the code between matches, we should only need to look ahead a couple increments.
// Worse case, if the stars line up, the client doesn't see the new sessionId, and times out, and gets booted.
2012-11-28 15:47:07 +00:00
// This should be impossible though, since the timings won't be possible considering how long it takes to end the match,
2012-11-26 18:58:24 +00:00
// and restart, and then restart again.
int numTries = 2 ;
2012-11-28 15:47:07 +00:00
while ( numTries - - > 0 & & searchStart ! = sessionID )
{
2012-11-26 18:58:24 +00:00
searchStart = IncrementSessionID ( searchStart ) ;
2012-11-28 15:47:07 +00:00
if ( searchStart = = sessionID )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " NET: Rolling session ID check found new ID: %i \n " , searchStart ) ;
2012-11-28 15:47:07 +00:00
if ( peers [ p ] . packetProc ! = NULL )
{
2012-11-26 18:58:24 +00:00
peers [ p ] . packetProc - > VerifyEmptyReliableQueue ( RELIABLE_GAME_DATA , RELIABLE_DUMMY_MSG ) ;
}
peers [ p ] . sessionID = searchStart ;
break ;
}
}
}
2012-11-28 15:47:07 +00:00
if ( peers [ p ] . sessionID ! = sessionID )
{
2012-11-26 18:58:24 +00:00
continue ;
}
return p ;
}
}
return - 1 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : FindAnyPeer
Find a peer when we don ' t know the session id , and we don ' t care since it ' s a connectionless msg
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : FindAnyPeer ( const lobbyAddress_t & remoteAddress ) const
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
if ( peers [ p ] . GetConnectionState ( ) = = CONNECTION_FREE )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( peers [ p ] . address . Compare ( remoteAddress ) )
{
2012-11-26 18:58:24 +00:00
return p ;
}
}
return - 1 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : FindFreePeer
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : FindFreePeer ( ) const
{
2012-11-26 18:58:24 +00:00
// Return the first non active peer
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
if ( ! peers [ p ] . IsActive ( ) )
{
2012-11-26 18:58:24 +00:00
return p ;
}
}
return - 1 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : AddPeer
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : AddPeer ( const lobbyAddress_t & remoteAddress , idPacketProcessor : : sessionId_t sessionID )
{
2012-11-26 18:58:24 +00:00
// First, make sure we don't already have this peer
int p = FindPeer ( remoteAddress , sessionID ) ;
assert ( p = = - 1 ) ; // When using session ID's, we SHOULDN'T find this remoteAddress/sessionID combo
2012-11-28 15:47:07 +00:00
if ( p = = - 1 )
{
2012-11-26 18:58:24 +00:00
// If we didn't find the peer, we need to add a new one
p = FindFreePeer ( ) ;
2012-11-28 15:47:07 +00:00
if ( p = = - 1 )
{
2012-11-26 18:58:24 +00:00
peer_t newPeer ;
p = peers . Append ( newPeer ) ;
}
2012-11-28 15:47:07 +00:00
peer_t & peer = peers [ p ] ;
2012-11-26 18:58:24 +00:00
peer . ResetAllData ( ) ;
assert ( peer . connectionState = = CONNECTION_FREE ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
peer . address = remoteAddress ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
peer . sessionID = sessionID ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Added peer %s at index %i \n " , remoteAddress . ToString ( ) , p ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Found peer %s at index %i \n " , remoteAddress . ToString ( ) , p ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
SetPeerConnectionState ( p , CONNECTION_CONNECTING ) ;
2012-11-28 15:47:07 +00:00
if ( lobbyType = = GetActingGameStateLobbyType ( ) )
{
2012-11-26 18:58:24 +00:00
// Reset various flags used in game mode
peers [ p ] . ResetMatchData ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return p ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : DisconnectPeerFromSession
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : DisconnectPeerFromSession ( int p )
{
if ( ! verify ( IsHost ( ) ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
peer_t & peer = peers [ p ] ;
if ( peer . GetConnectionState ( ) ! = CONNECTION_FREE )
{
2012-11-26 18:58:24 +00:00
SetPeerConnectionState ( p , CONNECTION_FREE ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : DisconnectAllPeers
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : DisconnectAllPeers ( )
{
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
2012-11-26 18:58:24 +00:00
DisconnectPeerFromSession ( p ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SendGoodbye
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : SendGoodbye ( const lobbyAddress_t & remoteAddress , bool wasFull )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( net_skipGoodbye . GetBool ( ) )
{
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
NET_VERBOSE_PRINT ( " NET: Sending goodbye to %s for %s (wasFull = %i) \n " , remoteAddress . ToString ( ) , GetLobbyName ( ) , wasFull ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
static const int NUM_REDUNDANT_GOODBYES = 10 ;
int msgType = OOB_GOODBYE ;
2012-11-28 15:47:07 +00:00
if ( wasFull )
{
2012-11-26 18:58:24 +00:00
msgType = OOB_GOODBYE_FULL ;
2012-11-28 15:47:07 +00:00
}
else if ( lobbyType = = TYPE_GAME & & ( sessionCB - > GetSessionOptions ( ) & idSession : : OPTION_LEAVE_WITH_PARTY ) & & ! ( parms . matchFlags & MATCH_PARTY_INVITE_PLACEHOLDER ) )
{
2012-11-26 18:58:24 +00:00
msgType = OOB_GOODBYE_W_PARTY ;
}
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < NUM_REDUNDANT_GOODBYES ; i + + )
{
SendConnectionLess ( remoteAddress , msgType ) ;
}
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SetPeerConnectionState
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : SetPeerConnectionState ( int p , connectionState_t newState , bool skipGoodbye )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( ! verify ( p > = 0 & & p < peers . Num ( ) ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " NET: SetPeerConnectionState invalid peer index %i \n " , p ) ;
return ;
}
2012-11-28 15:47:07 +00:00
peer_t & peer = peers [ p ] ;
2012-11-26 18:58:24 +00:00
const lobbyType_t actingGameStateLobbyType = GetActingGameStateLobbyType ( ) ;
2012-11-28 15:47:07 +00:00
if ( peer . GetConnectionState ( ) = = newState )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " NET: SetPeerConnectionState: Peer already in state %i \n " , newState ) ;
assert ( 0 ) ; // This case means something is most likely bad, and it's the programmers fault
assert ( ( peer . packetProc ! = NULL ) = = peer . IsActive ( ) ) ;
assert ( ( ( peer . snapProc ! = NULL ) = = peer . IsActive ( ) ) = = ( actingGameStateLobbyType = = lobbyType ) ) ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( newState = = CONNECTION_CONNECTING )
{
2012-11-26 18:58:24 +00:00
//mem.PushHeap();
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// We better be coming from a free connection state if we are trying to connect
assert ( peer . GetConnectionState ( ) = = CONNECTION_FREE ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
assert ( peer . packetProc = = NULL ) ;
2012-11-28 15:47:07 +00:00
peer . packetProc = new ( TAG_NETWORKING ) idPacketProcessor ( ) ;
if ( lobbyType = = actingGameStateLobbyType )
{
2012-11-26 18:58:24 +00:00
assert ( peer . snapProc = = NULL ) ;
2012-11-28 15:47:07 +00:00
peer . snapProc = new ( TAG_NETWORKING ) idSnapshotProcessor ( ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//mem.PopHeap();
2012-11-28 15:47:07 +00:00
}
else if ( newState = = CONNECTION_ESTABLISHED )
{
2012-11-26 18:58:24 +00:00
// If we are marking this peer as connected for the first time, make sure this peer was actually trying to connect.
assert ( peer . GetConnectionState ( ) = = CONNECTION_CONNECTING ) ;
2012-11-28 15:47:07 +00:00
}
else if ( newState = = CONNECTION_FREE )
{
2012-11-26 18:58:24 +00:00
// If we are freeing this connection and we had an established connection before, make sure to send a goodbye
2012-11-28 15:47:07 +00:00
if ( peer . GetConnectionState ( ) = = CONNECTION_ESTABLISHED & & ! skipGoodbye )
{
idLib : : Printf ( " SetPeerConnectionState: Sending goodbye to peer %s from session %s \n " , peer . address . ToString ( ) , GetLobbyName ( ) ) ;
2012-11-26 18:58:24 +00:00
SendGoodbye ( peer . address ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
peer . connectionState = newState ;
2012-11-28 15:47:07 +00:00
if ( ! peer . IsActive ( ) )
{
if ( peer . packetProc ! = NULL )
{
2012-11-26 18:58:24 +00:00
delete peer . packetProc ;
peer . packetProc = NULL ;
}
2012-11-28 15:47:07 +00:00
if ( peer . snapProc ! = NULL )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = actingGameStateLobbyType ) ;
delete peer . snapProc ;
peer . snapProc = NULL ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Do this in case we disconnected the peer
2012-11-28 15:47:07 +00:00
if ( IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
RemoveUsersWithDisconnectedPeers ( ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : QueueReliableMessage
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : QueueReliableMessage ( int p , byte type , const byte * data , int dataLen )
{
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
// Don't send to this peer if we don't have an established connection of this session type
NET_VERBOSE_PRINT ( " NET: Not sending reliable type %i to peer %i because connectionState is %i \n " , type , p , peer . GetConnectionState ( ) ) ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( peer . packetProc - > NumQueuedReliables ( ) > 2 )
{
2012-11-26 18:58:24 +00:00
idLib : : PrintfIf ( false , " NET: peer.packetProc->NumQueuedReliables() > 2: %i (%i / %s) \n " , peer . packetProc - > NumQueuedReliables ( ) , p , peer . address . ToString ( ) ) ;
}
2012-11-28 15:47:07 +00:00
if ( ! peer . packetProc - > QueueReliableMessage ( type , data , dataLen ) )
{
2012-11-26 18:58:24 +00:00
// For now, when this happens, disconnect from all session types
NET_VERBOSE_PRINT ( " NET: Dropping peer because we overflowed his reliable message queue \n " ) ;
2012-11-28 15:47:07 +00:00
if ( IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
// Disconnect peer from this session type
DisconnectPeerFromSession ( p ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
Shutdown ( ) ; // Shutdown session if we can't queue the reliable
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetNumConnectedPeers
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : GetNumConnectedPeers ( ) const
{
2012-11-26 18:58:24 +00:00
int numConnected = 0 ;
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
numConnected + + ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return numConnected ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetNumConnectedPeersInGame
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : GetNumConnectedPeersInGame ( ) const
{
2012-11-26 18:58:24 +00:00
int numActive = 0 ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < peers . Num ( ) ; i + + )
{
if ( peers [ i ] . IsConnected ( ) & & peers [ i ] . inGame )
{
2012-11-26 18:58:24 +00:00
numActive + + ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return numActive ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SendMatchParmsToPeers
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : SendMatchParmsToPeers ( )
{
if ( ! IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( GetNumConnectedPeers ( ) = = 0 )
{
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
byte buffer [ idPacketProcessor : : MAX_PACKET_SIZE ] ;
idBitMsg msg ( buffer , sizeof ( buffer ) ) ;
parms . Write ( msg ) ;
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
if ( ! peers [ p ] . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
QueueReliableMessage ( p , RELIABLE_MATCH_PARMS , msg . GetReadData ( ) , msg . GetSize ( ) ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
STATIC idLobby : : IsReliablePlayerToPlayerType
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : IsReliablePlayerToPlayerType ( byte type )
{
2012-11-26 18:58:24 +00:00
return ( type > = RELIABLE_PLAYER_TO_PLAYER_BEGIN ) & & ( type < RELIABLE_PLAYER_TO_PLAYER_END ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : HandleReliablePlayerToPlayerMsg
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : HandleReliablePlayerToPlayerMsg ( int peerNum , idBitMsg & msg , int type )
{
2012-11-26 18:58:24 +00:00
reliablePlayerToPlayerHeader_t info ;
int c , b ;
msg . SaveReadState ( c , b ) ; // in case we need to forward or fail
2012-11-28 15:47:07 +00:00
if ( ! info . Read ( this , msg ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Warning ( " NET: Ignoring invalid reliable player to player message " ) ;
msg . RestoreReadState ( c , b ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const bool isForLocalPlayer = IsSessionUserIndexLocal ( info . toSessionUserIndex ) ;
2012-11-28 15:47:07 +00:00
if ( isForLocalPlayer )
{
2012-11-26 18:58:24 +00:00
HandleReliablePlayerToPlayerMsg ( info , msg , type ) ;
2012-11-28 15:47:07 +00:00
}
else if ( IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
const int targetPeer = PeerIndexForSessionUserIndex ( info . toSessionUserIndex ) ;
msg . RestoreReadState ( c , b ) ;
// forward the rest of the data
2012-11-28 15:47:07 +00:00
const byte * data = msg . GetReadData ( ) + msg . GetReadCount ( ) ;
2012-11-26 18:58:24 +00:00
int dataLen = msg . GetSize ( ) - msg . GetReadCount ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
QueueReliableMessage ( targetPeer , type , data , dataLen ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
idLib : : Warning ( " NET: Can't forward reliable message for remote player: I'm not the host " ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : HandleReliablePlayerToPlayerMsg
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : HandleReliablePlayerToPlayerMsg ( const reliablePlayerToPlayerHeader_t & info , idBitMsg & msg , int reliableType )
{
2012-11-26 18:58:24 +00:00
#if 0
// Remember that the reliablePlayerToPlayerHeader_t was already removed from the msg
2012-11-28 15:47:07 +00:00
reliablePlayerToPlayer_t type = ( reliablePlayerToPlayer_t ) ( reliableType - RELIABLE_PLAYER_TO_PLAYER_BEGIN ) ;
switch ( type )
{
case RELIABLE_PLAYER_TO_PLAYER_VOICE_EVENT :
{
2012-11-26 18:58:24 +00:00
sessionCB - > HandleReliableVoiceEvent ( * this , info . fromSessionUserIndex , info . toSessionUserIndex , msg ) ;
break ;
}
2012-11-28 15:47:07 +00:00
default :
{
idLib : : Warning ( " NET: Ignored unknown player to player reliable type %i " , ( int ) type ) ;
2012-11-26 18:58:24 +00:00
}
} ;
# endif
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SendConnectionLess
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : SendConnectionLess ( const lobbyAddress_t & remoteAddress , byte type , const byte * data , int dataLen )
{
2012-11-26 18:58:24 +00:00
idBitMsg msg ( data , dataLen ) ;
msg . SetSize ( dataLen ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
byte buffer [ idPacketProcessor : : MAX_OOB_MSG_SIZE ] ;
idBitMsg processedMsg ( buffer , sizeof ( buffer ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Process the send
idPacketProcessor : : ProcessConnectionlessOutgoing ( msg , processedMsg , lobbyType , type ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const bool useDirectPort = ( lobbyType = = TYPE_GAME_STATE ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Send it
2012-11-28 15:47:07 +00:00
sessionCB - > SendRawPacket ( remoteAddress , processedMsg . GetReadData ( ) , processedMsg . GetSize ( ) , useDirectPort ) ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SendConnectionRequest
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : SendConnectionRequest ( )
{
2012-11-26 18:58:24 +00:00
// Some sanity checking
assert ( state = = STATE_CONNECT_HELLO_WAIT ) ;
assert ( peers [ host ] . GetConnectionState ( ) = = CONNECTION_CONNECTING ) ;
assert ( GetNumLobbyUsers ( ) = = 0 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Buffer to hold connect msg
byte buffer [ idPacketProcessor : : MAX_PACKET_SIZE - 2 ] ;
idBitMsg msg ( buffer , sizeof ( buffer ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Add the current version info to the handshake
2012-12-11 22:04:53 +00:00
const unsigned int localChecksum = NetGetVersionChecksum ( ) ; // DG: use int instead of long for 64bit compatibility
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: version = %i \n " , localChecksum ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
msg . WriteLong ( localChecksum ) ;
msg . WriteUShort ( peers [ host ] . sessionID ) ;
msg . WriteBool ( connectIsFromInvite ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// We use InitSessionUsersFromLocalUsers here to copy the current local users over to session users simply to have a list
// to send on the initial connection attempt. We immediately clear our session user list once sent.
InitSessionUsersFromLocalUsers ( true ) ;
2012-11-28 15:47:07 +00:00
if ( GetNumLobbyUsers ( ) > 0 )
{
2012-11-26 18:58:24 +00:00
// Fill up the msg with the users on this machine
msg . WriteByte ( GetNumLobbyUsers ( ) ) ;
2012-11-28 15:47:07 +00:00
for ( int u = 0 ; u < GetNumLobbyUsers ( ) ; u + + )
{
2012-11-26 18:58:24 +00:00
GetLobbyUser ( u ) - > WriteToMsg ( msg ) ;
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
FreeAllUsers ( ) ;
SetState ( STATE_FAILED ) ;
2012-11-28 15:47:07 +00:00
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
// We just used these users to fill up the msg above, we will get the real list from the server if we connect.
FreeAllUsers ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Sending hello to: %s (lobbyType: %s, session ID %i, attempt: %i) \n " , hostAddress . ToString ( ) , GetLobbyName ( ) , peers [ host ] . sessionID , connectionAttempts ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
SendConnectionLess ( hostAddress , OOB_HELLO , msg . GetReadData ( ) , msg . GetSize ( ) ) ;
connectionAttempts + + ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : ConnectTo
Fires off a request to get the address of a lobbyBackend owner , and then attempts to connect ( eventually handled in HandleObtainingLobbyOwnerAddress )
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : ConnectTo ( const lobbyConnectInfo_t & connectInfo , bool fromInvite )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: idSessionLocal::ConnectTo: fromInvite = %i \n " , fromInvite ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Make sure current session is shutdown
Shutdown ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
connectIsFromInvite = fromInvite ;
2012-11-28 15:47:07 +00:00
lobbyBackend = sessionCB - > JoinFromConnectInfo ( connectInfo , ( idLobbyBackend : : lobbyBackendType_t ) lobbyType ) ;
2012-11-26 18:58:24 +00:00
// First, we need the address of the lobbyBackend owner
lobbyBackend - > GetOwnerAddress ( hostAddress ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
SetState ( STATE_OBTAINING_ADDRESS ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : HandleGoodbyeFromPeer
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : HandleGoodbyeFromPeer ( int peerNum , lobbyAddress_t & remoteAddress , int msgType )
{
if ( migrationInfo . state ! = MIGRATE_NONE )
{
2012-11-26 18:58:24 +00:00
// If this peer is on our invite list, remove them
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < migrationInfo . invites . Num ( ) ; i + + )
{
if ( migrationInfo . invites [ i ] . address . Compare ( remoteAddress , true ) )
{
2012-11-26 18:58:24 +00:00
migrationInfo . invites . RemoveIndex ( i ) ;
break ;
}
}
}
2012-11-28 15:47:07 +00:00
if ( peerNum < 0 )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Goodbye from unknown peer %s on session %s \n " , remoteAddress . ToString ( ) , GetLobbyName ( ) ) ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( peers [ peerNum ] . GetConnectionState ( ) = = CONNECTION_FREE )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Goodbye from peer %s on session %s that is not connected \n " , remoteAddress . ToString ( ) , GetLobbyName ( ) ) ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
// Goodbye from peer, remove him
NET_VERBOSE_PRINT ( " NET: Goodbye from peer %s, on session %s \n " , remoteAddress . ToString ( ) , GetLobbyName ( ) ) ;
DisconnectPeerFromSession ( peerNum ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// Let session handler take care of this
NET_VERBOSE_PRINT ( " NET: Goodbye from host %s, on session %s \n " , remoteAddress . ToString ( ) , GetLobbyName ( ) ) ;
sessionCB - > GoodbyeFromHost ( * this , peerNum , remoteAddress , msgType ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : HandleGoodbyeFromPeer
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : HandleConnectionAttemptFailed ( )
{
2012-11-26 18:58:24 +00:00
Shutdown ( ) ;
failedReason = migrationInfo . persistUntilGameEndsData . wasMigratedJoin ? FAILED_MIGRATION_CONNECT_FAILED : FAILED_CONNECT_FAILED ;
SetState ( STATE_FAILED ) ;
2012-11-28 15:47:07 +00:00
if ( migrationInfo . persistUntilGameEndsData . wasMigratedJoin )
{
2012-11-26 18:58:24 +00:00
sessionCB - > FailedGameMigration ( * this ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
ResetAllMigrationState ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
needToDisplayMigrateMsg = false ;
migrateMsgFlags = 0 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : ConnectToNextSearchResult
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : ConnectToNextSearchResult ( )
{
if ( lobbyType ! = TYPE_GAME )
{
2012-11-26 18:58:24 +00:00
return false ; // Only game sessions use matchmaking searches
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// End current session lobby (this WON'T free search results)
Shutdown ( ) ;
2012-11-28 15:47:07 +00:00
if ( searchResults . Num ( ) = = 0 )
{
2012-11-26 18:58:24 +00:00
return false ; // No more search results to connect to, give up
}
// Get next search result
lobbyConnectInfo_t connectInfo = searchResults [ 0 ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Remove this search result
searchResults . RemoveIndex ( 0 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If we are connecting to a game lobby, tell our party to connect to this lobby as well
2012-11-28 15:47:07 +00:00
if ( lobbyType = = TYPE_GAME & & sessionCB - > GetPartyLobby ( ) . IsLobbyActive ( ) )
{
2012-11-26 18:58:24 +00:00
sessionCB - > GetPartyLobby ( ) . SendMembersToLobby ( lobbyType , connectInfo , true ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Attempt to connect the lobby
ConnectTo ( connectInfo , true ) ; // Pass in true for invite, since searches are for matchmaking, and we should always be able to connect to those types of matches
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Clear the "Lobby was Full" dialog in case it's up, since we are going to try to connect to a different lobby now
common - > Dialog ( ) . ClearDialog ( GDM_LOBBY_FULL ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ; // Notify caller we are attempting to connect
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : CheckVersion
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : CheckVersion ( idBitMsg & msg , lobbyAddress_t peerAddress )
{
2012-12-11 22:04:53 +00:00
const unsigned int remoteChecksum = msg . ReadLong ( ) ; // DG: use int instead of long for 64bit compatibility
2012-11-28 15:47:07 +00:00
if ( net_checkVersion . GetInteger ( ) = = 1 )
{
2012-12-11 22:04:53 +00:00
const unsigned int localChecksum = NetGetVersionChecksum ( ) ; // DG: use int instead of long for 64bit compatibility
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Comparing handshake version - localChecksum = %i, remoteChecksum = %i \n " , localChecksum , remoteChecksum ) ;
return ( remoteChecksum = = localChecksum ) ;
}
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : VerifyNumConnectingUsers
Make sure number of users connecting is valid , and make sure we have enough room
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : VerifyNumConnectingUsers ( idBitMsg & msg )
{
2012-11-26 18:58:24 +00:00
int c , b ;
msg . SaveReadState ( c , b ) ;
const int numUsers = msg . ReadByte ( ) ;
msg . RestoreReadState ( c , b ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const int numFreeSlots = NumFreeSlots ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: VerifyNumConnectingUsers %i users, %i free slots for %s \n " , numUsers , numFreeSlots , GetLobbyName ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( numUsers < = 0 | | numUsers > MAX_PLAYERS - 1 )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Invalid numUsers %i \n " , numUsers ) ;
return false ;
2012-11-28 15:47:07 +00:00
}
else if ( numUsers > numFreeSlots )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: %i slots requested, but only %i are available \n " , numUsers , numFreeSlots ) ;
return false ;
2012-11-28 15:47:07 +00:00
}
else if ( lobbyType = = TYPE_PARTY & & sessionCB - > GetState ( ) > = idSession : : GAME_LOBBY & & sessionCB - > GetGameLobby ( ) . IsLobbyActive ( ) & & ! IsMigrating ( ) )
{
2012-11-26 18:58:24 +00:00
const int numFreeGameSlots = sessionCB - > GetGameLobby ( ) . NumFreeSlots ( ) ;
2012-11-28 15:47:07 +00:00
if ( numUsers > numFreeGameSlots )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: %i slots requested, but only %i are available on the active game session \n " , numUsers , numFreeGameSlots ) ;
return false ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : VerifyLobbyUserIDs
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : VerifyLobbyUserIDs ( idBitMsg & msg )
{
2012-11-26 18:58:24 +00:00
int c , b ;
msg . SaveReadState ( c , b ) ;
const int numUsers = msg . ReadByte ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Add the new users to our own list
2012-11-28 15:47:07 +00:00
for ( int u = 0 ; u < numUsers ; u + + )
{
2012-11-26 18:58:24 +00:00
lobbyUser_t newUser ;
// Read in the new user
newUser . ReadFromMsg ( msg ) ;
2012-11-28 15:47:07 +00:00
if ( GetLobbyUserIndexByID ( newUser . lobbyUserID , true ) ! = - 1 )
{
2012-11-26 18:58:24 +00:00
msg . RestoreReadState ( c , b ) ;
return false ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
msg . RestoreReadState ( c , b ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : HandleInitialPeerConnection
Received on an initial peer connect request ( OOB_HELLO )
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : HandleInitialPeerConnection ( idBitMsg & msg , const lobbyAddress_t & peerAddress , int peerNum )
{
if ( net_ignoreConnects . GetInteger ( ) > 0 )
{
if ( net_ignoreConnects . GetInteger ( ) = = 2 )
{
2012-11-26 18:58:24 +00:00
SendGoodbye ( peerAddress ) ;
}
return - 1 ;
}
2012-11-28 15:47:07 +00:00
if ( ! IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Got connectionless hello from peer %s on session, and we are not a host \n " , peerAddress . ToString ( ) ) ;
SendGoodbye ( peerAddress ) ;
return - 1 ;
}
// See if this is a peer migrating to us, if so, remove them from our invite list
bool migrationInvite = false ;
int migrationGameData = - 1 ;
2012-11-28 15:47:07 +00:00
for ( int i = migrationInfo . invites . Num ( ) - 1 ; i > = 0 ; i - - )
{
if ( migrationInfo . invites [ i ] . address . Compare ( peerAddress , true ) )
{
2012-11-26 18:58:24 +00:00
migrationGameData = migrationInfo . invites [ i ] . migrationGameData ;
migrationInfo . invites . RemoveIndex ( i ) ; // Remove this peer from the list, since this peer will now be connected (or rejected, either way we don't want to keep sending invites)
migrationInvite = true ;
NET_VERBOSE_PRINT ( " ^2NET: Response from migration invite %s. GameData: %d \n " , peerAddress . ToString ( ) , migrationGameData ) ;
}
}
2012-11-28 15:47:07 +00:00
if ( ! MatchTypeIsJoinInProgress ( parms . matchFlags ) & & lobbyType = = TYPE_GAME & & migrationInfo . persistUntilGameEndsData . wasMigratedHost & & IsMigratedStatsGame ( ) & & ! migrationInvite )
{
2012-11-26 18:58:24 +00:00
// No matter what, don't let people join migrated game sessions that are going to continue on to the same game
// Not on invite list in a migrated game session - bounce him
NET_VERBOSE_PRINT ( " NET: Denying game connection from %s since not on migration invite list \n " , peerAddress . ToString ( ) ) ;
2012-11-28 15:47:07 +00:00
for ( int i = migrationInfo . invites . Num ( ) - 1 ; i > = 0 ; i - - )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " Invite[%d] addr: %s \n " , i , migrationInfo . invites [ i ] . address . ToString ( ) ) ;
}
SendGoodbye ( peerAddress ) ;
return - 1 ;
}
2012-11-28 15:47:07 +00:00
if ( MatchTypeIsJoinInProgress ( parms . matchFlags ) )
{
2012-11-26 18:58:24 +00:00
// If this is for a game connection, make sure we have a game lobby
2012-11-28 15:47:07 +00:00
if ( ( lobbyType = = TYPE_GAME | | lobbyType = = TYPE_GAME_STATE ) & & sessionCB - > GetState ( ) < idSession : : GAME_LOBBY )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Denying game connection from %s because we don't have a game lobby \n " , peerAddress . ToString ( ) ) ;
SendGoodbye ( peerAddress ) ;
return - 1 ;
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// If this is for a game connection, make sure we are in the game lobby
2012-11-28 15:47:07 +00:00
if ( lobbyType = = TYPE_GAME & & sessionCB - > GetState ( ) ! = idSession : : GAME_LOBBY )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Denying game connection from %s while not in game lobby \n " , peerAddress . ToString ( ) ) ;
SendGoodbye ( peerAddress ) ;
return - 1 ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If this is for a party connection, make sure we are not in game, unless this was for host migration invite
2012-11-28 15:47:07 +00:00
if ( ! migrationInvite & & lobbyType = = TYPE_PARTY & & ( sessionCB - > GetState ( ) = = idSession : : INGAME | | sessionCB - > GetState ( ) = = idSession : : LOADING ) )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Denying party connection from %s because we were already in a game \n " , peerAddress . ToString ( ) ) ;
SendGoodbye ( peerAddress ) ;
return - 1 ;
}
}
2012-11-28 15:47:07 +00:00
if ( ! CheckVersion ( msg , peerAddress ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " NET: Denying user %s with wrong version number \n " , peerAddress . ToString ( ) ) ;
SendGoodbye ( peerAddress ) ;
return - 1 ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idPacketProcessor : : sessionId_t sessionID = msg . ReadUShort ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Check to see if this is a peer trying to connect with a different sessionID
// If the peer got abruptly disconnected, the peer could be trying to reconnect from a non clean disconnect
2012-11-28 15:47:07 +00:00
if ( peerNum > = 0 )
{
peer_t & existingPeer = peers [ peerNum ] ;
2012-11-26 18:58:24 +00:00
assert ( existingPeer . GetConnectionState ( ) ! = CONNECTION_FREE ) ;
2012-11-28 15:47:07 +00:00
if ( existingPeer . sessionID = = sessionID )
{
2012-11-26 18:58:24 +00:00
return peerNum ; // If this is the same sessionID, then assume redundant connection attempt
}
//
// This peer must be trying to reconnect from a previous abrupt disconnect
//
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Reconnecting peer %s for session %s \n " , peerAddress . ToString ( ) , GetLobbyName ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Assume a peer is trying to reconnect from a non clean disconnect
// We want to set the connection back to FREE manually, so we don't send a goodbye
existingPeer . connectionState = CONNECTION_FREE ;
2012-11-28 15:47:07 +00:00
if ( existingPeer . packetProc ! = NULL )
{
2012-11-26 18:58:24 +00:00
delete existingPeer . packetProc ;
existingPeer . packetProc = NULL ;
}
2012-11-28 15:47:07 +00:00
if ( existingPeer . snapProc ! = NULL )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = TYPE_GAME ) ; // Only games sessions should be creating snap processors
delete existingPeer . snapProc ;
existingPeer . snapProc = NULL ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
RemoveUsersWithDisconnectedPeers ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
peerNum = - 1 ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// See if this was from an invite we sent out. If it wasn't, make sure we aren't invite only
const bool fromInvite = msg . ReadBool ( ) ;
2012-11-28 15:47:07 +00:00
if ( ! fromInvite & & MatchTypeInviteOnly ( parms . matchFlags ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " NET: Denying user %s because they were not invited to an invite only match \n " , peerAddress . ToString ( ) ) ;
SendGoodbye ( peerAddress ) ;
return - 1 ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Make sure we have room for the users connecting
2012-11-28 15:47:07 +00:00
if ( ! VerifyNumConnectingUsers ( msg ) )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Denying connection from %s in session %s due to being out of user slots \n " , peerAddress . ToString ( ) , GetLobbyName ( ) ) ;
SendGoodbye ( peerAddress , true ) ;
return - 1 ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Make sure there are no lobby id conflicts
2012-11-28 15:47:07 +00:00
if ( ! verify ( VerifyLobbyUserIDs ( msg ) ) )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Denying connection from %s in session %s due to lobby id conflict \n " , peerAddress . ToString ( ) , GetLobbyName ( ) ) ;
SendGoodbye ( peerAddress , true ) ;
return - 1 ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Calling AddPeer will set our connectionState to this peer as CONNECTION_CONNECTING (which will get set to CONNECTION_ESTABLISHED below)
peerNum = AddPeer ( peerAddress , sessionID ) ;
2012-11-28 15:47:07 +00:00
peer_t & newPeer = peers [ peerNum ] ;
2012-11-26 18:58:24 +00:00
assert ( newPeer . GetConnectionState ( ) = = CONNECTION_CONNECTING ) ;
assert ( lobbyType ! = GetActingGameStateLobbyType ( ) | | newPeer . snapProc ! = NULL ) ;
2012-11-28 15:47:07 +00:00
// First, add users from this new peer to our user list
2012-11-26 18:58:24 +00:00
// (which will then forward the list to all peers except peerNum)
AddUsersFromMsg ( msg , peerNum ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Mark the peer as connected for this session type
SetPeerConnectionState ( peerNum , CONNECTION_ESTABLISHED ) ;
// Update their heart beat to current
newPeer . lastHeartBeat = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
byte buffer [ idPacketProcessor : : MAX_PACKET_SIZE ] ;
idBitMsg outmsg ( buffer , sizeof ( buffer ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Let them know their peer index on this host
// peerIndexOnHost (put this here so it shows up in search results when finding out where it's used/referenced)
outmsg . WriteLong ( peerNum ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If they are connecting to our party lobby, let them know the party token
2012-11-28 15:47:07 +00:00
if ( lobbyType = = TYPE_PARTY )
{
2012-11-26 18:58:24 +00:00
outmsg . WriteLong ( GetPartyTokenAsHost ( ) ) ;
}
2012-11-28 15:47:07 +00:00
if ( lobbyType = = TYPE_GAME | | lobbyType = = TYPE_GAME_STATE )
{
2012-11-26 18:58:24 +00:00
// If this is a game session, reset the loading and ingame flags
newPeer . loaded = false ;
newPeer . inGame = false ;
}
// Write out current match parms
parms . Write ( outmsg ) ;
2012-11-28 15:47:07 +00:00
// Send list of existing users to this new peer
2012-11-26 18:58:24 +00:00
// (the users from the new peer will also be in this list, since we already called AddUsersFromMsg)
outmsg . WriteByte ( GetNumLobbyUsers ( ) ) ;
2012-11-28 15:47:07 +00:00
for ( int u = 0 ; u < GetNumLobbyUsers ( ) ; u + + )
{
2012-11-26 18:58:24 +00:00
GetLobbyUser ( u ) - > WriteToMsg ( outmsg ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lobbyBackend - > FillMsgWithPostConnectInfo ( outmsg ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Sending response to %s, lobbyType %s, sessionID %i \n " , peerAddress . ToString ( ) , GetLobbyName ( ) , sessionID ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
QueueReliableMessage ( peerNum , RELIABLE_HELLO , outmsg . GetReadData ( ) , outmsg . GetSize ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( MatchTypeIsJoinInProgress ( parms . matchFlags ) )
{
2012-11-26 18:58:24 +00:00
// If have an active game lobby, and someone joins our party, tell them to join our game
2012-11-28 15:47:07 +00:00
if ( lobbyType = = TYPE_PARTY & & sessionCB - > GetState ( ) > = idSession : : GAME_LOBBY )
{
2012-11-26 18:58:24 +00:00
SendPeerMembersToLobby ( peerNum , TYPE_GAME , false ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// We are are ingame, then start the client loading immediately
2012-11-28 15:47:07 +00:00
if ( ( lobbyType = = TYPE_GAME | | lobbyType = = TYPE_GAME_STATE ) & & sessionCB - > GetState ( ) > = idSession : : LOADING )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " ******* JOIN IN PROGRESS ******** \n " ) ;
2012-11-28 15:47:07 +00:00
if ( sessionCB - > GetState ( ) = = idSession : : INGAME )
{
2012-11-26 18:58:24 +00:00
newPeer . pauseSnapshots = true ; // Since this player joined in progress, let game dictate when to start sending snaps
}
QueueReliableMessage ( peerNum , idLobby : : RELIABLE_START_LOADING ) ;
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// If we are in a game lobby, and someone joins our party, tell them to join our game
2012-11-28 15:47:07 +00:00
if ( lobbyType = = TYPE_PARTY & & sessionCB - > GetState ( ) = = idSession : : GAME_LOBBY )
{
2012-11-26 18:58:24 +00:00
SendPeerMembersToLobby ( peerNum , TYPE_GAME , false ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Send mic status of the current lobby to applicable peers
SendPeersMicStatusToNewUsers ( peerNum ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If we made is this far, update the users migration game data index
2012-11-28 15:47:07 +00:00
for ( int u = 0 ; u < GetNumLobbyUsers ( ) ; u + + )
{
if ( GetLobbyUser ( u ) - > peerIndex = = peerNum )
{
2012-11-26 18:58:24 +00:00
GetLobbyUser ( u ) - > migrationGameData = migrationGameData ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return peerNum ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : InitStateLobbyHost
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : InitStateLobbyHost ( )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyBackend ! = NULL ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// We will be the host
isHost = true ;
2012-11-28 15:47:07 +00:00
if ( net_headlessServer . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
return ; // Don't add any players to headless server
}
2012-11-28 15:47:07 +00:00
if ( migrationInfo . state ! = MIGRATE_NONE )
{
2012-11-26 18:58:24 +00:00
migrationInfo . persistUntilGameEndsData . wasMigratedHost = true ; // InitSessionUsersFromLocalUsers needs to know this
migrationInfo . persistUntilGameEndsData . hasRelaunchedMigratedGame = false ;
// migrationDlg = GDM_MIGRATING_WAITING;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Initialize the initial user list for this lobby
InitSessionUsersFromLocalUsers ( MatchTypeIsOnline ( parms . matchFlags ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Set the session's hostAddress to the local players' address.
const int myUserIndex = GetLobbyUserIndexByLocalUserHandle ( sessionCB - > GetSignInManager ( ) . GetMasterLocalUserHandle ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( myUserIndex ! = - 1 )
{
2012-11-26 18:58:24 +00:00
hostAddress = GetLobbyUser ( myUserIndex ) - > address ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Since we are the host, we have to register our initial session users with the lobby
// All additional users will join through AddUsersFromMsg, and RegisterUser is handled in there from here on out.
// Peers will add users exclusively through AddUsersFromMsg.
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < GetNumLobbyUsers ( ) ; i + + )
{
lobbyUser_t * user = GetLobbyUser ( i ) ;
2012-11-26 18:58:24 +00:00
RegisterUser ( user ) ;
2012-11-28 15:47:07 +00:00
if ( lobbyType = = TYPE_PARTY )
{
2012-11-26 18:58:24 +00:00
user - > partyToken = GetPartyTokenAsHost ( ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Set the lobbies skill level
lobbyBackend - > UpdateLobbySkill ( GetAverageSessionLevel ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Make sure and register all the addresses of the invites we'll send out as the new host
2012-11-28 15:47:07 +00:00
if ( migrationInfo . state ! = MIGRATE_NONE )
{
2012-11-26 18:58:24 +00:00
// Tell the session that we became the host, so the session mgr can adjust state if needed
sessionCB - > BecameHost ( * this ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Register this address with this lobbyBackend
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < migrationInfo . invites . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
lobbyBackend - > RegisterAddress ( migrationInfo . invites [ i ] . address ) ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SendMembersToLobby
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : SendMembersToLobby ( lobbyType_t destLobbyType , const lobbyConnectInfo_t & connectInfo , bool waitForOtherMembers )
{
2012-11-26 18:58:24 +00:00
// It's not our job to send party members to a game if we aren't the party host
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
2012-11-26 18:58:24 +00:00
// Send the message to all connected peers
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
SendPeerMembersToLobby ( i , destLobbyType , connectInfo , waitForOtherMembers ) ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SendMembersToLobby
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : SendMembersToLobby ( idLobby & destLobby , bool waitForOtherMembers )
{
if ( destLobby . lobbyBackend = = NULL )
{
2012-11-26 18:58:24 +00:00
return ; // We don't have a game lobbyBackend to get an address for
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lobbyConnectInfo_t connectInfo = destLobby . lobbyBackend - > GetConnectInfo ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
SendMembersToLobby ( destLobby . lobbyType , connectInfo , waitForOtherMembers ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SendPeerMembersToLobby
Give the address of a game lobby to a particular peer , notifying that peer to send a hello to the same server .
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : SendPeerMembersToLobby ( int peerIndex , lobbyType_t destLobbyType , const lobbyConnectInfo_t & connectInfo , bool waitForOtherMembers )
{
2012-11-26 18:58:24 +00:00
// It's not our job to send party members to a game if we aren't the party host
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
2012-11-26 18:58:24 +00:00
assert ( peerIndex > = 0 ) ;
assert ( peerIndex < peers . Num ( ) ) ;
2012-11-28 15:47:07 +00:00
peer_t & peer = peers [ peerIndex ] ;
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Sending peer %i (%s) to game lobby \n " , peerIndex , peer . address . ToString ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( ! peer . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Warning ( " NET: Can't send peer %i to game lobby: peer isn't in party " , peerIndex ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
byte buffer [ idPacketProcessor : : MAX_PACKET_SIZE - 2 ] ;
idBitMsg outmsg ( buffer , sizeof ( buffer ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Have lobby fill out msg with connection info
connectInfo . WriteToMsg ( outmsg ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
outmsg . WriteByte ( destLobbyType ) ;
outmsg . WriteBool ( waitForOtherMembers ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
QueueReliableMessage ( peerIndex , RELIABLE_CONNECT_AND_MOVE_TO_LOBBY , outmsg . GetReadData ( ) , outmsg . GetSize ( ) ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SendPeerMembersToLobby
Give the address of a game lobby to a particular peer , notifying that peer to send a hello to the same server .
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : SendPeerMembersToLobby ( int peerIndex , lobbyType_t destLobbyType , bool waitForOtherMembers )
{
idLobby * lobby = sessionCB - > GetLobbyFromType ( destLobbyType ) ;
if ( ! verify ( lobby ! = NULL ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( ! verify ( lobby - > lobbyBackend ! = NULL ) )
{
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
lobbyConnectInfo_t connectInfo = lobby - > lobbyBackend - > GetConnectInfo ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
SendPeerMembersToLobby ( peerIndex , destLobbyType , connectInfo , waitForOtherMembers ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : NotifyPartyOfLeavingGameLobby
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : NotifyPartyOfLeavingGameLobby ( )
{
if ( lobbyType ! = TYPE_PARTY )
{
2012-11-26 18:58:24 +00:00
return ; // We are not a party lobby
}
2012-11-28 15:47:07 +00:00
if ( ! IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
return ; // We are not the host of a party lobby, we can't do this
}
2012-11-28 15:47:07 +00:00
if ( ! ( sessionCB - > GetSessionOptions ( ) & idSession : : OPTION_LEAVE_WITH_PARTY ) )
{
2012-11-26 18:58:24 +00:00
return ; // Options aren't set to notify party of leaving
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Tell our party to leave the game they are in
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
QueueReliableMessage ( i , RELIABLE_PARTY_LEAVE_GAME_LOBBY ) ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetPartyTokenAsHost
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
uint32 idLobby : : GetPartyTokenAsHost ( )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = TYPE_PARTY ) ;
assert ( IsHost ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( partyToken = = 0 )
{
2012-11-26 18:58:24 +00:00
// I don't know if this is mathematically sound, but it seems reasonable.
// Don't do this at app startup (i.e. in the constructor) or it will be a lot less random.
2012-12-11 22:04:53 +00:00
// DG: use int instead of long for 64bit compatibility
unsigned int seed = Sys_Milliseconds ( ) ; // time app has been running
// DG end
2012-11-28 15:47:07 +00:00
idLocalUser * masterUser = session - > GetSignInManager ( ) . GetMasterLocalUser ( ) ;
if ( masterUser ! = NULL )
{
2012-11-26 18:58:24 +00:00
seed + = idStr : : Hash ( masterUser - > GetGamerTag ( ) ) ;
}
partyToken = idRandom ( seed ) . RandomInt ( ) ;
idLib : : Printf ( " NET: PartyToken is %u (seed = %u) \n " , partyToken , seed ) ;
}
return partyToken ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : EncodeSessionID
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idPacketProcessor : : sessionId_t idLobby : : EncodeSessionID ( uint32 key ) const
{
2012-11-26 18:58:24 +00:00
assert ( sizeof ( uint32 ) > = sizeof ( idPacketProcessor : : sessionId_t ) ) ;
const int numBits = sizeof ( idPacketProcessor : : sessionId_t ) * 8 - idPacketProcessor : : NUM_LOBBY_TYPE_BITS ;
const uint32 mask = ( 1 < < numBits ) - 1 ;
idPacketProcessor : : sessionId_t sessionID = ( key & mask ) < < idPacketProcessor : : NUM_LOBBY_TYPE_BITS ;
sessionID | = ( lobbyType + 1 ) ;
return sessionID ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : EncodeSessionID
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : DecodeSessionID ( idPacketProcessor : : sessionId_t sessionID , uint32 & key ) const
{
2012-11-26 18:58:24 +00:00
assert ( sizeof ( uint32 ) > = sizeof ( idPacketProcessor : : sessionId_t ) ) ;
key = sessionID > > idPacketProcessor : : NUM_LOBBY_TYPE_BITS ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GenerateSessionID
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idPacketProcessor : : sessionId_t idLobby : : GenerateSessionID ( ) const
{
2012-11-26 18:58:24 +00:00
idPacketProcessor : : sessionId_t sessionID = EncodeSessionID ( Sys_Milliseconds ( ) ) ;
// Make sure we can use it
2012-11-28 15:47:07 +00:00
while ( ! SessionIDCanBeUsedForInBand ( sessionID ) )
{
2012-11-26 18:58:24 +00:00
sessionID = IncrementSessionID ( sessionID ) ;
}
return sessionID ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SessionIDCanBeUsedForInBand
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : SessionIDCanBeUsedForInBand ( idPacketProcessor : : sessionId_t sessionID ) const
{
if ( sessionID = = idPacketProcessor : : SESSION_ID_INVALID )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( sessionID = = idPacketProcessor : : SESSION_ID_CONNECTIONLESS_PARTY )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( sessionID = = idPacketProcessor : : SESSION_ID_CONNECTIONLESS_GAME )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( sessionID = = idPacketProcessor : : SESSION_ID_CONNECTIONLESS_GAME_STATE )
{
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 : : IncrementSessionID
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idPacketProcessor : : sessionId_t idLobby : : IncrementSessionID ( idPacketProcessor : : sessionId_t sessionID ) const
{
2012-11-26 18:58:24 +00:00
// Increment, taking into account valid id's
2012-11-28 15:47:07 +00:00
while ( 1 )
{
2012-11-26 18:58:24 +00:00
uint32 key = 0 ;
DecodeSessionID ( sessionID , key ) ;
key + + ;
sessionID = EncodeSessionID ( key ) ;
2012-11-28 15:47:07 +00:00
if ( SessionIDCanBeUsedForInBand ( sessionID ) )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
return sessionID ;
}
# define VERIFY_CONNECTED_PEER( p, sessionType_, msgType ) \
if ( ! verify ( lobbyType = = sessionType_ ) ) { \
idLib : : Printf ( " NET: " # msgType " , peer:%s invalid session type for " # sessionType_ " %i. \n " , peer . address . ToString ( ) , sessionType_ ) ; \
return ; \
} \
if ( peers [ p ] . GetConnectionState ( ) ! = CONNECTION_ESTABLISHED ) { \
idLib : : Printf ( " NET: " # msgType " , peer:%s not connected for " # sessionType_ " %i. \n " , peer . address . ToString ( ) , sessionType_ ) ; \
return ; \
}
# define VERIFY_CONNECTING_PEER( p, sessionType_, msgType ) \
if ( ! verify ( lobbyType = = sessionType_ ) ) { \
idLib : : Printf ( " NET: " # msgType " , peer:%s invalid session type for " # sessionType_ " %i. \n " , peer . address . ToString ( ) , sessionType_ ) ; \
return ; \
} \
if ( peers [ p ] . GetConnectionState ( ) ! = CONNECTION_CONNECTING ) { \
idLib : : Printf ( " NET: " # msgType " , peer:%s not connecting for " # sessionType_ " %i. \n " , peer . address . ToString ( ) , sessionType_ ) ; \
return ; \
}
# define VERIFY_FROM_HOST( p, sessionType_, msgType ) \
VERIFY_CONNECTED_PEER ( p , sessionType_ , msgType ) ; \
if ( p ! = host ) { \
idLib : : Printf ( " NET: " # msgType " , not from " # sessionType_ " host: %s \n " , peer . address . ToString ( ) ) ; \
return ; \
} \
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
# define VERIFY_FROM_CONNECTING_HOST( p, sessionType_, msgType ) \
VERIFY_CONNECTING_PEER ( p , sessionType_ , msgType ) ; \
if ( p ! = host ) { \
idLib : : Printf ( " NET: " # msgType " , not from " # sessionType_ " host: %s \n " , peer . address . ToString ( ) ) ; \
return ; \
} \
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : HandleHelloAck
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : HandleHelloAck ( int p , idBitMsg & msg )
{
peer_t & peer = peers [ p ] ;
if ( state ! = STATE_CONNECT_HELLO_WAIT )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " NET: Hello ack for session type %s while not waiting for hello. \n " , GetLobbyName ( ) ) ;
SendGoodbye ( peer . address ) ; // We send a customary goodbye to make sure we are not in their list anymore
return ;
}
2012-11-28 15:47:07 +00:00
if ( p ! = host )
{
2012-11-26 18:58:24 +00:00
// This shouldn't be possible
idLib : : Printf ( " NET: Hello ack for session type %s, not from correct host. \n " , GetLobbyName ( ) ) ;
SendGoodbye ( peer . address ) ; // We send a customary goodbye to make sure we are not in their list anymore
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
assert ( GetNumLobbyUsers ( ) = = 0 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Hello ack for session type %s from %s \n " , GetLobbyName ( ) , peer . address . ToString ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// We are now connected to this session type
SetPeerConnectionState ( p , CONNECTION_ESTABLISHED ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Obtain what our peer index is on the host is
peerIndexOnHost = msg . ReadLong ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If we connected to a party lobby, get the party token from the lobby owner
2012-11-28 15:47:07 +00:00
if ( lobbyType = = TYPE_PARTY )
{
2012-11-26 18:58:24 +00:00
partyToken = msg . ReadLong ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Read match parms
parms . Read ( msg ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Update lobbyBackend with parms
2012-11-28 15:47:07 +00:00
if ( lobbyBackend ! = NULL )
{
2012-11-26 18:58:24 +00:00
lobbyBackend - > UpdateMatchParms ( parms ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Populate the user list with the one from the host (which will also include our local users)
// This ensures the user lists are kept in sync
FreeAllUsers ( ) ;
AddUsersFromMsg ( msg , p ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Make sure the host has a current heartbeat
peer . lastHeartBeat = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lobbyBackend - > PostConnectFromMsg ( msg ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Tell the lobby controller to finalize the connection
SetState ( STATE_FINALIZE_CONNECT ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//
// Success - We've received an ack from the server, letting us know we've been registered with the lobbies
//
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetLobbyUserName
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
const char * idLobby : : GetLobbyUserName ( lobbyUserID_t lobbyUserID ) const
{
2012-11-26 18:58:24 +00:00
const int index = GetLobbyUserIndexByID ( lobbyUserID ) ;
2012-11-28 15:47:07 +00:00
const lobbyUser_t * user = GetLobbyUser ( index ) ;
if ( user = = NULL )
{
for ( int i = 0 ; i < disconnectedUsers . Num ( ) ; i + + )
{
if ( disconnectedUsers [ i ] . lobbyUserID . CompareIgnoreLobbyType ( lobbyUserID ) )
{
2012-11-26 18:58:24 +00:00
return disconnectedUsers [ i ] . gamertag ;
}
}
return INVALID_LOBBY_USER_NAME ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return user - > gamertag ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetLobbyUserSkinIndex
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : GetLobbyUserSkinIndex ( lobbyUserID_t lobbyUserID ) const
{
2012-11-26 18:58:24 +00:00
const int userIndex = GetLobbyUserIndexByID ( lobbyUserID ) ;
2012-11-28 15:47:07 +00:00
const lobbyUser_t * user = GetLobbyUser ( userIndex ) ;
2012-11-26 18:58:24 +00:00
return user ? user - > selectedSkin : 0 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetLobbyUserWeaponAutoSwitch
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : GetLobbyUserWeaponAutoSwitch ( lobbyUserID_t lobbyUserID ) const
{
2012-11-26 18:58:24 +00:00
const int userIndex = GetLobbyUserIndexByID ( lobbyUserID ) ;
2012-11-28 15:47:07 +00:00
const lobbyUser_t * user = GetLobbyUser ( userIndex ) ;
2012-11-26 18:58:24 +00:00
return user ? user - > weaponAutoSwitch : true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetLobbyUserWeaponAutoReload
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : GetLobbyUserWeaponAutoReload ( lobbyUserID_t lobbyUserID ) const
{
2012-11-26 18:58:24 +00:00
const int userIndex = GetLobbyUserIndexByID ( lobbyUserID ) ;
2012-11-28 15:47:07 +00:00
const lobbyUser_t * user = GetLobbyUser ( userIndex ) ;
return user ? user - > weaponAutoReload : true ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetLobbyUserLevel
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : GetLobbyUserLevel ( lobbyUserID_t lobbyUserID ) const
{
2012-11-26 18:58:24 +00:00
const int userIndex = GetLobbyUserIndexByID ( lobbyUserID ) ;
2012-11-28 15:47:07 +00:00
const lobbyUser_t * user = GetLobbyUser ( userIndex ) ;
2012-11-26 18:58:24 +00:00
return user ? user - > level : 0 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetLobbyUserQoS
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : GetLobbyUserQoS ( lobbyUserID_t lobbyUserID ) const
{
2012-11-26 18:58:24 +00:00
const int userIndex = GetLobbyUserIndexByID ( lobbyUserID ) ;
2012-11-28 15:47:07 +00:00
if ( IsHost ( ) & & IsSessionUserIndexLocal ( userIndex ) )
{
2012-11-26 18:58:24 +00:00
return 0 ; // Local users on the host of the active session have 0 ping
}
2012-11-28 15:47:07 +00:00
const lobbyUser_t * user = GetLobbyUser ( userIndex ) ;
if ( ! verify ( user ! = NULL ) )
{
2012-11-26 18:58:24 +00:00
return 0 ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return user - > pingMs ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetLobbyUserTeam
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : GetLobbyUserTeam ( lobbyUserID_t lobbyUserID ) const
{
2012-11-26 18:58:24 +00:00
const int userIndex = GetLobbyUserIndexByID ( lobbyUserID ) ;
2012-11-28 15:47:07 +00:00
const lobbyUser_t * user = GetLobbyUser ( userIndex ) ;
2012-11-26 18:58:24 +00:00
return user ? user - > teamNumber : 0 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SetLobbyUserTeam
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : SetLobbyUserTeam ( lobbyUserID_t lobbyUserID , int teamNumber )
{
2012-11-26 18:58:24 +00:00
const int userIndex = GetLobbyUserIndexByID ( lobbyUserID ) ;
2012-11-28 15:47:07 +00:00
lobbyUser_t * user = GetLobbyUser ( userIndex ) ;
if ( user ! = NULL )
{
if ( teamNumber ! = user - > teamNumber )
{
2012-11-26 18:58:24 +00:00
user - > teamNumber = teamNumber ;
2012-11-28 15:47:07 +00:00
if ( IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
byte buffer [ idPacketProcessor : : MAX_PACKET_SIZE - 2 ] ;
idBitMsg msg ( buffer , sizeof ( buffer ) ) ;
CreateUserUpdateMessage ( userIndex , msg ) ;
idBitMsg readMsg ;
readMsg . InitRead ( buffer , msg . GetSize ( ) ) ;
UpdateSessionUserOnPeers ( readMsg ) ;
}
return true ;
}
}
return false ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetLobbyUserPartyToken
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : GetLobbyUserPartyToken ( lobbyUserID_t lobbyUserID ) const
{
2012-11-26 18:58:24 +00:00
const int userIndex = GetLobbyUserIndexByID ( lobbyUserID ) ;
2012-11-28 15:47:07 +00:00
const lobbyUser_t * user = GetLobbyUser ( userIndex ) ;
2012-11-26 18:58:24 +00:00
return user ? user - > partyToken : 0 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetProfileFromLobbyUser
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idPlayerProfile * idLobby : : GetProfileFromLobbyUser ( lobbyUserID_t lobbyUserID )
{
2012-11-26 18:58:24 +00:00
const int userIndex = GetLobbyUserIndexByID ( lobbyUserID ) ;
2012-11-28 15:47:07 +00:00
idPlayerProfile * profile = NULL ;
idLocalUser * localUser = GetLocalUserFromLobbyUserIndex ( userIndex ) ;
if ( localUser ! = NULL )
{
2012-11-26 18:58:24 +00:00
profile = localUser - > GetProfile ( ) ;
}
2012-11-28 15:47:07 +00:00
if ( profile = = NULL )
{
2012-11-26 18:58:24 +00:00
// Whoops
profile = session - > GetSignInManager ( ) . GetDefaultProfile ( ) ;
//idLib::Warning( "Returning fake profile until the code is fixed to handle NULL profiles." );
}
return profile ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetLocalUserFromLobbyUser
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idLocalUser * idLobby : : GetLocalUserFromLobbyUser ( lobbyUserID_t lobbyUserID )
{
2012-11-26 18:58:24 +00:00
const int userIndex = GetLobbyUserIndexByID ( lobbyUserID ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return GetLocalUserFromLobbyUserIndex ( userIndex ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetNumLobbyUsersOnTeam
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : GetNumLobbyUsersOnTeam ( int teamNumber ) const
{
2012-11-26 18:58:24 +00:00
int numTeam = 0 ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < GetNumLobbyUsers ( ) ; + + i )
{
if ( GetLobbyUser ( i ) - > teamNumber = = teamNumber )
{
2012-11-26 18:58:24 +00:00
+ + numTeam ;
}
}
return numTeam ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetPeerName
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
const char * idLobby : : GetPeerName ( int peerNum ) const
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < GetNumLobbyUsers ( ) ; + + i )
{
if ( ! verify ( GetLobbyUser ( i ) ! = NULL ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( GetLobbyUser ( i ) - > peerIndex = = peerNum )
{
2012-11-26 18:58:24 +00:00
return GetLobbyUserName ( GetLobbyUser ( i ) - > lobbyUserID ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return INVALID_LOBBY_USER_NAME ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : HandleReliableMsg
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : HandleReliableMsg ( int p , idBitMsg & msg )
{
peer_t & peer = peers [ p ] ;
2012-11-26 18:58:24 +00:00
int reliableType = msg . ReadByte ( ) ;
//idLib::Printf(" Received reliable msg: %i \n", reliableType );
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const lobbyType_t actingGameStateLobbyType = GetActingGameStateLobbyType ( ) ;
2012-11-28 15:47:07 +00:00
if ( reliableType = = RELIABLE_HELLO )
{
2012-11-26 18:58:24 +00:00
VERIFY_FROM_CONNECTING_HOST ( p , lobbyType , RELIABLE_HELLO ) ;
// This is sent from the host acking a request to join the game lobby
HandleHelloAck ( p , msg ) ;
2012-11-28 15:47:07 +00:00
return ;
}
else if ( reliableType = = RELIABLE_USER_CONNECT_REQUEST )
{
2012-11-26 18:58:24 +00:00
VERIFY_CONNECTED_PEER ( p , lobbyType , RELIABLE_USER_CONNECT_REQUEST ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// This message is sent from a peer requesting for a new user to join the game lobby
// This will be sent while we are in a game lobby as a host. otherwise, denied.
NET_VERBOSE_PRINT ( " NET: RELIABLE_USER_CONNECT_REQUEST (%s) from %s \n " , GetLobbyName ( ) , peer . address . ToString ( ) ) ;
idSession : : sessionState_t expectedState = ( lobbyType = = TYPE_PARTY ) ? idSession : : PARTY_LOBBY : idSession : : GAME_LOBBY ;
2012-11-28 15:47:07 +00:00
if ( sessionCB - > GetState ( ) = = expectedState & & IsHost ( ) & & NumFreeSlots ( ) > 0 ) // This assumes only one user in the msg
{
2012-11-26 18:58:24 +00:00
// Add user to session, which will also forward the operation to all other peers
AddUsersFromMsg ( msg , p ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// Let peer know user couldn't be added
HandleUserConnectFailure ( p , msg , RELIABLE_USER_CONNECT_DENIED ) ;
}
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_USER_CONNECT_DENIED )
{
2012-11-26 18:58:24 +00:00
// This message is sent back from the host when a RELIABLE_PARTY_USER_CONNECT_REQUEST failed
VERIFY_FROM_HOST ( p , lobbyType , RELIABLE_PARTY_USER_CONNECT_DENIED ) ;
// Remove this user from the sign-in manager, so we don't keep trying to add them
2012-11-28 15:47:07 +00:00
if ( ! sessionCB - > GetSignInManager ( ) . RemoveLocalUserByHandle ( localUserHandle_t ( msg . ReadLong ( ) ) ) )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: RELIABLE_PARTY_USER_CONNECT_DENIED, local user not found \n " ) ;
return ;
}
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_KICK_PLAYER )
{
2012-11-26 18:58:24 +00:00
VERIFY_FROM_HOST ( p , lobbyType , RELIABLE_KICK_PLAYER ) ;
common - > Dialog ( ) . AddDialog ( GDM_KICKED , DIALOG_ACCEPT , NULL , NULL , false ) ;
2012-11-28 15:47:07 +00:00
if ( sessionCB - > GetPartyLobby ( ) . IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
session - > SetSessionOption ( idSession : : OPTION_LEAVE_WITH_PARTY ) ;
}
session - > Cancel ( ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_HEADSET_STATE )
{
2012-11-26 18:58:24 +00:00
HandleHeadsetStateChange ( p , msg ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_USER_CONNECTED )
{
2012-11-26 18:58:24 +00:00
// This message is sent back from the host when users have connected, and we need to update our lists to reflect that
VERIFY_FROM_HOST ( p , lobbyType , RELIABLE_USER_CONNECTED ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: RELIABLE_USER_CONNECTED (%s) from %s \n " , GetLobbyName ( ) , peer . address . ToString ( ) ) ;
AddUsersFromMsg ( msg , p ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_USER_DISCONNECTED )
{
2012-11-26 18:58:24 +00:00
// This message is sent back from the host when users have diconnected, and we need to update our lists to reflect that
VERIFY_FROM_HOST ( p , lobbyType , RELIABLE_USER_DISCONNECTED ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
ProcessUserDisconnectMsg ( msg ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_MATCH_PARMS )
{
2012-11-26 18:58:24 +00:00
parms . Read ( msg ) ;
// Update lobby with parms
2012-11-28 15:47:07 +00:00
if ( lobbyBackend ! = NULL )
{
2012-11-26 18:58:24 +00:00
lobbyBackend - > UpdateMatchParms ( parms ) ;
}
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_START_LOADING )
{
2012-11-26 18:58:24 +00:00
// This message is sent from the host to start loading a map
VERIFY_FROM_HOST ( p , actingGameStateLobbyType , RELIABLE_START_LOADING ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: RELIABLE_START_LOADING from %s \n " , peer . address . ToString ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
startLoadingFromHost = true ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_LOADING_DONE )
{
2012-11-26 18:58:24 +00:00
// This message is sent from the peers to state they are done loading the map
VERIFY_CONNECTED_PEER ( p , actingGameStateLobbyType , RELIABLE_LOADING_DONE ) ;
2012-11-28 15:47:07 +00:00
2012-12-11 22:04:53 +00:00
unsigned int networkChecksum = 0 ; // DG: use int instead of long for 64bit compatibility
2012-11-26 18:58:24 +00:00
networkChecksum = msg . ReadLong ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
peer . networkChecksum = networkChecksum ;
peer . loaded = true ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_IN_GAME )
{
2012-11-26 18:58:24 +00:00
VERIFY_CONNECTED_PEER ( p , actingGameStateLobbyType , RELIABLE_IN_GAME ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
peer . inGame = true ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_SNAPSHOT_ACK )
{
2012-11-26 18:58:24 +00:00
VERIFY_CONNECTED_PEER ( p , actingGameStateLobbyType , RELIABLE_SNAPSHOT_ACK ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// update our base state for his last received snapshot
int snapNum = msg . ReadLong ( ) ;
float receivedBps = msg . ReadQuantizedUFloat < BANDWIDTH_REPORTING_MAX , BANDWIDTH_REPORTING_BITS > ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Update reported received bps
2012-11-28 15:47:07 +00:00
if ( peer . receivedBpsIndex ! = snapNum )
{
2012-11-26 18:58:24 +00:00
// Only do this the first time we get reported bps per snapshot. Subsequent ACKs of the same shot will usually have lower reported bps
// due to more time elapsing but not receiving a new ss
peer . receivedBps = receivedBps ;
peer . receivedBpsIndex = snapNum ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
ApplySnapshotDelta ( p , snapNum ) ;
//idLib::Printf( "NET: Peer %d Ack'd snapshot %d\n", p, snapNum );
NET_VERBOSESNAPSHOT_PRINT_LEVEL ( 2 , va ( " NET: Peer %d Ack'd snapshot %d \n " , p , snapNum ) ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_RESOURCE_ACK )
{
}
else if ( reliableType = = RELIABLE_UPDATE_MATCH_PARMS )
{
2012-11-26 18:58:24 +00:00
VERIFY_CONNECTED_PEER ( p , TYPE_GAME , RELIABLE_UPDATE_MATCH_PARMS ) ;
int msgType = msg . ReadLong ( ) ;
sessionCB - > HandlePeerMatchParamUpdate ( p , msgType ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_MATCHFINISHED )
{
2012-11-26 18:58:24 +00:00
VERIFY_FROM_HOST ( p , actingGameStateLobbyType , RELIABLE_MATCHFINISHED ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
sessionCB - > ClearMigrationState ( ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_ENDMATCH )
{
2012-11-26 18:58:24 +00:00
VERIFY_FROM_HOST ( p , actingGameStateLobbyType , RELIABLE_ENDMATCH ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
sessionCB - > EndMatchInternal ( ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_ENDMATCH_PREMATURE )
{
VERIFY_FROM_HOST ( p , actingGameStateLobbyType , RELIABLE_ENDMATCH_PREMATURE ) ;
2012-11-26 18:58:24 +00:00
sessionCB - > EndMatchInternal ( true ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_START_MATCH_GAME_LOBBY_HOST )
{
2012-11-26 18:58:24 +00:00
// This message should be from the host of the game lobby, telling us (as the host of the GameStateLobby) to start loading
VERIFY_CONNECTED_PEER ( p , TYPE_GAME_STATE , RELIABLE_START_MATCH_GAME_LOBBY_HOST ) ;
2012-11-28 15:47:07 +00:00
if ( session - > GetState ( ) > = idSession : : LOADING )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: RELIABLE_START_MATCH_GAME_LOBBY_HOST already loading \n " ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Read match parms, and start loading
parms . Read ( msg ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Send these new match parms to currently connected peers
SendMatchParmsToPeers ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
startLoadingFromHost = true ; // Hijack this flag
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_ARBITRATE )
{
2012-11-26 18:58:24 +00:00
VERIFY_CONNECTED_PEER ( p , TYPE_GAME , RELIABLE_ARBITRATE ) ;
// Host telling us to arbitrate
// Set a flag to do this later, since the lobby may not be in a state where it can fulfil the request at the moment
respondToArbitrate = true ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_ARBITRATE_OK )
{
2012-11-26 18:58:24 +00:00
VERIFY_CONNECTED_PEER ( p , TYPE_GAME , RELIABLE_ARBITRATE_OK ) ;
NET_VERBOSE_PRINT ( " NET: Got an arbitration ok from %d \n " , p ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
everyoneArbitrated = true ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < GetNumLobbyUsers ( ) ; i + + )
{
lobbyUser_t * user = GetLobbyUser ( i ) ;
if ( ! verify ( user ! = NULL ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( user - > peerIndex = = p )
{
2012-11-26 18:58:24 +00:00
user - > arbitrationAcked = true ;
2012-11-28 15:47:07 +00:00
}
else if ( ! user - > arbitrationAcked )
{
2012-11-26 18:58:24 +00:00
everyoneArbitrated = false ;
}
}
2012-11-28 15:47:07 +00:00
if ( everyoneArbitrated )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Everyone says they registered for arbitration, verifying \n " ) ;
lobbyBackend - > Arbitrate ( ) ;
//sessionCB->EveryoneArbitrated();
return ;
}
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_POST_STATS )
{
2012-11-26 18:58:24 +00:00
VERIFY_FROM_HOST ( p , actingGameStateLobbyType , RELIABLE_POST_STATS ) ;
sessionCB - > RecvLeaderboardStats ( msg ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_SESSION_USER_MODIFIED )
{
2012-11-26 18:58:24 +00:00
VERIFY_CONNECTED_PEER ( p , lobbyType , RELIABLE_SESSION_USER_MODIFIED ) ;
UpdateSessionUserOnPeers ( msg ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_UPDATE_SESSION_USER )
{
2012-11-26 18:58:24 +00:00
VERIFY_FROM_HOST ( p , lobbyType , RELIABLE_UPDATE_SESSION_USER ) ;
HandleUpdateSessionUser ( msg ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_CONNECT_AND_MOVE_TO_LOBBY )
{
2012-11-26 18:58:24 +00:00
VERIFY_FROM_HOST ( p , lobbyType , RELIABLE_CONNECT_AND_MOVE_TO_LOBBY ) ;
NET_VERBOSE_PRINT ( " NET: RELIABLE_CONNECT_AND_MOVE_TO_LOBBY \n " ) ;
2012-11-28 15:47:07 +00:00
if ( IsHost ( ) )
{
idLib : : Printf ( " RELIABLE_CONNECT_AND_MOVE_TO_LOBBY: We are the host. \n " ) ;
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
// Get connection info
lobbyConnectInfo_t connectInfo ;
connectInfo . ReadFromMsg ( msg ) ;
2012-11-28 15:47:07 +00:00
const lobbyType_t destLobbyType = ( lobbyType_t ) msg . ReadByte ( ) ;
2012-11-26 18:58:24 +00:00
const bool waitForMembers = msg . ReadBool ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
assert ( destLobbyType > lobbyType ) ; // Make sure this is a proper transition (i.e. TYPE_PARTY moves to TYPE_GAME, TYPE_GAME moves to TYPE_GAME_STATE)
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
sessionCB - > ConnectAndMoveToLobby ( destLobbyType , connectInfo , waitForMembers ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_PARTY_CONNECT_OK )
{
2012-11-26 18:58:24 +00:00
VERIFY_FROM_HOST ( p , TYPE_PARTY , RELIABLE_PARTY_CONNECT_OK ) ;
2012-11-28 15:47:07 +00:00
if ( ! sessionCB - > GetGameLobby ( ) . waitForPartyOk )
{
idLib : : Printf ( " RELIABLE_PARTY_CONNECT_OK: Wasn't waiting for ok. \n " ) ;
2012-11-26 18:58:24 +00:00
}
sessionCB - > GetGameLobby ( ) . waitForPartyOk = false ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_PARTY_LEAVE_GAME_LOBBY )
{
2012-11-26 18:58:24 +00:00
VERIFY_FROM_HOST ( p , TYPE_PARTY , RELIABLE_PARTY_LEAVE_GAME_LOBBY ) ;
NET_VERBOSE_PRINT ( " NET: RELIABLE_PARTY_LEAVE_GAME_LOBBY \n " ) ;
2012-11-28 15:47:07 +00:00
if ( sessionCB - > GetState ( ) ! = idSession : : GAME_LOBBY )
{
idLib : : Printf ( " RELIABLE_PARTY_LEAVE_GAME_LOBBY: Not in a game lobby, ignoring. \n " ) ;
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( IsHost ( ) )
{
idLib : : Printf ( " RELIABLE_PARTY_LEAVE_GAME_LOBBY: Host of party, ignoring. \n " ) ;
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
sessionCB - > LeaveGameLobby ( ) ;
2012-11-28 15:47:07 +00:00
}
else if ( IsReliablePlayerToPlayerType ( reliableType ) )
{
2012-11-26 18:58:24 +00:00
HandleReliablePlayerToPlayerMsg ( p , msg , reliableType ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_PING )
{
2012-11-26 18:58:24 +00:00
HandleReliablePing ( p , msg ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_PING_VALUES )
{
2012-11-26 18:58:24 +00:00
HandlePingValues ( msg ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_BANDWIDTH_VALUES )
{
2012-11-26 18:58:24 +00:00
HandleBandwidhTestValue ( p , msg ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_MIGRATION_GAME_DATA )
{
2012-11-26 18:58:24 +00:00
HandleMigrationGameData ( msg ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType > = RELIABLE_GAME_DATA )
{
2012-11-26 18:58:24 +00:00
VERIFY_CONNECTED_PEER ( p , lobbyType , RELIABLE_GAME_DATA ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
common - > NetReceiveReliable ( p , reliableType - RELIABLE_GAME_DATA , msg ) ;
2012-11-28 15:47:07 +00:00
}
else if ( reliableType = = RELIABLE_DUMMY_MSG )
{
2012-11-26 18:58:24 +00:00
// Ignore dummy msg's
NET_VERBOSE_PRINT ( " NET: ignoring dummy msg from %s \n " , peer . address . ToString ( ) ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Unknown reliable packet type %d from %s \n " , reliableType , peer . address . ToString ( ) ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetTotalOutgoingRate
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : GetTotalOutgoingRate ( )
{
2012-11-26 18:58:24 +00:00
int totalSendRate = 0 ;
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
const 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
continue ;
}
2012-11-28 15:47:07 +00:00
const idPacketProcessor & proc = * peer . packetProc ;
2012-11-26 18:58:24 +00:00
totalSendRate + = proc . GetOutgoingRateBytes ( ) ;
}
return totalSendRate ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : DrawDebugNetworkHUD
= = = = = = = = = = = = = = = = = = = = = = = =
*/
extern idCVar net_forceUpstream ;
2012-11-28 15:47:07 +00:00
void idLobby : : DrawDebugNetworkHUD ( ) const
{
2012-11-26 18:58:24 +00:00
int totalSendRate = 0 ;
int totalRecvRate = 0 ;
float totalSentMB = 0.0f ;
float totalRecvMB = 0.0f ;
const float Y_OFFSET = 20.0f ;
const float X_OFFSET = 20.0f ;
const float Y_SPACING = 15.0f ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float curY = Y_OFFSET ;
2012-11-28 15:47:07 +00:00
int numLines = ( net_forceUpstream . GetFloat ( ) ! = 0.0f ? 6 : 5 ) ;
2012-11-26 18:58:24 +00:00
renderSystem - > DrawFilled ( idVec4 ( 0.0f , 0.0f , 0.0f , 0.7f ) , X_OFFSET - 10.0f , curY - 10.0f , 1550 , ( peers . Num ( ) + numLines ) * Y_SPACING + 20.0f ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderSystem - > DrawSmallStringExt ( idMath : : Ftoi ( X_OFFSET ) , idMath : : Ftoi ( curY ) , " # Peer | Sent kB/s | Recv kB/s | Sent MB | Recv MB | Ping | L | % | R.NM | R.SZ | R.AK | T " , colorGreen , false ) ;
curY + = Y_SPACING ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderSystem - > DrawSmallStringExt ( idMath : : Ftoi ( X_OFFSET ) , idMath : : Ftoi ( curY ) , " ------------------------------------------------------------------------------------------------------------------------------------ " , colorGreen , false ) ;
curY + = Y_SPACING ;
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
const 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
continue ;
}
2012-11-28 15:47:07 +00:00
const idPacketProcessor & proc = * peer . packetProc ;
2012-11-26 18:58:24 +00:00
totalSendRate + = proc . GetOutgoingRateBytes ( ) ;
totalRecvRate + = proc . GetIncomingRateBytes ( ) ;
2012-11-28 15:47:07 +00:00
float sentKps = ( float ) proc . GetOutgoingRateBytes ( ) / 1024.0f ;
float recvKps = ( float ) proc . GetIncomingRateBytes ( ) / 1024.0f ;
float sentMB = ( float ) proc . GetOutgoingBytes ( ) / ( 1024.0f * 1024.0f ) ;
float recvMB = ( float ) proc . GetIncomingBytes ( ) / ( 1024.0f * 1024.0f ) ;
2012-11-26 18:58:24 +00:00
totalSentMB + = sentMB ;
totalRecvMB + = recvMB ;
idVec4 color = sentKps > 20.0f ? colorRed : colorGreen ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int resourcePercent = 0 ;
idStr name = peer . address . ToString ( ) ;
2012-11-28 15:47:07 +00:00
name + = lobbyType = = TYPE_PARTY ? " (P " : " (G " ;
2012-11-26 18:58:24 +00:00
name + = host = = p ? " :H) " : " :C) " ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderSystem - > DrawSmallStringExt ( X_OFFSET , curY , va ( " %i %22s | %2.02f kB/s | %2.02f kB/s | %2.02f MB | %2.02f MB |%4i ms | %i | %i%% | %i | %i | %i | %2.2f / %2.2f / %i " , p , name . c_str ( ) , sentKps , recvKps , sentMB , recvMB , peer . lastPingRtt , peer . loaded , resourcePercent , peer . packetProc - > NumQueuedReliables ( ) , peer . packetProc - > GetReliableDataSize ( ) , peer . packetProc - > NeedToSendReliableAck ( ) , peer . snapHz , peer . maxSnapBps , peer . failedPingRecoveries ) , color , false ) ;
curY + = Y_SPACING ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderSystem - > DrawSmallStringExt ( idMath : : Ftoi ( X_OFFSET ) , idMath : : Ftoi ( curY ) , " ------------------------------------------------------------------------------------------------------------------------------------ " , colorGreen , false ) ;
curY + = Y_SPACING ;
2012-11-28 15:47:07 +00:00
float totalSentKps = ( float ) totalSendRate / 1024.0f ;
float totalRecvKps = ( float ) totalRecvRate / 1024.0f ;
2012-11-26 18:58:24 +00:00
idVec4 color = totalSentKps > 100.0f ? colorRed : colorGreen ;
renderSystem - > DrawSmallStringExt ( X_OFFSET , curY , va ( " # %20s | %2.02f KB/s | %2.02f KB/s | %2.02f MB | %2.02f MB " , " " , totalSentKps , totalRecvKps , totalSentMB , totalRecvMB ) , color , false ) ;
curY + = Y_SPACING ;
2012-11-28 15:47:07 +00:00
if ( net_forceUpstream . GetFloat ( ) ! = 0.0f )
{
2012-11-26 18:58:24 +00:00
float upstreamDropRate = session - > GetUpstreamDropRate ( ) ;
float upstreamQueuedRate = session - > GetUpstreamQueueRate ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int queuedBytes = session - > GetQueuedBytes ( ) ;
renderSystem - > DrawSmallStringExt ( X_OFFSET , curY , va ( " Queued: %d | Dropping: %2.02f kB/s Queue: %2.02f kB/s -> Effective %2.02f kB/s " , queuedBytes , upstreamDropRate / 1024.0f , upstreamQueuedRate / 1024.0f , totalSentKps - ( upstreamDropRate / 1024.0f ) + ( upstreamQueuedRate / 1024.0f ) ) , color , false ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : DrawDebugNetworkHUD2
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : DrawDebugNetworkHUD2 ( ) const
{
2012-11-26 18:58:24 +00:00
int totalSendRate = 0 ;
int totalRecvRate = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const float Y_OFFSET = 20.0f ;
const float X_OFFSET = 20.0f ;
const float Y_SPACING = 15.0f ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float curY = Y_OFFSET ;
2012-11-28 15:47:07 +00:00
renderSystem - > DrawFilled ( idVec4 ( 0.0f , 0.0f , 0.0f , 0.7f ) , X_OFFSET - 10.0f , curY - 10.0f , 550 , ( peers . Num ( ) + 4 ) * Y_SPACING + 20.0f ) ;
2012-11-26 18:58:24 +00:00
const char * stateName = session - > GetStateString ( ) ;
2012-11-28 15:47:07 +00:00
renderSystem - > DrawFilled ( idVec4 ( 1.0f , 1.0f , 1.0f , 0.7f ) , X_OFFSET - 10.0f , curY - 10.0f , 550 , ( peers . Num ( ) + 5 ) * Y_SPACING + 20.0f ) ;
renderSystem - > DrawSmallStringExt ( idMath : : Ftoi ( X_OFFSET ) , idMath : : Ftoi ( curY ) , va ( " State: %s. Local time: %d " , stateName , Sys_Milliseconds ( ) ) , colorGreen , false ) ;
2012-11-26 18:58:24 +00:00
curY + = Y_SPACING ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderSystem - > DrawSmallStringExt ( idMath : : Ftoi ( X_OFFSET ) , idMath : : Ftoi ( curY ) , " Peer | Sent kB/s | Recv kB/s | L | R | Resources " , colorGreen , false ) ;
curY + = Y_SPACING ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderSystem - > DrawSmallStringExt ( idMath : : Ftoi ( X_OFFSET ) , idMath : : Ftoi ( curY ) , " ------------------------------------------------------------------ " , colorGreen , false ) ;
curY + = Y_SPACING ;
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
if ( ! peers [ p ] . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
idPacketProcessor & proc = * peers [ p ] . packetProc ;
2012-11-26 18:58:24 +00:00
totalSendRate + = proc . GetOutgoingRate2 ( ) ;
totalRecvRate + = proc . GetIncomingRate2 ( ) ;
float sentKps = ( float ) proc . GetOutgoingRate2 ( ) / 1024.0f ;
float recvKps = ( float ) proc . GetIncomingRate2 ( ) / 1024.0f ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// should probably complement that with a bandwidth reading
// right now I am mostly concerned about fragmentation and the latency spikes it will cause
idVec4 color = proc . TickFragmentAccumulator ( ) ? colorRed : colorGreen ;
int rLoaded = peers [ p ] . numResources ;
int rTotal = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// show the names of the clients connected to the server. Also make sure it looks reasonably good.
idStr peerName ;
2012-11-28 15:47:07 +00:00
if ( IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
peerName = GetPeerName ( p ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int MAX_PEERNAME_LENGTH = 10 ;
int nameLength = peerName . Length ( ) ;
2012-11-28 15:47:07 +00:00
if ( nameLength > MAX_PEERNAME_LENGTH )
{
2012-11-26 18:58:24 +00:00
peerName = peerName . Left ( MAX_PEERNAME_LENGTH ) ;
2012-11-28 15:47:07 +00:00
}
else if ( nameLength < MAX_PEERNAME_LENGTH )
{
2012-11-26 18:58:24 +00:00
idStr filler ;
filler . Fill ( ' ' , MAX_PEERNAME_LENGTH ) ;
peerName + = filler . Left ( MAX_PEERNAME_LENGTH - nameLength ) ;
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
peerName = " Local " ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderSystem - > DrawSmallStringExt ( X_OFFSET , curY , va ( " %i - %s | %2.02f kB/s | %2.02f kB/s | %i | %i | %d/%d " , p , peerName . c_str ( ) , sentKps , recvKps , peers [ p ] . loaded , peers [ p ] . address . UsingRelay ( ) , rLoaded , rTotal ) , color , false ) ;
curY + = Y_SPACING ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderSystem - > DrawSmallStringExt ( idMath : : Ftoi ( X_OFFSET ) , idMath : : Ftoi ( curY ) , " ------------------------------------------------------------------ " , colorGreen , false ) ;
curY + = Y_SPACING ;
2012-11-28 15:47:07 +00:00
float totalSentKps = ( float ) totalSendRate / 1024.0f ;
float totalRecvKps = ( float ) totalRecvRate / 1024.0f ;
2012-11-26 18:58:24 +00:00
renderSystem - > DrawSmallStringExt ( X_OFFSET , curY , va ( " Total | %2.02f KB/s | %2.02f KB/s " , totalSentKps , totalRecvKps ) , colorGreen , false ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : DrawDebugNetworkHUD_ServerSnapshotMetrics
= = = = = = = = = = = = = = = = = = = = = = = =
*/
idCVar net_debughud3_bps_max ( " net_debughud3_bps_max " , " 5120.0f " , CVAR_FLOAT , " Highest factor of server base snapRate that a client can be throttled " ) ;
2012-11-28 15:47:07 +00:00
void idLobby : : DrawDebugNetworkHUD_ServerSnapshotMetrics ( bool draw )
{
2012-11-26 18:58:24 +00:00
const float Y_OFFSET = 20.0f ;
const float X_OFFSET = 20.0f ;
const float Y_SPACING = 15.0f ;
idVec4 color = colorWhite ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float curY = Y_OFFSET ;
2012-11-28 15:47:07 +00:00
if ( ! draw )
{
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
for ( int i = 0 ; i < peers [ p ] . debugGraphs . Num ( ) ; i + + )
{
if ( peers [ p ] . debugGraphs [ i ] ! = NULL )
{
2012-11-26 18:58:24 +00:00
peers [ p ] . debugGraphs [ i ] - > Enable ( false ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
return ;
}
}
}
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
static int lastTime = 0 ;
int time = Sys_Milliseconds ( ) ;
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
idPacketProcessor * packetProc = peer . packetProc ;
idSnapshotProcessor * snapProc = peer . snapProc ;
if ( ! verify ( packetProc ! = NULL & & snapProc ! = NULL ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int snapSeq = snapProc - > GetSnapSequence ( ) ;
int snapBase = snapProc - > GetBaseSequence ( ) ;
int deltaSeq = snapSeq - snapBase ;
bool throttled = peer . throttledSnapRate > common - > GetSnapRate ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int numLines = net_forceUpstream . GetBool ( ) ? 5 : 4 ;
2012-11-28 15:47:07 +00:00
const int width = renderSystem - > GetWidth ( ) / 2.0f - ( X_OFFSET * 2 ) ;
enum netDebugGraphs_t
{
2012-11-26 18:58:24 +00:00
GRAPH_SNAPSENT ,
GRAPH_OUTGOING ,
GRAPH_INCOMINGREPORTED ,
GRAPH_MAX
} ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
peer . debugGraphs . SetNum ( GRAPH_MAX , NULL ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < GRAPH_MAX ; i + + )
{
// Initialize graphs
if ( peer . debugGraphs [ i ] = = NULL )
{
2012-11-26 18:58:24 +00:00
peer . debugGraphs [ i ] = console - > CreateGraph ( 500 ) ;
2012-11-28 15:47:07 +00:00
if ( ! verify ( peer . debugGraphs [ i ] ! = NULL ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
peer . debugGraphs [ i ] - > SetPosition ( X_OFFSET - 10.0f + width , curY - 10.0f , width , Y_SPACING * numLines ) ;
}
2012-11-28 15:47:07 +00:00
peer . debugGraphs [ i ] - > Enable ( true ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderSystem - > DrawFilled ( idVec4 ( 0.0f , 0.0f , 0.0f , 0.7f ) , X_OFFSET - 10.0f , curY - 10.0f , width , ( Y_SPACING * numLines ) + 20.0f ) ;
2012-11-28 15:47:07 +00:00
renderSystem - > DrawSmallStringExt ( X_OFFSET , curY , va ( " Peer %d - %s RTT %d %sPeerSnapRate: %d %s " , p , GetPeerName ( p ) , peer . lastPingRtt , throttled ? " ^1 " : " ^2 " , peer . throttledSnapRate / 1000 , throttled ? " ^1Throttled " : " " ) , color , false ) ;
2012-11-26 18:58:24 +00:00
curY + = Y_SPACING ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderSystem - > DrawSmallStringExt ( X_OFFSET , curY , va ( " SnapSeq %d BaseSeq %d Delta %d Queue %d " , snapSeq , snapBase , deltaSeq , snapProc - > GetSnapQueueSize ( ) ) , color , false ) ;
curY + = Y_SPACING ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderSystem - > DrawSmallStringExt ( X_OFFSET , curY , va ( " Reliables: %d / %d bytes Reliable Ack: %d " , packetProc - > NumQueuedReliables ( ) , packetProc - > GetReliableDataSize ( ) , packetProc - > NeedToSendReliableAck ( ) ) , color , false ) ;
curY + = Y_SPACING ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
renderSystem - > DrawSmallStringExt ( X_OFFSET , curY , va ( " Outgoing %.2f kB/s Reported %.2f kB/s Throttle: %.2f " , peer . packetProc - > GetOutgoingRateBytes ( ) / 1024.0f , peers [ p ] . receivedBps / 1024.0f , peer . receivedThrottle ) , color , false ) ;
curY + = Y_SPACING ;
2012-11-28 15:47:07 +00:00
if ( net_forceUpstream . GetFloat ( ) ! = 0.0f )
{
2012-11-26 18:58:24 +00:00
float upstreamDropRate = session - > GetUpstreamDropRate ( ) ;
float upstreamQueuedRate = session - > GetUpstreamQueueRate ( ) ;
int queuedBytes = session - > GetQueuedBytes ( ) ;
renderSystem - > DrawSmallStringExt ( X_OFFSET , curY , va ( " Queued: %d | Dropping: %2.02f kB/s Queue: %2.02f kB/s " , queuedBytes , upstreamDropRate / 1024.0f , upstreamQueuedRate / 1024.0f ) , color , false ) ;
}
2012-11-28 15:47:07 +00:00
curY + = Y_SPACING ;
if ( peer . debugGraphs [ GRAPH_SNAPSENT ] ! = NULL )
{
if ( peer . lastSnapTime > lastTime )
{
peer . debugGraphs [ GRAPH_SNAPSENT ] - > SetValue ( - 1 , 1.0f , colorBlue ) ;
}
else
{
peer . debugGraphs [ GRAPH_SNAPSENT ] - > SetValue ( - 1 , 0.0f , colorBlue ) ;
2012-11-26 18:58:24 +00:00
}
}
2012-11-28 15:47:07 +00:00
if ( peer . debugGraphs [ GRAPH_OUTGOING ] ! = NULL )
{
2012-11-26 18:58:24 +00:00
idVec4 bgColor ( vec4_zero ) ;
peer . debugGraphs [ GRAPH_OUTGOING ] - > SetBackgroundColor ( bgColor ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idVec4 lineColor = colorLtGrey ;
lineColor . w = 0.5f ;
float outgoingRate = peer . sentBpsHistory [ peer . receivedBpsIndex % MAX_BPS_HISTORY ] ;
// peer.packetProc->GetOutgoingRateBytes()
2012-11-28 15:47:07 +00:00
peer . debugGraphs [ GRAPH_OUTGOING ] - > SetValue ( - 1 , idMath : : ClampFloat ( 0.0f , 1.0f , outgoingRate / net_debughud3_bps_max . GetFloat ( ) ) , lineColor ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
if ( peer . debugGraphs [ GRAPH_INCOMINGREPORTED ] ! = NULL )
{
2012-11-26 18:58:24 +00:00
idVec4 lineColor = colorYellow ;
extern idCVar net_peer_throttle_bps_peer_threshold_pct ;
extern idCVar net_peer_throttle_bps_host_threshold ;
2012-11-28 15:47:07 +00:00
if ( peer . packetProc - > GetOutgoingRateBytes ( ) > net_peer_throttle_bps_host_threshold . GetFloat ( ) )
{
2012-11-26 18:58:24 +00:00
float pct = peer . packetProc - > GetOutgoingRateBytes ( ) > 0.0f ? peer . receivedBps / peer . packetProc - > GetOutgoingRateBytes ( ) : 0.0f ;
2012-11-28 15:47:07 +00:00
if ( pct < net_peer_throttle_bps_peer_threshold_pct . GetFloat ( ) )
{
2012-11-26 18:58:24 +00:00
lineColor = colorRed ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
lineColor = colorGreen ;
}
}
idVec4 bgColor ( vec4_zero ) ;
peer . debugGraphs [ GRAPH_INCOMINGREPORTED ] - > SetBackgroundColor ( bgColor ) ;
peer . debugGraphs [ GRAPH_INCOMINGREPORTED ] - > SetFillMode ( idDebugGraph : : GRAPH_LINE ) ;
2012-11-28 15:47:07 +00:00
peer . debugGraphs [ GRAPH_INCOMINGREPORTED ] - > SetValue ( - 1 , idMath : : ClampFloat ( 0.0f , 1.0f , peer . receivedBps / net_debughud3_bps_max . GetFloat ( ) ) , lineColor ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Skip down
2012-11-28 15:47:07 +00:00
curY + = ( Y_SPACING * 2.0f ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lastTime = time ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : CheckHeartBeats
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : CheckHeartBeats ( )
{
2012-11-26 18:58:24 +00:00
// Disconnect peers that haven't responded within net_peerTimeoutInSeconds
int time = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int timeoutInMs = session - > GetTitleStorageInt ( " net_peerTimeoutInSeconds " , net_peerTimeoutInSeconds . GetInteger ( ) ) * 1000 ;
2012-11-28 15:47:07 +00:00
if ( sessionCB - > GetState ( ) < idSession : : LOADING & & migrationInfo . state = = MIGRATE_NONE )
{
2012-11-26 18:58:24 +00:00
// Use shorter timeout in lobby (TCR)
timeoutInMs = session - > GetTitleStorageInt ( " net_peerTimeoutInSeconds_Lobby " , net_peerTimeoutInSeconds_Lobby . GetInteger ( ) ) * 1000 ;
}
2012-11-28 15:47:07 +00:00
if ( timeoutInMs > 0 )
{
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
if ( peers [ p ] . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
bool peerTimeout = false ;
2012-11-28 15:47:07 +00:00
if ( time - peers [ p ] . lastHeartBeat > timeoutInMs )
{
2012-11-26 18:58:24 +00:00
peerTimeout = true ;
}
2012-11-28 15:47:07 +00:00
// if reliable queue is almost full, disconnect the peer.
// (this seems reasonable since the reliable queue is set to 64 currently. In practice we should never
2012-11-26 18:58:24 +00:00
// have more than 3 or 4 queued)
2012-11-28 15:47:07 +00:00
if ( peers [ p ] . packetProc - > NumQueuedReliables ( ) > idPacketProcessor : : MAX_RELIABLE_QUEUE - 1 )
{
2012-11-26 18:58:24 +00:00
peerTimeout = true ;
}
2012-11-28 15:47:07 +00:00
if ( peerTimeout )
{
2012-11-26 18:58:24 +00:00
// Disconnect the peer from any sessions we are a host of
2012-11-28 15:47:07 +00:00
if ( IsHost ( ) )
{
idLib : : Printf ( " Peer %i timed out for %s session @ %d (lastHeartBeat %d) \n " , p , GetLobbyName ( ) , time , peers [ p ] . lastHeartBeat ) ;
2012-11-26 18:58:24 +00:00
DisconnectPeerFromSession ( p ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Handle peers not receiving a heartbeat from the host in awhile
2012-11-28 15:47:07 +00:00
if ( IsPeer ( ) )
{
if ( migrationInfo . state ! = MIGRATE_PICKING_HOST )
{
idLib : : Printf ( " Host timed out for %s session \n " , GetLobbyName ( ) ) ;
2012-11-26 18:58:24 +00:00
// Pick a host for this session
PickNewHost ( ) ;
}
}
}
}
}
}
2012-11-28 15:47:07 +00:00
if ( IsHost ( ) & & lobbyType = = GetActingGameStateLobbyType ( ) )
{
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
if ( ! peers [ p ] . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
CheckPeerThrottle ( p ) ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : CheckHeartBeats
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : IsLosingConnectionToHost ( ) const
{
if ( ! verify ( IsPeer ( ) & & host > = 0 & & host < peers . Num ( ) ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( ! peers [ host ] . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
return true ;
}
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 timeoutInMs = session - > GetTitleStorageInt ( " net_peerTimeoutInSeconds " , net_peerTimeoutInSeconds . GetInteger ( ) ) * 1000 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// return true if heartbeat > half the timeout length
2012-11-28 15:47:07 +00:00
if ( timeoutInMs > 0 & & time - peers [ host ] . lastHeartBeat > timeoutInMs / 2 )
{
2012-11-26 18:58:24 +00:00
return true ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// return true if reliable queue is more than half full
2012-11-28 15:47:07 +00:00
// (this seems reasonable since the reliable queue is set to 64 currently. In practice we should never
2012-11-26 18:58:24 +00:00
// have more than 3 or 4 queued)
2012-11-28 15:47:07 +00:00
if ( peers [ host ] . packetProc - > NumQueuedReliables ( ) > idPacketProcessor : : MAX_RELIABLE_QUEUE / 2 )
{
2012-11-26 18:58:24 +00:00
return true ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return false ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : IsMigratedStatsGame
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : IsMigratedStatsGame ( ) const
{
if ( ! IsLobbyActive ( ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( lobbyType ! = TYPE_GAME )
{
2012-11-26 18:58:24 +00:00
return false ; // Only game session migrates games stats
}
2012-11-28 15:47:07 +00:00
if ( ! MatchTypeHasStats ( parms . matchFlags ) )
{
2012-11-26 18:58:24 +00:00
return false ; // Only stats games migrate stats
}
2012-11-28 15:47:07 +00:00
if ( ! MatchTypeIsRanked ( parms . matchFlags ) )
{
2012-11-26 18:58:24 +00:00
return false ; // Only ranked games should migrate stats into new game
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return migrationInfo . persistUntilGameEndsData . wasMigratedGame & & migrationInfo . persistUntilGameEndsData . hasGameData ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : ShouldRelaunchMigrationGame
returns true if we are hosting a migrated game and we had valid migration data
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : ShouldRelaunchMigrationGame ( ) const
{
if ( IsMigrating ( ) )
{
2012-11-26 18:58:24 +00:00
return false ; // Don't relaunch until all clients have reconnected
}
2012-11-28 15:47:07 +00:00
if ( ! IsMigratedStatsGame ( ) )
{
2012-11-26 18:58:24 +00:00
return false ; // If we are not migrating stats, we don't want to relaunch a new game
}
2012-11-28 15:47:07 +00:00
if ( ! migrationInfo . persistUntilGameEndsData . wasMigratedHost )
{
2012-11-26 18:58:24 +00:00
return false ; // Only relaunch if we are the host
}
2012-11-28 15:47:07 +00:00
if ( migrationInfo . persistUntilGameEndsData . hasRelaunchedMigratedGame )
{
2012-11-26 18:58:24 +00:00
return false ; // We already relaunched this game
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : ShouldShowMigratingDialog
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : ShouldShowMigratingDialog ( ) const
{
if ( IsMigrating ( ) )
{
2012-11-26 18:58:24 +00:00
return true ; // If we are in the process of truly migrating, then definitely return true
}
2012-11-28 15:47:07 +00:00
if ( sessionCB - > GetState ( ) = = idSession : : INGAME )
{
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
// We're either waiting on the server (which could be us) to relaunch, so show the dialog
return IsMigratedStatsGame ( ) & & sessionCB - > GetState ( ) ! = idSession : : INGAME ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : IsMigrating
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : IsMigrating ( ) const
{
2012-11-26 18:58:24 +00:00
return migrationInfo . state ! = idLobby : : MIGRATE_NONE ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : PingPeers
Host only .
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : PingPeers ( )
{
if ( ! verify ( IsHost ( ) ) )
{
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 int now = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
pktPing_t packet ;
memset ( & packet , 0 , sizeof ( packet ) ) ; // We're gonna memset like it's 1999.
packet . timestamp = now ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
byte packetCopy [ sizeof ( packet ) ] ;
idBitMsg msg ( packetCopy , sizeof ( packetCopy ) ) ;
msg . WriteLong ( packet . timestamp ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < peers . Num ( ) ; + + i )
{
peer_t & peer = peers [ i ] ;
if ( ! peer . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( peer . nextPing < = now )
{
2012-11-26 18:58:24 +00:00
peer . nextPing = now + PING_INTERVAL_MS ;
QueueReliableMessage ( i , RELIABLE_PING , msg . GetReadData ( ) , msg . GetSize ( ) ) ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : ThrottlePeerSnapRate
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : ThrottlePeerSnapRate ( int p )
{
if ( ! verify ( IsHost ( ) ) | | ! verify ( p > = 0 ) )
{
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
peers [ p ] . throttledSnapRate = common - > GetSnapRate ( ) * 2 ;
2012-11-28 15:47:07 +00:00
idLib : : Printf ( " ^1Throttling peer %d %s! \n " , p , GetPeerName ( p ) ) ;
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " New snaprate: %d \n " , peers [ p ] . throttledSnapRate / 1000 ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SaturatePeers
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : BeginBandwidthTest ( )
{
if ( ! verify ( IsHost ( ) ) )
{
idLib : : Warning ( " Bandwidth test should only be done on host " ) ;
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( bandwidthChallengeStartTime > 0 )
{
idLib : : Warning ( " Already started bandwidth test " ) ;
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 ( ) ;
bandwidthChallengeStartTime = time ;
bandwidthChallengeEndTime = 0 ;
bandwidthChallengeFinished = false ;
bandwidthChallengeNumGoodSeq = 0 ;
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; + + p )
{
if ( ! peers [ p ] . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( ! verify ( peers [ p ] . packetProc ! = NULL ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
peers [ p ] . bandwidthSequenceNum = 0 ;
peers [ p ] . bandwidthChallengeStartSendTime = 0 ;
peers [ p ] . bandwidthChallengeResults = false ;
peers [ p ] . bandwidthChallengeSendComplete = false ;
peers [ p ] . bandwidthTestBytes = peers [ p ] . packetProc - > GetOutgoingBytes ( ) ; // cache this off so we can see the difference when we are done
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SaturatePeers
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : BandwidthTestStarted ( )
{
2012-11-26 18:58:24 +00:00
return bandwidthChallengeStartTime ! = 0 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : ServerUpdateBandwidthTest
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : ServerUpdateBandwidthTest ( )
{
if ( bandwidthChallengeStartTime < = 0 )
{
2012-11-26 18:58:24 +00:00
// Not doing a test
return ;
}
2012-11-28 15:47:07 +00:00
if ( ! verify ( IsHost ( ) ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
int time = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
if ( bandwidthChallengeFinished )
{
2012-11-26 18:58:24 +00:00
// test is over
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idRandom random ;
random . SetSeed ( time ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bool sentAll = true ;
bool recAll = true ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < peers . Num ( ) ; + + i )
{
peer_t & peer = peers [ i ] ;
if ( ! peer . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( peer . bandwidthChallengeResults )
{
2012-11-26 18:58:24 +00:00
continue ;
}
recAll = false ;
2012-11-28 15:47:07 +00:00
if ( peer . bandwidthChallengeSendComplete )
{
2012-11-26 18:58:24 +00:00
continue ;
}
sentAll = false ;
2012-11-28 15:47:07 +00:00
if ( time - peer . bandwidthTestLastSendTime < session - > GetTitleStorageInt ( " net_bw_test_interval " , net_bw_test_interval . GetInteger ( ) ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( peer . packetProc - > HasMoreFragments ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( peer . bandwidthChallengeStartSendTime = = 0 )
{
2012-11-26 18:58:24 +00:00
peer . bandwidthChallengeStartSendTime = time ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
peer . bandwidthTestLastSendTime = time ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Ok, send him a big packet
byte buffer [ idPacketProcessor : : MAX_OOB_MSG_SIZE ] ; // <---- NOTE - When calling ProcessOutgoingMsg with true for oob, we can't go over this size
2012-11-28 15:47:07 +00:00
idBitMsg msg ( buffer , sizeof ( buffer ) ) ;
2012-11-26 18:58:24 +00:00
msg . WriteLong ( peer . bandwidthSequenceNum + + ) ;
2012-11-28 15:47:07 +00:00
unsigned int randomSize = Min ( ( unsigned int ) ( sizeof ( buffer ) - 12 ) , ( unsigned int ) session - > GetTitleStorageInt ( " net_bw_test_packetSizeBytes " , net_bw_test_packetSizeBytes . GetInteger ( ) ) ) ;
2012-11-26 18:58:24 +00:00
msg . WriteLong ( randomSize ) ;
2012-11-28 15:47:07 +00:00
for ( unsigned int j = 0 ; j < randomSize ; j + + )
{
2012-11-26 18:58:24 +00:00
msg . WriteByte ( random . RandomInt ( 255 ) ) ;
}
unsigned int checksum = MD5_BlockChecksum ( & buffer [ 8 ] , randomSize ) ;
msg . WriteLong ( checksum ) ;
2012-11-28 15:47:07 +00:00
NET_VERBOSE_PRINT ( " Net: Sending bw challenge to peer %d time %d packet size %d \n " , i , time , msg . GetSize ( ) ) ;
2012-11-26 18:58:24 +00:00
ProcessOutgoingMsg ( i , buffer , msg . GetSize ( ) , true , OOB_BANDWIDTH_TEST ) ;
2012-11-28 15:47:07 +00:00
if ( session - > GetTitleStorageInt ( " net_bw_test_numPackets " , net_bw_test_numPackets . GetInteger ( ) ) > 0 & & peer . bandwidthSequenceNum > = net_bw_test_numPackets . GetInteger ( ) )
{
2012-11-26 18:58:24 +00:00
int sentBytes = peers [ i ] . packetProc - > GetOutgoingBytes ( ) - peers [ i ] . bandwidthTestBytes ; // FIXME: this won't include the last sent msg
peers [ i ] . bandwidthTestBytes = sentBytes ; // this now means total bytes sent (we don't care about starting/ending total bytes sent to peer)
peers [ i ] . bandwidthChallengeSendComplete = true ;
2012-11-28 15:47:07 +00:00
NET_VERBOSE_PRINT ( " Sent enough packets to peer %d for bandwidth test in %dms. Total bytes: %d \n " , i , time - bandwidthChallengeStartTime , sentBytes ) ;
2012-11-26 18:58:24 +00:00
}
}
2012-11-28 15:47:07 +00:00
if ( sentAll )
{
if ( bandwidthChallengeEndTime = = 0 )
{
2012-11-26 18:58:24 +00:00
// We finished sending all our packets, set the timeout time
bandwidthChallengeEndTime = time + session - > GetTitleStorageInt ( " net_bw_test_host_timeout " , net_bw_test_host_timeout . GetInteger ( ) ) ;
2012-11-28 15:47:07 +00:00
NET_VERBOSE_PRINT ( " Net: finished sending BWC to peers. Waiting until %d to hear back \n " , bandwidthChallengeEndTime ) ;
2012-11-26 18:58:24 +00:00
}
}
2012-11-28 15:47:07 +00:00
if ( recAll )
{
2012-11-26 18:58:24 +00:00
bandwidthChallengeFinished = true ;
bandwidthChallengeStartTime = 0 ;
2012-11-28 15:47:07 +00:00
}
else if ( bandwidthChallengeEndTime ! = 0 & & bandwidthChallengeEndTime < time )
{
2012-11-26 18:58:24 +00:00
// Timed out waiting for someone - throttle them and move on
2012-11-28 15:47:07 +00:00
NET_VERBOSE_PRINT ( " ^2Net: timed out waiting for bandwidth challenge results \n " ) ;
for ( int i = 0 ; i < peers . Num ( ) ; i + + )
{
NET_VERBOSE_PRINT ( " Peer[%d] %s. SentAll: %d RecAll: %d \n " , i , GetPeerName ( i ) , peers [ i ] . bandwidthChallengeSendComplete , peers [ i ] . bandwidthChallengeResults ) ;
if ( peers [ i ] . bandwidthChallengeSendComplete & & ! peers [ i ] . bandwidthChallengeResults )
{
2012-11-26 18:58:24 +00:00
ThrottlePeerSnapRate ( i ) ;
}
}
bandwidthChallengeFinished = true ;
bandwidthChallengeStartTime = 0 ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : UpdateBandwidthTest
This will be called on clients to check current state of bandwidth testing
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : ClientUpdateBandwidthTest ( )
{
if ( ! verify ( ! IsHost ( ) ) | | ! verify ( host > = 0 ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( ! peers [ host ] . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( bandwidthChallengeStartTime < = 0 )
{
2012-11-26 18:58:24 +00:00
// Not doing a test
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 ( bandwidthChallengeEndTime > time )
{
2012-11-26 18:58:24 +00:00
// Test is still going on
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Its been long enough since we last received bw test msg. So lets send the results to the server
byte buffer [ idPacketProcessor : : MAX_MSG_SIZE ] ;
idBitMsg msg ( buffer , sizeof ( buffer ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Send total time it took to receive all the msgs
// (note, subtract net_bw_test_timeout to get 'last recevied bandwidth test packet')
// (^^ Note if the last packet is fragmented and we never get it, this is technically wrong!)
int totalTime = ( bandwidthChallengeEndTime - session - > GetTitleStorageInt ( " net_bw_test_timeout " , net_bw_test_timeout . GetInteger ( ) ) ) - bandwidthChallengeStartTime ;
msg . WriteLong ( totalTime ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Send total number of complete, in order packets we got
msg . WriteLong ( bandwidthChallengeNumGoodSeq ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Send the overall average bandwidth in KBS
2012-11-28 15:47:07 +00:00
// Note that sending the number of good packets is not enough. If the packets going out are fragmented, and we
2012-11-26 18:58:24 +00:00
// drop fragments, the number of good sequences will be lower than the bandwidth we actually received.
int totalIncomingBytes = peers [ host ] . packetProc - > GetIncomingBytes ( ) - peers [ host ] . bandwidthTestBytes ;
msg . WriteLong ( totalIncomingBytes ) ;
2012-11-28 15:47:07 +00:00
idLib : : Printf ( " ^3Finished Bandwidth test: \n " ) ;
idLib : : Printf ( " Total time: %d \n " , totalTime ) ;
idLib : : Printf ( " Num good packets: %d \n " , bandwidthChallengeNumGoodSeq ) ;
idLib : : Printf ( " Total received byes: %d \n \n " , totalIncomingBytes ) ;
2012-11-26 18:58:24 +00:00
bandwidthChallengeStartTime = 0 ;
bandwidthChallengeNumGoodSeq = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
QueueReliableMessage ( host , RELIABLE_BANDWIDTH_VALUES , msg . GetReadData ( ) , msg . GetSize ( ) ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : HandleBandwidhTestValue
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : HandleBandwidhTestValue ( int p , idBitMsg & msg )
{
if ( ! IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
idLib : : Printf ( " Received RELIABLE_BANDWIDTH_CHECK %d \n " , Sys_Milliseconds ( ) ) ;
if ( bandwidthChallengeStartTime < 0 | | bandwidthChallengeFinished )
{
idLib : : Warning ( " Received bandwidth test results too early from peer %d " , 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 totalTime = msg . ReadLong ( ) ;
int totalGoodSeq = msg . ReadLong ( ) ;
int totalReceivedBytes = msg . ReadLong ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// This is the % of complete packets we received. If the packets used in the BWC are big enough to fragment, then pctPackets
// will be lower than bytesPct (we will have received a larger PCT of overall bandwidth than PCT of full packets received).
// Im not sure if this is a useful distinction or not, but it may be good to compare against for now.
2012-11-28 15:47:07 +00:00
float pctPackets = peers [ p ] . bandwidthSequenceNum > 0 ? ( float ) totalGoodSeq / ( float ) peers [ p ] . bandwidthSequenceNum : - 1.0f ;
2012-11-26 18:58:24 +00:00
// This is the % of total bytes sent/bytes received.
2012-11-28 15:47:07 +00:00
float bytesPct = peers [ p ] . bandwidthTestBytes > 0 ? ( float ) totalReceivedBytes / ( float ) peers [ p ] . bandwidthTestBytes : - 1.0f ;
2012-11-26 18:58:24 +00:00
// Calculate overall bandwidth for the test. That is, total amount received over time.
2012-11-28 15:47:07 +00:00
// We may want to expand this to also factor in an average instantaneous rate.
2012-11-26 18:58:24 +00:00
// For now we are mostly concerned with culling out poor performing clients
float peerKBS = - 1.0f ;
2012-11-28 15:47:07 +00:00
if ( verify ( totalTime > 0 ) )
{
peerKBS = ( ( float ) totalReceivedBytes / 1024.0f ) / MS2SEC ( totalTime ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int totalSendTime = peers [ p ] . bandwidthTestLastSendTime - peers [ p ] . bandwidthChallengeStartSendTime ;
float outgoingKBS = - 1.0f ;
2012-11-28 15:47:07 +00:00
if ( verify ( totalSendTime > 0 ) )
{
outgoingKBS = ( ( float ) peers [ p ] . bandwidthTestBytes / 1024.0f ) / MS2SEC ( totalSendTime ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
float pctKBS = peerKBS / outgoingKBS ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bool failedRate = ( pctKBS < session - > GetTitleStorageFloat ( " net_bw_test_throttle_rate_pct " , net_bw_test_throttle_rate_pct . GetFloat ( ) ) ) ;
bool failedByte = ( bytesPct < session - > GetTitleStorageFloat ( " net_bw_test_throttle_byte_pct " , net_bw_test_throttle_byte_pct . GetFloat ( ) ) ) ;
bool failedSeq = ( pctPackets < session - > GetTitleStorageFloat ( " net_bw_test_throttle_seq_pct " , net_bw_test_throttle_seq_pct . GetFloat ( ) ) ) ;
2012-11-28 15:47:07 +00:00
idLib : : Printf ( " ^3Finished Bandwidth test %s: \n " , GetPeerName ( p ) ) ;
idLib : : Printf ( " Total time: %dms \n " , totalTime ) ;
idLib : : Printf ( " %sNum good packets: %d (%.2f%) \n " , ( failedSeq ? " ^1 " : " ^2 " ) , totalGoodSeq , pctPackets ) ;
idLib : : Printf ( " %sTotal received bytes: %d (%.2f%) \n " , ( failedByte ? " ^1 " : " ^2 " ) , totalReceivedBytes , bytesPct ) ;
idLib : : Printf ( " %sEffective downstream: %.2fkbs (host: %.2fkbs) -> %.2f% \n \n " , ( failedRate ? " ^1 " : " ^2 " ) , peerKBS , outgoingKBS , pctKBS ) ;
2012-11-26 18:58:24 +00:00
// If shittConnection(totalTime, totalGoodSeq/totalSeq, totalReceivedBytes/totalSentBytes)
2012-11-28 15:47:07 +00:00
// throttle this user:
2012-11-26 18:58:24 +00:00
// peers[p].throttledSnapRate = baseSnapRate * 2
2012-11-28 15:47:07 +00:00
if ( failedRate | | failedByte | | failedSeq )
{
2012-11-26 18:58:24 +00:00
ThrottlePeerSnapRate ( p ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// See if we are finished
peers [ p ] . bandwidthChallengeResults = true ;
bandwidthChallengeFinished = true ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < peers . Num ( ) ; i + + )
{
if ( peers [ i ] . bandwidthChallengeSendComplete & & ! peers [ i ] . bandwidthChallengeResults )
{
2012-11-26 18:58:24 +00:00
bandwidthChallengeFinished = false ;
}
}
2012-11-28 15:47:07 +00:00
if ( bandwidthChallengeFinished )
{
2012-11-26 18:58:24 +00:00
bandwidthChallengeStartTime = 0 ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SendPingValues
Host only
Periodically send all peers ' pings to all peers ( for the UI ) .
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : SendPingValues ( )
{
if ( ! verify ( IsHost ( ) ) )
{
2012-11-26 18:58:24 +00:00
// paranoia
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const int now = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
if ( nextSendPingValuesTime > now )
{
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
nextSendPingValuesTime = now + PING_INTERVAL_MS ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
pktPingValues_t packet ;
2012-11-28 15:47:07 +00:00
memset ( & packet , 0 , sizeof ( packet ) ) ;
for ( int i = 0 ; i < peers . Max ( ) ; + + i )
{
if ( i > = peers . Num ( ) )
{
2012-11-26 18:58:24 +00:00
packet . pings [ i ] = - 1 ;
2012-11-28 15:47:07 +00:00
}
else if ( peers [ i ] . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
packet . pings [ i ] = peers [ i ] . lastPingRtt ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
packet . pings [ i ] = - 1 ;
}
}
2012-11-28 15:47:07 +00:00
byte packetCopy [ sizeof ( packet ) ] ;
idBitMsg msg ( packetCopy , sizeof ( packetCopy ) ) ;
for ( int i = 0 ; i < peers . Max ( ) ; + + i )
{
2012-11-26 18:58:24 +00:00
msg . WriteShort ( packet . pings [ i ] ) ;
}
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
QueueReliableMessage ( i , RELIABLE_PING_VALUES , msg . GetReadData ( ) , msg . GetSize ( ) ) ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : PumpPings
Host : Periodically determine the round - trip time for a packet to all peers , and tell everyone
what everyone else ' s ping to the host is so they can display it in the UI .
Client : Indicate to the player when the server hasn ' t updated the ping values in too long .
This is usually going to preceed a connection timeout .
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : PumpPings ( )
{
if ( IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
// Calculate ping to all peers
PingPeers ( ) ;
// Send the hosts calculated ping values to each peer to everyone has updated ping times
SendPingValues ( ) ;
2012-11-28 15:47:07 +00:00
// Do bandwidth testing
2012-11-26 18:58:24 +00:00
ServerUpdateBandwidthTest ( ) ;
// Send Migration Data
SendMigrationGameData ( ) ;
2012-11-28 15:47:07 +00:00
}
else if ( IsPeer ( ) )
{
2012-11-26 18:58:24 +00:00
ClientUpdateBandwidthTest ( ) ;
2012-11-28 15:47:07 +00:00
if ( lastPingValuesRecvTime + PING_INTERVAL_MS + 1000 < Sys_Milliseconds ( ) & & migrationInfo . state = = MIGRATE_NONE )
{
for ( int userIndex = 0 ; userIndex < GetNumLobbyUsers ( ) ; + + userIndex )
{
lobbyUser_t * user = GetLobbyUser ( userIndex ) ;
if ( ! verify ( user ! = NULL ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
user - > pingMs = 999999 ;
}
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : HandleReliablePing
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : HandleReliablePing ( int p , idBitMsg & msg )
{
2012-11-26 18:58:24 +00:00
int c , b ;
msg . SaveReadState ( c , b ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
pktPing_t ping ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
memset ( & ping , 0 , sizeof ( ping ) ) ;
2012-11-28 15:47:07 +00:00
if ( ! verify ( sizeof ( ping ) < = msg . GetRemainingData ( ) ) )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Ignoring ping from peer %i because packet was the wrong size \n " , p ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
ping . timestamp = msg . ReadLong ( ) ;
2012-11-28 15:47:07 +00:00
if ( IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
// we should probably verify here whether or not this ping was solicited or not
HandlePingReply ( p , ping ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// this means the server is requesting a ping, so reply
msg . RestoreReadState ( c , b ) ;
QueueReliableMessage ( p , RELIABLE_PING , msg . GetReadData ( ) + msg . GetReadCount ( ) , msg . GetRemainingData ( ) ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : HandlePingReply
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : HandlePingReply ( int p , const pktPing_t & ping )
{
2012-11-26 18:58:24 +00:00
const int now = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const int rtt = now - ping . timestamp ;
peers [ p ] . lastPingRtt = rtt ;
2012-11-28 15:47:07 +00:00
for ( int userIndex = 0 ; userIndex < GetNumLobbyUsers ( ) ; + + userIndex )
{
lobbyUser_t * u = GetLobbyUser ( userIndex ) ;
if ( u - > peerIndex = = p )
{
2012-11-26 18:58:24 +00:00
u - > pingMs = rtt ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : HandlePingValues
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : HandlePingValues ( idBitMsg & msg )
{
2012-11-26 18:58:24 +00:00
pktPingValues_t packet ;
memset ( & packet , 0 , sizeof ( packet ) ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < peers . Max ( ) ; + + i )
{
packet . pings [ i ] = msg . ReadShort ( ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
assert ( IsPeer ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lastPingValuesRecvTime = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
for ( int userIndex = 0 ; userIndex < GetNumLobbyUsers ( ) ; + + userIndex )
{
lobbyUser_t * u = GetLobbyUser ( userIndex ) ;
if ( u - > peerIndex ! = - 1 & & verify ( u - > peerIndex > = 0 & & u - > peerIndex < MAX_PEERS ) )
{
2012-11-26 18:58:24 +00:00
u - > pingMs = packet . pings [ u - > peerIndex ] ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
u - > pingMs = 0 ;
}
}
// Stuff our ping in the hosts slot
2012-11-28 15:47:07 +00:00
if ( peerIndexOnHost ! = - 1 & & verify ( peerIndexOnHost > = 0 & & peerIndexOnHost < MAX_PEERS ) )
{
2012-11-26 18:58:24 +00:00
peers [ host ] . lastPingRtt = packet . pings [ peerIndexOnHost ] ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
peers [ host ] . lastPingRtt = 0 ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SendAnotherFragment
Other than connectionless sends , this should be the chokepoint for sending packets to peers .
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : SendAnotherFragment ( int p )
{
peer_t & peer = peers [ p ] ;
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( ! peer . IsConnected ( ) ) // Not connected to any mode (party or game), so no need to send
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( ! peer . packetProc - > HasMoreFragments ( ) )
{
2012-11-26 18:58:24 +00:00
return false ; // No fragments to send for this peer
}
2012-11-28 15:47:07 +00:00
if ( ! CanSendMoreData ( p ) )
{
2012-11-26 18:58:24 +00:00
return false ; // We need to throttle the sends so we don't saturate the connection
}
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 ( time - peer . lastFragmentSendTime < 2 )
{
NET_VERBOSE_PRINT ( " Too soon to send another packet. Delta: %d \n " , ( time - peer . lastFragmentSendTime ) ) ;
2012-11-26 18:58:24 +00:00
return false ; // Too soon to send another fragment
}
peer . lastFragmentSendTime = time ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bool sentFragment = false ;
2012-11-28 15:47:07 +00:00
while ( true )
{
2012-11-26 18:58:24 +00:00
idBitMsg msg ;
// We use the final packet size here because it has been processed, and no more headers will be added
2012-11-28 15:47:07 +00:00
byte buffer [ idPacketProcessor : : MAX_FINAL_PACKET_SIZE ] ;
2012-11-26 18:58:24 +00:00
msg . InitWrite ( buffer , sizeof ( buffer ) ) ;
2012-11-28 15:47:07 +00:00
if ( ! peers [ p ] . packetProc - > GetSendFragment ( time , peers [ p ] . sessionID , msg ) )
{
2012-11-26 18:58:24 +00:00
break ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const bool useDirectPort = ( lobbyType = = TYPE_GAME_STATE ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
msg . BeginReading ( ) ;
2012-11-28 15:47:07 +00:00
sessionCB - > SendRawPacket ( peers [ p ] . address , msg . GetReadData ( ) , msg . GetSize ( ) , useDirectPort ) ;
2012-11-26 18:58:24 +00:00
sentFragment = true ;
break ; // Comment this out to send all fragments in one burst
}
2012-11-28 15:47:07 +00:00
if ( peer . packetProc - > HasMoreFragments ( ) )
{
NET_VERBOSE_PRINT ( " More packets left after ::SendAnotherFragment \n " ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return sentFragment ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : CanSendMoreData
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : CanSendMoreData ( int p )
{
if ( ! verify ( p > = 0 & & p < peers . Num ( ) ) )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: CanSendMoreData %i NO: not a peer \n " , p ) ;
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
NET_VERBOSE_PRINT ( " NET: CanSendMoreData %i NO: not connected \n " , p ) ;
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return peer . packetProc - > CanSendMoreData ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : ProcessOutgoingMsg
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : ProcessOutgoingMsg ( int p , const void * data , int size , bool isOOB , int userData )
{
2012-11-26 18:58:24 +00:00
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 . GetConnectionState ( ) ! = CONNECTION_ESTABLISHED )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " peer.GetConnectionState() != CONNECTION_ESTABLISHED \n " ) ;
return ; // Peer not fully connected for this session type, return
}
2012-11-28 15:47:07 +00:00
if ( peer . packetProc - > HasMoreFragments ( ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Error ( " FATAL: Attempt to process a packet while fragments still need to be sent. \n " ) ; // We can't handle this case
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int currentTime = Sys_Milliseconds ( ) ;
// if ( currentTime - peer.lastProcTime < 30 ) {
// idLib::Printf("ProcessOutgoingMsg called within %dms %s\n", (currentTime - peer.lastProcTime), GetLobbyName() );
// }
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
peer . lastProcTime = currentTime ;
2012-11-28 15:47:07 +00:00
if ( ! isOOB )
{
// Keep track of the last time an in-band packet was sent
2012-11-26 18:58:24 +00:00
// (used for things like knowing when reliables could have been last sent)
peer . lastInBandProcTime = peer . lastProcTime ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idBitMsg msg ;
2012-11-28 15:47:07 +00:00
msg . InitRead ( ( byte * ) data , size ) ;
2012-11-26 18:58:24 +00:00
peer . packetProc - > ProcessOutgoing ( currentTime , msg , isOOB , userData ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : ResendReliables
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : ResendReliables ( int p )
{
2012-11-26 18:58:24 +00:00
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 . packetProc - > HasMoreFragments ( ) )
{
2012-11-26 18:58:24 +00:00
return ; // We can't send more data while fragments are still being sent out
}
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
int time = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const int DEFAULT_MIN_RESEND = 20 ; // Quicker resend while not in game to speed up resource transmission acks
const int DEFAULT_MIN_RESEND_INGAME = 100 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int resendWait = DEFAULT_MIN_RESEND_INGAME ;
2012-11-28 15:47:07 +00:00
if ( sessionCB - > GetState ( ) = = idSession : : INGAME )
{
2012-11-26 18:58:24 +00:00
// setup some minimum waits and account for ping
resendWait = Max ( DEFAULT_MIN_RESEND_INGAME , peer . lastPingRtt / 2 ) ;
2012-11-28 15:47:07 +00:00
if ( lobbyType = = TYPE_PARTY )
{
2012-11-26 18:58:24 +00:00
resendWait = Max ( 500 , resendWait ) ; // party session does not need fast frequency at all once in game
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// don't trust the ping when still loading stuff
// need to resend fast to speed up transmission of network decls
resendWait = DEFAULT_MIN_RESEND ;
}
2012-11-28 15:47:07 +00:00
if ( time - peer . lastInBandProcTime < resendWait )
{
2012-11-26 18:58:24 +00:00
// no need to resend reliables if they went out on an in-band packet recently
return ;
}
2012-11-28 15:47:07 +00:00
if ( peer . packetProc - > NumQueuedReliables ( ) > 0 | | peer . packetProc - > NeedToSendReliableAck ( ) )
{
2012-11-26 18:58:24 +00:00
//NET_VERBOSE_PRINT( "NET: ResendReliables %s\n", GetLobbyName() );
ProcessOutgoingMsg ( p , NULL , 0 , false , 0 ) ; // Force an empty unreliable msg so any reliables will get processed as well
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : PumpPackets
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : PumpPackets ( )
{
2012-11-26 18:58:24 +00:00
int newTime = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
if ( peers [ p ] . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
peers [ p ] . packetProc - > RefreshRates ( newTime ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Resend reliable msg's (do this before we send out the fragments)
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
2012-11-26 18:58:24 +00:00
ResendReliables ( p ) ;
}
// If we haven't sent anything to our peers in a long time, make sure to send an empty packet (so our heartbeat gets updated) so we don't get disconnected
// NOTE - We used to only send these to the host, but the host needs to also send these to clients
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
if ( ! peers [ p ] . IsConnected ( ) | | peers [ p ] . packetProc - > HasMoreFragments ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( newTime - peers [ p ] . lastProcTime > 1000 * PEER_HEARTBEAT_IN_SECONDS )
{
2012-11-26 18:58:24 +00:00
//NET_VERBOSE_PRINT( "NET: ProcessOutgoing Heartbeat %s\n", GetLobbyName() );
2012-11-28 15:47:07 +00:00
ProcessOutgoingMsg ( p , NULL , 0 , false , 0 ) ;
2012-11-26 18:58:24 +00:00
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Send any unsent fragments for each peer (do this last)
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
2012-11-26 18:58:24 +00:00
SendAnotherFragment ( p ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : UpdateMatchParms
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : UpdateMatchParms ( const idMatchParameters & p )
{
if ( ! IsHost ( ) )
{
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
parms = p ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Update lobbyBackend with parms
2012-11-28 15:47:07 +00:00
if ( lobbyBackend ! = NULL )
{
2012-11-26 18:58:24 +00:00
lobbyBackend - > UpdateMatchParms ( parms ) ;
}
SendMatchParmsToPeers ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetHostUserName
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
const char * idLobby : : GetHostUserName ( ) const
{
if ( ! IsLobbyActive ( ) )
{
2012-11-26 18:58:24 +00:00
return INVALID_LOBBY_USER_NAME ;
}
return GetPeerName ( - 1 ) ; // This will just grab the first user with this peerIndex (which should be the host)
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SendReliable
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : SendReliable ( int type , idBitMsg & msg , bool callReceiveReliable /*= true*/ , peerMask_t sessionUserMask /*= MAX_UNSIGNED_TYPE( peerMask_t ) */ )
{
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
assert ( type < 256 ) ; // QueueReliable only accepts a byte for message type
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// the queuing below sends the whole message
// I don't know if whole message is a good thing or a bad thing, but if the passed message has been read from already, this is most likely not going to do what the caller expects
assert ( msg . GetReadCount ( ) + msg . GetReadBit ( ) = = 0 ) ;
2012-11-28 15:47:07 +00:00
if ( callReceiveReliable )
{
2012-11-26 18:58:24 +00:00
// NOTE: this will put the msg's read status to fully read - which is why the assert check is above
common - > NetReceiveReliable ( - 1 , type , msg ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
uint32 sentPeerMask = 0 ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < GetNumLobbyUsers ( ) ; + + i )
{
lobbyUser_t * user = GetLobbyUser ( i ) ;
if ( user - > peerIndex = = - 1 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// We only care about sending these to peers in our party lobby
2012-11-28 15:47:07 +00:00
if ( user - > IsDisconnected ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Don't sent to a user if they are in the exlusion session user mask
2012-11-28 15:47:07 +00:00
if ( sessionUserMask ! = 0 & & ( sessionUserMask & ( BIT ( i ) ) ) = = 0 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const int peerIndex = user - > peerIndex ;
2012-11-28 15:47:07 +00:00
if ( peerIndex > = peers . Num ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
peer_t & peer = peers [ peerIndex ] ;
if ( ! peer . IsConnected ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( ( sentPeerMask & ( 1 < < user - > peerIndex ) ) = = 0 )
{
2012-11-26 18:58:24 +00:00
QueueReliableMessage ( user - > peerIndex , idLobby : : RELIABLE_GAME_DATA + type , msg . GetReadData ( ) , msg . GetSize ( ) ) ;
sentPeerMask | = 1 < < user - > peerIndex ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SendReliableToLobbyUser
can only be used on the server . will take care of calling locally if addressed to player 0
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : SendReliableToLobbyUser ( lobbyUserID_t lobbyUserID , int type , idBitMsg & msg )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
assert ( type < 256 ) ; // QueueReliable only accepts a byte for message type
assert ( IsHost ( ) ) ; // This function should only be called in the server atm
const int peerIndex = PeerIndexFromLobbyUser ( lobbyUserID ) ;
2012-11-28 15:47:07 +00:00
if ( peerIndex > = 0 )
{
2012-11-26 18:58:24 +00:00
// will send the remainder of a message that was started reading through, but not handling a partial byte read
assert ( msg . GetReadBit ( ) = = 0 ) ;
QueueReliableMessage ( peerIndex , idLobby : : RELIABLE_GAME_DATA + type , msg . GetReadData ( ) + msg . GetReadCount ( ) , msg . GetRemainingData ( ) ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
common - > NetReceiveReliable ( - 1 , type , msg ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SendReliableToHost
will make sure to invoke locally if used on the server
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : SendReliableToHost ( int type , idBitMsg & msg )
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
common - > NetReceiveReliable ( - 1 , type , msg ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// will send the remainder of a message that was started reading through, but not handling a partial byte read
assert ( msg . GetReadBit ( ) = = 0 ) ;
QueueReliableMessage ( host , idLobby : : RELIABLE_GAME_DATA + type , msg . GetReadData ( ) + msg . GetReadCount ( ) , msg . GetRemainingData ( ) ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : reliablePlayerToPlayerHeader_t
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : reliablePlayerToPlayerHeader_t : : reliablePlayerToPlayerHeader_t
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idLobby : : reliablePlayerToPlayerHeader_t : : reliablePlayerToPlayerHeader_t ( ) : fromSessionUserIndex ( - 1 ) , toSessionUserIndex ( - 1 )
{
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idSessionLocal : : reliablePlayerToPlayerHeader_t : : Read
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : reliablePlayerToPlayerHeader_t : : Read ( idLobby * lobby , idBitMsg & msg )
{
2012-11-26 18:58:24 +00:00
assert ( lobby ! = NULL ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lobbyUserID_t lobbyUserIDFrom ;
lobbyUserID_t lobbyUserIDTo ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lobbyUserIDFrom . ReadFromMsg ( msg ) ;
lobbyUserIDTo . ReadFromMsg ( msg ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
fromSessionUserIndex = lobby - > GetLobbyUserIndexByID ( lobbyUserIDFrom ) ;
toSessionUserIndex = lobby - > GetLobbyUserIndexByID ( lobbyUserIDTo ) ;
2012-11-28 15:47:07 +00:00
if ( ! verify ( lobby - > GetLobbyUser ( fromSessionUserIndex ) ! = NULL ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( ! verify ( lobby - > GetLobbyUser ( toSessionUserIndex ) ! = NULL ) )
{
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 : : reliablePlayerToPlayerHeader_t : : Write
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : reliablePlayerToPlayerHeader_t : : Write ( idLobby * lobby , idBitMsg & msg )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( ! verify ( lobby - > GetLobbyUser ( fromSessionUserIndex ) ! = NULL ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( ! verify ( lobby - > GetLobbyUser ( toSessionUserIndex ) ! = NULL ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
lobby - > GetLobbyUser ( fromSessionUserIndex ) - > lobbyUserID . WriteToMsg ( msg ) ;
lobby - > GetLobbyUser ( toSessionUserIndex ) - > lobbyUserID . WriteToMsg ( msg ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetNumActiveLobbyUsers
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : GetNumActiveLobbyUsers ( ) const
{
2012-11-26 18:58:24 +00:00
int numActive = 0 ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < GetNumLobbyUsers ( ) ; + + i )
{
if ( ! GetLobbyUser ( i ) - > IsDisconnected ( ) )
{
2012-11-26 18:58:24 +00:00
numActive + + ;
}
}
return numActive ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : AllPeersInGame
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : AllPeersInGame ( ) const
{
2012-11-26 18:58:24 +00:00
assert ( lobbyType = = GetActingGameStateLobbyType ( ) ) ; // This function doesn't make sense on a party lobby currently
2012-11-28 15:47:07 +00:00
for ( int p = 0 ; p < peers . Num ( ) ; p + + )
{
if ( peers [ p ] . IsConnected ( ) & & ! peers [ p ] . inGame )
{
2012-11-26 18:58:24 +00:00
return false ;
}
}
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : PeerIndexFromLobbyUser
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : PeerIndexFromLobbyUser ( lobbyUserID_t lobbyUserID ) const
{
2012-11-26 18:58:24 +00:00
const int lobbyUserIndex = GetLobbyUserIndexByID ( lobbyUserID ) ;
2012-11-28 15:47:07 +00:00
const lobbyUser_t * user = GetLobbyUser ( lobbyUserIndex ) ;
if ( user = = NULL )
{
2012-11-26 18:58:24 +00:00
// This needs to be OK for bot support ( or else add bots at the session level )
return - 1 ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return user - > peerIndex ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetPeerTimeSinceLastPacket
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : GetPeerTimeSinceLastPacket ( int peerIndex ) const
{
if ( peerIndex < 0 )
{
2012-11-26 18:58:24 +00:00
return 0 ;
}
return Sys_Milliseconds ( ) - peers [ peerIndex ] . lastHeartBeat ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetActingGameStateLobbyType
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idLobby : : lobbyType_t idLobby : : GetActingGameStateLobbyType ( ) const
{
2012-11-26 18:58:24 +00:00
extern idCVar net_useGameStateLobby ;
return ( net_useGameStateLobby . GetBool ( ) ) ? TYPE_GAME_STATE : TYPE_GAME ;
}
//========================================================================================================================
// idLobby::peer_t
//========================================================================================================================
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : peer_t : : GetConnectionState
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idLobby : : connectionState_t idLobby : : peer_t : : GetConnectionState ( ) const
{
2012-11-26 18:58:24 +00:00
return connectionState ;
}