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
# include "../idlib/precompiled.h"
# include "sys_lobby.h"
2012-11-28 15:47:07 +00:00
idCVar net_migration_debug ( " net_migration_debug " , " 0 " , CVAR_BOOL , " debug " ) ;
idCVar net_migration_disable ( " net_migration_disable " , " 0 " , CVAR_BOOL , " debug " ) ;
2012-11-26 18:58:24 +00:00
idCVar net_migration_forcePeerAsHost ( " net_migration_forcePeerAsHost " , " -1 " , CVAR_INTEGER , " When set to >-1, it forces that peer number to be the new host during migration " ) ;
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : IsBetterHost
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : IsBetterHost ( int ping1 , lobbyUserID_t userId1 , int ping2 , lobbyUserID_t userId2 )
{
if ( lobbyType = = TYPE_PARTY )
{
2012-11-26 18:58:24 +00:00
return userId1 < userId2 ; // Only use user id for party, since ping doesn't matter
}
2012-11-28 15:47:07 +00:00
if ( ping1 < ping2 )
{
2012-11-26 18:58:24 +00:00
// Better ping wins
return true ;
2012-11-28 15:47:07 +00:00
}
else if ( ping1 = = ping2 & & userId1 < userId2 )
{
2012-11-26 18:58:24 +00:00
// User id is tie breaker
return true ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return false ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : FindMigrationInviteIndex
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLobby : : FindMigrationInviteIndex ( lobbyAddress_t & address )
{
if ( migrationInfo . state = = MIGRATE_NONE )
{
2012-11-26 18:58:24 +00:00
return - 1 ;
}
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < migrationInfo . invites . Num ( ) ; i + + )
{
if ( migrationInfo . invites [ i ] . address . Compare ( address , true ) )
{
2012-11-26 18:58:24 +00:00
return i ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return - 1 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : UpdateHostMigration
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : UpdateHostMigration ( )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
int time = Sys_Milliseconds ( ) ;
2012-11-26 18:58:24 +00:00
// If we are picking a new host, then update that
2012-11-28 15:47:07 +00:00
if ( migrationInfo . state = = MIGRATE_PICKING_HOST )
{
2012-11-26 18:58:24 +00:00
const int MIGRATION_PICKING_HOST_TIMEOUT_IN_SECONDS = 20 ; // FIXME: set back to 5 // Give other hosts 5 seconds
2012-11-28 15:47:07 +00:00
if ( time - migrationInfo . migrationStartTime > session - > GetTitleStorageInt ( " MIGRATION_PICKING_HOST_TIMEOUT_IN_SECONDS " , MIGRATION_PICKING_HOST_TIMEOUT_IN_SECONDS ) * 1000 )
{
2012-11-26 18:58:24 +00:00
// Just become the host if we haven't heard from a host in awhile
BecomeHost ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
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
// See if we are a new migrated host that needs to invite the original members back
2012-11-28 15:47:07 +00:00
if ( migrationInfo . state ! = MIGRATE_BECOMING_HOST )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( lobbyBackend = = NULL | | lobbyBackend - > GetState ( ) ! = idLobbyBackend : : STATE_READY )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( state ! = STATE_IDLE )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( ! IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const int MIGRATION_TIMEOUT_IN_SECONDS = 30 ; // FIXME: setting to 30 for dev purposes. 10 seems more reasonable. Need to make unloading game / loading lobby async
const int MIGRATION_INVITE_TIME_IN_SECONDS = 2 ;
2012-11-28 15:47:07 +00:00
if ( migrationInfo . invites . Num ( ) = = 0 | | time - migrationInfo . migrationStartTime > session - > GetTitleStorageInt ( " MIGRATION_TIMEOUT_IN_SECONDS " , MIGRATION_TIMEOUT_IN_SECONDS ) * 1000 )
{
2012-11-26 18:58:24 +00:00
// Either everyone acked, or we timed out, just keep who we have, and stop sending invites
EndMigration ( ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Send invites to anyone who hasn't responded
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < migrationInfo . invites . Num ( ) ; i + + )
{
if ( time - migrationInfo . invites [ i ] . lastInviteTime < session - > GetTitleStorageInt ( " MIGRATION_INVITE_TIME_IN_SECONDS " , MIGRATION_INVITE_TIME_IN_SECONDS ) * 1000 )
{
2012-11-26 18:58:24 +00:00
continue ; // Not enough time passed
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Mark the time
migrationInfo . invites [ i ] . lastInviteTime = time ;
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 lobbyBackend fill out msg with connection info
lobbyConnectInfo_t connectInfo = lobbyBackend - > GetConnectInfo ( ) ;
connectInfo . WriteToMsg ( outmsg ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Let them know whether or not this was from in game
outmsg . WriteBool ( migrationInfo . persistUntilGameEndsData . wasMigratedGame ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Sending migration invite to %s \n " , migrationInfo . invites [ i ] . address . ToString ( ) ) ;
// Send the migration invite
2012-11-28 15:47:07 +00:00
SendConnectionLess ( migrationInfo . invites [ i ] . address , OOB_MIGRATE_INVITE , outmsg . GetReadData ( ) , outmsg . GetSize ( ) ) ;
2012-11-26 18:58:24 +00:00
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : BuildMigrationInviteList
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : BuildMigrationInviteList ( bool inviteOldHost )
{
2012-11-26 18:58:24 +00:00
migrationInfo . invites . Clear ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Build a list of addresses we will send invites to (gather all unique remote addresses from the session user list)
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 - > IsDisconnected ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( IsSessionUserIndexLocal ( i ) )
{
2012-11-26 18:58:24 +00:00
migrationInfo . ourPingMs = user - > pingMs ;
migrationInfo . ourUserId = user - > lobbyUserID ;
migrationInfo . persistUntilGameEndsData . ourGameData = user - > migrationGameData ;
NET_VERBOSE_PRINT ( " ^2NET: Migration game data for local user is index %d \n " , user - > migrationGameData ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
continue ; // Only interested in remote users
}
2012-11-28 15:47:07 +00:00
if ( ! inviteOldHost & & user - > peerIndex = = - 1 )
{
2012-11-26 18:58:24 +00:00
continue ; // Don't invite old host if told not to do so
}
2012-11-28 15:47:07 +00:00
if ( FindMigrationInviteIndex ( user - > address ) = = - 1 )
{
2012-11-26 18:58:24 +00:00
migrationInvite_t invite ;
invite . address = user - > address ;
invite . pingMs = user - > pingMs ;
invite . userId = user - > lobbyUserID ;
invite . migrationGameData = user - > migrationGameData ;
invite . lastInviteTime = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " ^2NET: Migration game data for user %s is index %d \n " , user - > gamertag , user - > migrationGameData ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
migrationInfo . invites . Append ( invite ) ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : PickNewHost
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : PickNewHost ( bool forceMe , bool inviteOldHost )
{
if ( IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " PickNewHost: Already host of session %s \n " , GetLobbyName ( ) ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
sessionCB - > PrePickNewHost ( * this , forceMe , inviteOldHost ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : PickNewHostInternal
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : PickNewHostInternal ( bool forceMe , bool inviteOldHost )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( migrationInfo . state = = MIGRATE_PICKING_HOST )
{
2012-11-26 18:58:24 +00:00
return ; // Already picking new host
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " PickNewHost: Started picking new host %s. \n " , GetLobbyName ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " PickNewHost: Already host of session %s \n " , GetLobbyName ( ) ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Find the user with the lowest ping
int bestUserIndex = - 1 ;
int bestPingMs = 0 ;
lobbyUserID_t bestUserId ;
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 - > IsDisconnected ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( user - > peerIndex = = - 1 )
{
2012-11-26 18:58:24 +00:00
continue ; // Don't try and pick old host
}
2012-11-28 15:47:07 +00:00
if ( bestUserIndex = = - 1 | | IsBetterHost ( user - > pingMs , user - > lobbyUserID , bestPingMs , bestUserId ) )
{
2012-11-26 18:58:24 +00:00
bestUserIndex = i ;
bestPingMs = user - > pingMs ;
bestUserId = user - > lobbyUserID ;
}
2012-11-28 15:47:07 +00:00
if ( user - > peerIndex = = net_migration_forcePeerAsHost . GetInteger ( ) )
{
2012-11-26 18:58:24 +00:00
bestUserIndex = i ;
bestPingMs = user - > pingMs ;
bestUserId = user - > lobbyUserID ;
break ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Remember when we first started picking a new host
migrationInfo . state = MIGRATE_PICKING_HOST ;
2012-11-28 15:47:07 +00:00
migrationInfo . migrationStartTime = Sys_Milliseconds ( ) ;
2012-11-26 18:58:24 +00:00
migrationInfo . persistUntilGameEndsData . wasMigratedGame = sessionCB - > GetState ( ) = = idSession : : INGAME ;
2012-11-28 15:47:07 +00:00
if ( bestUserIndex = = - 1 ) // This can happen if we call PickNewHost on an lobby that was Shutdown
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " MIGRATION: PickNewHost was called on an lobby that was Shutdown \n " ) ;
BecomeHost ( ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " MIGRATION: Chose user index %d (%s) for new host \n " , bestUserIndex , GetLobbyUser ( bestUserIndex ) - > gamertag ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bool bestWasLocal = IsSessionUserIndexLocal ( bestUserIndex ) ; // Check before shutting down the lobby
2012-11-28 15:47:07 +00:00
migrateMsgFlags = parms . matchFlags ; // Save off match parms
2012-11-26 18:58:24 +00:00
// Build invite list
BuildMigrationInviteList ( inviteOldHost ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If the best user is on this machine, then we become the host now, otherwise, wait for a new host to contact us
2012-11-28 15:47:07 +00:00
if ( forceMe | | bestWasLocal )
{
2012-11-26 18:58:24 +00:00
BecomeHost ( ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : BecomeHost
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : BecomeHost ( )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( ! verify ( migrationInfo . state = = MIGRATE_PICKING_HOST ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " BecomeHost: Must be called from PickNewHost. \n " ) ;
EndMigration ( ) ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( IsHost ( ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " BecomeHost: Already host of session. \n " ) ;
EndMigration ( ) ;
return ;
}
2012-11-28 15:47:07 +00:00
if ( ! sessionCB - > BecomingHost ( * this ) )
{
2012-11-26 18:58:24 +00:00
EndMigration ( ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " BecomeHost: Sending %i invites on %s. \n " , migrationInfo . invites . Num ( ) , GetLobbyName ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
migrationInfo . state = MIGRATE_BECOMING_HOST ;
migrationInfo . migrationStartTime = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
if ( lobbyBackend = = NULL )
{
2012-11-26 18:58:24 +00:00
// If we don't have a lobbyBackend, then just create one
Shutdown ( ) ;
StartCreating ( ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Shutdown the current lobby, but keep the lobbyBackend (we'll migrate it)
Shutdown ( true ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Migrate the lobbyBackend to host
lobbyBackend - > BecomeHost ( migrationInfo . invites . Num ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Wait for it to complete
SetState ( STATE_CREATE_LOBBY_BACKEND ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : EndMigration
This gets called when we are done migrating , and invites will no longer be sent out .
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : EndMigration ( )
{
if ( migrationInfo . state = = MIGRATE_NONE )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " idSessionLocal::EndMigration: Not migrating. \n " ) ;
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
sessionCB - > MigrationEnded ( * this ) ;
2012-11-28 15:47:07 +00:00
if ( lobbyBackend ! = NULL )
{
2012-11-26 18:58:24 +00:00
lobbyBackend - > FinishBecomeHost ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
migrationInfo . state = MIGRATE_NONE ;
migrationInfo . invites . Clear ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : ResetAllMigrationState
This will reset all state related to host migration . Should be called
at match end so our next game is not treated as a migrated game
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : ResetAllMigrationState ( )
{
2012-11-26 18:58:24 +00:00
migrationInfo . state = MIGRATE_NONE ;
migrationInfo . invites . Clear ( ) ;
migrationInfo . persistUntilGameEndsData . Clear ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
migrateMsgFlags = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
common - > Dialog ( ) . ClearDialog ( GDM_MIGRATING ) ;
common - > Dialog ( ) . ClearDialog ( GDM_MIGRATING_WAITING ) ;
common - > Dialog ( ) . ClearDialog ( GDM_MIGRATING_RELAUNCHING ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetMigrationGameData
This will setup the passed in idBitMsg to either read or write from the global migration game data buffer
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : GetMigrationGameData ( idBitMsg & msg , bool reading )
{
if ( reading )
{
if ( ! IsMigratedStatsGame ( ) | | ! migrationInfo . persistUntilGameEndsData . wasMigratedHost )
{
2012-11-26 18:58:24 +00:00
// This was not a migrated session, we have no migration data
return false ;
}
msg . InitRead ( migrationInfo . persistUntilGameEndsData . gameData , sizeof ( migrationInfo . persistUntilGameEndsData . gameData ) ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
migrationInfo . persistUntilGameEndsData . hasGameData = true ;
memset ( migrationInfo . persistUntilGameEndsData . gameData , 0 , sizeof ( migrationInfo . persistUntilGameEndsData . gameData ) ) ;
msg . InitWrite ( migrationInfo . persistUntilGameEndsData . gameData , sizeof ( migrationInfo . persistUntilGameEndsData . gameData ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : GetMigrationGameDataUser
This will setup the passed in idBitMsg to either read or write from the user ' s migration game data buffer
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLobby : : GetMigrationGameDataUser ( lobbyUserID_t lobbyUserID , idBitMsg & msg , bool reading )
{
2012-11-26 18:58:24 +00:00
const int userNum = GetLobbyUserIndexByID ( lobbyUserID ) ;
2012-11-28 15:47:07 +00:00
if ( ! verify ( userNum > = 0 & & userNum < MAX_PLAYERS ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
lobbyUser_t * u = GetLobbyUser ( userNum ) ;
if ( u ! = NULL )
{
if ( reading )
{
if ( ! IsMigratedStatsGame ( ) | | ! migrationInfo . persistUntilGameEndsData . wasMigratedHost )
{
2012-11-26 18:58:24 +00:00
// This was not a migrated session, we have no migration data
return false ;
}
2012-11-28 15:47:07 +00:00
if ( u - > migrationGameData > = 0 & & u - > migrationGameData < MAX_PLAYERS )
{
2012-11-26 18:58:24 +00:00
msg . InitRead ( migrationInfo . persistUntilGameEndsData . gameDataUser [ u - > migrationGameData ] , sizeof ( migrationInfo . persistUntilGameEndsData . gameDataUser [ 0 ] ) ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// We don't have migration data for this user
idLib : : Warning ( " No migration data for user %d in a migrated game (%d) " , userNum , u - > migrationGameData ) ;
return false ;
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// Writing
migrationInfo . persistUntilGameEndsData . hasGameData = true ;
u - > migrationGameData = userNum ;
memset ( migrationInfo . persistUntilGameEndsData . gameDataUser [ userNum ] , 0 , sizeof ( migrationInfo . persistUntilGameEndsData . gameDataUser [ 0 ] ) ) ;
msg . InitWrite ( migrationInfo . persistUntilGameEndsData . gameDataUser [ userNum ] , sizeof ( migrationInfo . persistUntilGameEndsData . gameDataUser [ 0 ] ) ) ;
}
return true ;
}
return false ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : HandleMigrationGameData
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : HandleMigrationGameData ( idBitMsg & msg )
{
2012-11-26 18:58:24 +00:00
// Receives game migration data from the server. Just save off the raw data. If we ever become host we'll let the game code read
// that chunk in (we can't do anything with it now anyways: we don't have entities or any server code to read it in to)
migrationInfo . persistUntilGameEndsData . hasGameData = true ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Reset each user's migration game data. If we don't receive new data for them in this msg, we don't want to use the old data
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < GetNumLobbyUsers ( ) ; i + + )
{
lobbyUser_t * u = GetLobbyUser ( i ) ;
if ( u ! = NULL )
{
2012-11-26 18:58:24 +00:00
u - > migrationGameData = - 1 ;
}
}
msg . ReadData ( migrationInfo . persistUntilGameEndsData . gameData , sizeof ( migrationInfo . persistUntilGameEndsData . gameData ) ) ;
int numUsers = msg . ReadByte ( ) ;
2012-11-28 15:47:07 +00:00
int dataIndex = 0 ;
for ( int i = 0 ; i < numUsers ; i + + )
{
2012-11-26 18:58:24 +00:00
lobbyUserID_t lobbyUserID ;
lobbyUserID . ReadFromMsg ( msg ) ;
2012-11-28 15:47:07 +00:00
lobbyUser_t * user = GetLobbyUser ( GetLobbyUserIndexByID ( lobbyUserID ) ) ;
if ( user ! = NULL )
{
2012-11-26 18:58:24 +00:00
NET_VERBOSE_PRINT ( " NET: Got migration data[%d] for user %s \n " , dataIndex , user - > gamertag ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
user - > migrationGameData = dataIndex ;
msg . ReadData ( migrationInfo . persistUntilGameEndsData . gameDataUser [ dataIndex ] , sizeof ( migrationInfo . persistUntilGameEndsData . gameDataUser [ dataIndex ] ) ) ;
2012-11-28 15:47:07 +00:00
dataIndex + + ;
2012-11-26 18:58:24 +00:00
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLobby : : SendMigrationGameData
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLobby : : SendMigrationGameData ( )
{
if ( net_migration_disable . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( sessionCB - > GetState ( ) ! = idSession : : INGAME )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( ! migrationInfo . persistUntilGameEndsData . hasGameData )
{
2012-11-26 18:58:24 +00:00
// Haven't been given any migration game data yet
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 ( nextSendMigrationGameTime > 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
byte packetData [ idPacketProcessor : : MAX_MSG_SIZE ] ;
2012-11-28 15:47:07 +00:00
idBitMsg msg ( packetData , sizeof ( packetData ) ) ;
2012-11-26 18:58:24 +00:00
// Write global data
msg . WriteData ( & migrationInfo . persistUntilGameEndsData . gameData , sizeof ( migrationInfo . persistUntilGameEndsData . gameData ) ) ;
msg . WriteByte ( GetNumLobbyUsers ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Write user data
2012-11-28 15:47:07 +00:00
for ( int userIndex = 0 ; userIndex < GetNumLobbyUsers ( ) ; + + userIndex )
{
lobbyUser_t * u = GetLobbyUser ( userIndex ) ;
if ( u - > IsDisconnected ( ) | | u - > migrationGameData < 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
u - > lobbyUserID . WriteToMsg ( msg ) ;
msg . WriteData ( migrationInfo . persistUntilGameEndsData . gameDataUser [ u - > migrationGameData ] , sizeof ( migrationInfo . persistUntilGameEndsData . gameDataUser [ u - > migrationGameData ] ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Send to 1 peer
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < peers . Num ( ) ; i + + )
{
2012-11-26 18:58:24 +00:00
int peerToSend = ( nextSendMigrationGamePeer + i ) % peers . Num ( ) ;
2012-11-28 15:47:07 +00:00
if ( peers [ peerToSend ] . IsConnected ( ) & & peers [ peerToSend ] . loaded )
{
if ( peers [ peerToSend ] . packetProc - > NumQueuedReliables ( ) > idPacketProcessor : : MAX_RELIABLE_QUEUE / 2 )
{
2012-11-26 18:58:24 +00:00
// This is kind of a hack for development so we don't DC clients by sending them too many reliable migration messages
// when they aren't responding. Doesn't seem like a horrible thing to have in a shipping product but is not necessary.
2012-11-28 15:47:07 +00:00
NET_VERBOSE_PRINT ( " NET: Skipping reliable game migration data msg because client reliable queue is > half full \n " ) ;
}
else
{
if ( net_migration_debug . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " NET: Sending migration game data to peer %d. size: %d \n " , peerToSend , msg . GetSize ( ) ) ;
}
QueueReliableMessage ( peerToSend , RELIABLE_MIGRATION_GAME_DATA , msg . GetReadData ( ) , msg . GetSize ( ) ) ;
}
break ;
}
}
// Increment next send time / next send peer
nextSendMigrationGamePeer + + ;
2012-11-28 15:47:07 +00:00
if ( nextSendMigrationGamePeer > = peers . Num ( ) )
{
2012-11-26 18:58:24 +00:00
nextSendMigrationGamePeer = 0 ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
nextSendMigrationGameTime = now + MIGRATION_GAME_DATA_INTERVAL_MS ;
}