2011-11-22 21:28:15 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 GPL Source Code
2011-12-06 18:20:15 +00:00
Copyright ( C ) 1999 - 2011 id Software LLC , a ZeniMax Media company .
2011-11-22 21:28:15 +00:00
2011-12-06 16:14:59 +00:00
This file is part of the Doom 3 GPL Source Code ( " Doom 3 Source Code " ) .
2011-11-22 21:28:15 +00:00
Doom 3 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 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 Source Code . If not , see < http : //www.gnu.org/licenses/>.
In addition , the Doom 3 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 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 .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2011-12-16 22:28:29 +00:00
# include "sys/platform.h"
# include "idlib/LangDict.h"
# include "framework/async/AsyncNetwork.h"
# include "framework/Licensee.h"
# include "framework/Game.h"
# include "framework/Session_local.h"
# include "sound/sound.h"
2011-11-22 21:28:15 +00:00
2011-12-16 22:28:29 +00:00
# include "framework/async/AsyncClient.h"
2011-11-22 21:28:15 +00:00
const int SETUP_CONNECTION_RESEND_TIME = 1000 ;
const int EMPTY_RESEND_TIME = 500 ;
const int PREDICTION_FAST_ADJUST = 4 ;
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : idAsyncClient
= = = = = = = = = = = = = = = = = =
*/
idAsyncClient : : idAsyncClient ( void ) {
guiNetMenu = NULL ;
updateState = UPDATE_NONE ;
Clear ( ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : Clear
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : Clear ( void ) {
active = false ;
realTime = 0 ;
clientTime = 0 ;
clientId = 0 ;
clientDataChecksum = 0 ;
clientNum = 0 ;
clientState = CS_DISCONNECTED ;
clientPrediction = 0 ;
clientPredictTime = 0 ;
serverId = 0 ;
serverChallenge = 0 ;
serverMessageSequence = 0 ;
lastConnectTime = - 9999 ;
lastEmptyTime = - 9999 ;
lastPacketTime = - 9999 ;
lastSnapshotTime = - 9999 ;
snapshotGameFrame = 0 ;
snapshotGameTime = 0 ;
snapshotSequence = 0 ;
gameInitId = GAME_INIT_ID_INVALID ;
gameFrame = 0 ;
gameTimeResidual = 0 ;
gameTime = 0 ;
memset ( userCmds , 0 , sizeof ( userCmds ) ) ;
backgroundDownload . completed = true ;
lastRconTime = 0 ;
showUpdateMessage = false ;
lastFrameDelta = 0 ;
dlRequest = - 1 ;
dlCount = - 1 ;
memset ( dlChecksums , 0 , sizeof ( int ) * MAX_PURE_PAKS ) ;
currentDlSize = 0 ;
totalDlSize = 0 ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : Shutdown
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : Shutdown ( void ) {
guiNetMenu = NULL ;
updateMSG . Clear ( ) ;
updateURL . Clear ( ) ;
updateFile . Clear ( ) ;
updateFallback . Clear ( ) ;
backgroundDownload . url . url . Clear ( ) ;
dlList . Clear ( ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : InitPort
= = = = = = = = = = = = = = = = = =
*/
bool idAsyncClient : : InitPort ( void ) {
// if this is the first time we connect to a server, open the UDP port
if ( ! clientPort . GetPort ( ) ) {
if ( ! clientPort . InitForPort ( PORT_ANY ) ) {
common - > Printf ( " Couldn't open client network port. \n " ) ;
return false ;
}
}
// maintain it valid between connects and ui manager reloads
guiNetMenu = uiManager - > FindGui ( " guis/netmenu.gui " , true , false , true ) ;
return true ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ClosePort
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ClosePort ( void ) {
clientPort . Close ( ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ClearPendingPackets
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ClearPendingPackets ( void ) {
int size ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
netadr_t from ;
while ( clientPort . GetPacket ( from , msgBuf , size , sizeof ( msgBuf ) ) ) {
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : HandleGuiCommandInternal
= = = = = = = = = = = = = = = = = =
*/
const char * idAsyncClient : : HandleGuiCommandInternal ( const char * cmd ) {
if ( ! idStr : : Cmp ( cmd , " abort " ) | | ! idStr : : Cmp ( cmd , " pure_abort " ) ) {
common - > DPrintf ( " connection aborted \n " ) ;
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , " disconnect " ) ;
return " " ;
} else {
common - > DWarning ( " idAsyncClient::HandleGuiCommand: unknown cmd %s " , cmd ) ;
}
return NULL ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : HandleGuiCommand
= = = = = = = = = = = = = = = = = =
*/
const char * idAsyncClient : : HandleGuiCommand ( const char * cmd ) {
return idAsyncNetwork : : client . HandleGuiCommandInternal ( cmd ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ConnectToServer
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ConnectToServer ( const netadr_t adr ) {
// shutdown any current game. that includes network disconnect
session - > Stop ( ) ;
if ( ! InitPort ( ) ) {
return ;
}
if ( cvarSystem - > GetCVarBool ( " net_serverDedicated " ) ) {
common - > Printf ( " Can't connect to a server as dedicated \n " ) ;
return ;
}
// trash any currently pending packets
ClearPendingPackets ( ) ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
serverAddress = adr ;
// clear the client state
Clear ( ) ;
// get a pseudo random client id, but don't use the id which is reserved for connectionless packets
clientId = Sys_Milliseconds ( ) & CONNECTIONLESS_MESSAGE_ID_MASK ;
// calculate a checksum on some of the essential data used
clientDataChecksum = declManager - > GetChecksum ( ) ;
// start challenging the server
clientState = CS_CHALLENGING ;
active = true ;
guiNetMenu = uiManager - > FindGui ( " guis/netmenu.gui " , true , false , true ) ;
guiNetMenu - > SetStateString ( " status " , va ( common - > GetLanguageDict ( ) - > GetString ( " #str_06749 " ) , Sys_NetAdrToString ( adr ) ) ) ;
session - > SetGUI ( guiNetMenu , HandleGuiCommand ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : Reconnect
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : Reconnect ( void ) {
ConnectToServer ( serverAddress ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ConnectToServer
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ConnectToServer ( const char * address ) {
int serverNum ;
netadr_t adr ;
if ( idStr : : IsNumeric ( address ) ) {
serverNum = atoi ( address ) ;
if ( serverNum < 0 | | serverNum > = serverList . Num ( ) ) {
session - > MessageBox ( MSG_OK , va ( common - > GetLanguageDict ( ) - > GetString ( " #str_06733 " ) , serverNum ) , common - > GetLanguageDict ( ) - > GetString ( " #str_06735 " ) , true ) ;
return ;
}
adr = serverList [ serverNum ] . adr ;
} else {
if ( ! Sys_StringToNetAdr ( address , & adr , true ) ) {
session - > MessageBox ( MSG_OK , va ( common - > GetLanguageDict ( ) - > GetString ( " #str_06734 " ) , address ) , common - > GetLanguageDict ( ) - > GetString ( " #str_06735 " ) , true ) ;
return ;
}
}
if ( ! adr . port ) {
adr . port = PORT_SERVER ;
}
common - > Printf ( " \" %s \" resolved to %s \n " , address , Sys_NetAdrToString ( adr ) ) ;
ConnectToServer ( adr ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : DisconnectFromServer
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : DisconnectFromServer ( void ) {
idBitMsg msg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
if ( clientState > = CS_CONNECTED ) {
// if we were actually connected, clear the pure list
fileSystem - > ClearPureChecksums ( ) ;
// send reliable disconnect to server
msg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
msg . WriteByte ( CLIENT_RELIABLE_MESSAGE_DISCONNECT ) ;
msg . WriteString ( " disconnect " ) ;
if ( ! channel . SendReliableMessage ( msg ) ) {
common - > Error ( " client->server reliable messages overflow \n " ) ;
}
SendEmptyToServer ( true ) ;
SendEmptyToServer ( true ) ;
SendEmptyToServer ( true ) ;
}
if ( clientState ! = CS_PURERESTART ) {
channel . Shutdown ( ) ;
clientState = CS_DISCONNECTED ;
}
active = false ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : GetServerInfo
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : GetServerInfo ( const netadr_t adr ) {
idBitMsg msg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
if ( ! InitPort ( ) ) {
return ;
}
msg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
msg . WriteShort ( CONNECTIONLESS_MESSAGE_ID ) ;
msg . WriteString ( " getInfo " ) ;
2012-06-28 11:15:40 +00:00
msg . WriteInt ( serverList . GetChallenge ( ) ) ; // challenge
2011-11-22 21:28:15 +00:00
2011-12-06 18:20:15 +00:00
clientPort . SendPacket ( adr , msg . GetData ( ) , msg . GetSize ( ) ) ;
2011-11-22 21:28:15 +00:00
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : GetServerInfo
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : GetServerInfo ( const char * address ) {
netadr_t adr ;
if ( address & & * address ! = ' \0 ' ) {
if ( ! Sys_StringToNetAdr ( address , & adr , true ) ) {
common - > Printf ( " Couldn't get server address for \" %s \" \n " , address ) ;
return ;
}
} else if ( active ) {
adr = serverAddress ;
} else if ( idAsyncNetwork : : server . IsActive ( ) ) {
// used to be a Sys_StringToNetAdr( "localhost", &adr, true ); and send a packet over loopback
// but this breaks with net_ip ( typically, for multi-homed servers )
idAsyncNetwork : : server . PrintLocalServerInfo ( ) ;
return ;
} else {
common - > Printf ( " no server found \n " ) ;
return ;
}
if ( ! adr . port ) {
adr . port = PORT_SERVER ;
}
GetServerInfo ( adr ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : GetLANServers
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : GetLANServers ( void ) {
int i ;
idBitMsg msg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
netadr_t broadcastAddress ;
if ( ! InitPort ( ) ) {
return ;
}
idAsyncNetwork : : LANServer . SetBool ( true ) ;
serverList . SetupLANScan ( ) ;
msg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
msg . WriteShort ( CONNECTIONLESS_MESSAGE_ID ) ;
msg . WriteString ( " getInfo " ) ;
2012-06-28 11:15:40 +00:00
msg . WriteInt ( serverList . GetChallenge ( ) ) ;
2011-11-22 21:28:15 +00:00
broadcastAddress . type = NA_BROADCAST ;
for ( i = 0 ; i < MAX_SERVER_PORTS ; i + + ) {
broadcastAddress . port = PORT_SERVER + i ;
clientPort . SendPacket ( broadcastAddress , msg . GetData ( ) , msg . GetSize ( ) ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : GetNETServers
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : GetNETServers ( void ) {
idBitMsg msg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
idAsyncNetwork : : LANServer . SetBool ( false ) ;
// NetScan only clears GUI and results, not the stored list
serverList . Clear ( ) ;
serverList . NetScan ( ) ;
serverList . StartServers ( true ) ;
msg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
msg . WriteShort ( CONNECTIONLESS_MESSAGE_ID ) ;
msg . WriteString ( " getServers " ) ;
2012-06-28 11:15:40 +00:00
msg . WriteInt ( ASYNC_PROTOCOL_VERSION ) ;
2011-11-22 21:28:15 +00:00
msg . WriteString ( cvarSystem - > GetCVarString ( " fs_game " ) ) ;
msg . WriteBits ( cvarSystem - > GetCVarInteger ( " gui_filter_password " ) , 2 ) ;
msg . WriteBits ( cvarSystem - > GetCVarInteger ( " gui_filter_players " ) , 2 ) ;
msg . WriteBits ( cvarSystem - > GetCVarInteger ( " gui_filter_gameType " ) , 2 ) ;
netadr_t adr ;
if ( idAsyncNetwork : : GetMasterAddress ( 0 , adr ) ) {
clientPort . SendPacket ( adr , msg . GetData ( ) , msg . GetSize ( ) ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ListServers
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ListServers ( void ) {
int i ;
for ( i = 0 ; i < serverList . Num ( ) ; i + + ) {
common - > Printf ( " %3d: %s %dms (%s) \n " , i , serverList [ i ] . serverInfo . GetString ( " si_name " ) , serverList [ i ] . ping , Sys_NetAdrToString ( serverList [ i ] . adr ) ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ClearServers
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ClearServers ( void ) {
serverList . Clear ( ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : RemoteConsole
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : RemoteConsole ( const char * command ) {
netadr_t adr ;
idBitMsg msg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
if ( ! InitPort ( ) ) {
return ;
}
if ( active ) {
adr = serverAddress ;
} else {
Sys_StringToNetAdr ( idAsyncNetwork : : clientRemoteConsoleAddress . GetString ( ) , & adr , true ) ;
}
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
if ( ! adr . port ) {
adr . port = PORT_SERVER ;
}
lastRconAddress = adr ;
lastRconTime = realTime ;
msg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
msg . WriteShort ( CONNECTIONLESS_MESSAGE_ID ) ;
msg . WriteString ( " rcon " ) ;
msg . WriteString ( idAsyncNetwork : : clientRemoteConsolePassword . GetString ( ) ) ;
msg . WriteString ( command ) ;
2011-12-06 18:20:15 +00:00
clientPort . SendPacket ( adr , msg . GetData ( ) , msg . GetSize ( ) ) ;
2011-11-22 21:28:15 +00:00
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : GetPrediction
= = = = = = = = = = = = = = = = = =
*/
int idAsyncClient : : GetPrediction ( void ) const {
if ( clientState < CS_CONNECTED ) {
return - 1 ;
} else {
return clientPrediction ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : GetTimeSinceLastPacket
= = = = = = = = = = = = = = = = = =
*/
int idAsyncClient : : GetTimeSinceLastPacket ( void ) const {
if ( clientState < CS_CONNECTED ) {
return - 1 ;
} else {
return clientTime - lastPacketTime ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : GetOutgoingRate
= = = = = = = = = = = = = = = = = =
*/
int idAsyncClient : : GetOutgoingRate ( void ) const {
if ( clientState < CS_CONNECTED ) {
return - 1 ;
} else {
return channel . GetOutgoingRate ( ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : GetIncomingRate
= = = = = = = = = = = = = = = = = =
*/
int idAsyncClient : : GetIncomingRate ( void ) const {
if ( clientState < CS_CONNECTED ) {
return - 1 ;
} else {
return channel . GetIncomingRate ( ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : GetOutgoingCompression
= = = = = = = = = = = = = = = = = =
*/
float idAsyncClient : : GetOutgoingCompression ( void ) const {
if ( clientState < CS_CONNECTED ) {
return 0.0f ;
} else {
return channel . GetOutgoingCompression ( ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : GetIncomingCompression
= = = = = = = = = = = = = = = = = =
*/
float idAsyncClient : : GetIncomingCompression ( void ) const {
if ( clientState < CS_CONNECTED ) {
return 0.0f ;
} else {
return channel . GetIncomingCompression ( ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : GetIncomingPacketLoss
= = = = = = = = = = = = = = = = = =
*/
float idAsyncClient : : GetIncomingPacketLoss ( void ) const {
if ( clientState < CS_CONNECTED ) {
return 0.0f ;
} else {
return channel . GetIncomingPacketLoss ( ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : DuplicateUsercmds
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : DuplicateUsercmds ( int frame , int time ) {
int i , previousIndex , currentIndex ;
previousIndex = ( frame - 1 ) & ( MAX_USERCMD_BACKUP - 1 ) ;
currentIndex = frame & ( MAX_USERCMD_BACKUP - 1 ) ;
// duplicate previous user commands if no new commands are available for a client
for ( i = 0 ; i < MAX_ASYNC_CLIENTS ; i + + ) {
idAsyncNetwork : : DuplicateUsercmd ( userCmds [ previousIndex ] [ i ] , userCmds [ currentIndex ] [ i ] , frame , time ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : SendUserInfoToServer
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : SendUserInfoToServer ( void ) {
idBitMsg msg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
idDict info ;
if ( clientState < CS_CONNECTED ) {
return ;
}
info = * cvarSystem - > MoveCVarsToDict ( CVAR_USERINFO ) ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
// send reliable client info to server
msg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
msg . WriteByte ( CLIENT_RELIABLE_MESSAGE_CLIENTINFO ) ;
msg . WriteDeltaDict ( info , & sessLocal . mapSpawnData . userInfo [ clientNum ] ) ;
if ( ! channel . SendReliableMessage ( msg ) ) {
common - > Error ( " client->server reliable messages overflow \n " ) ;
}
sessLocal . mapSpawnData . userInfo [ clientNum ] = info ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : SendEmptyToServer
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : SendEmptyToServer ( bool force , bool mapLoad ) {
idBitMsg msg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
if ( lastEmptyTime > realTime ) {
lastEmptyTime = realTime ;
}
if ( ! force & & ( realTime - lastEmptyTime < EMPTY_RESEND_TIME ) ) {
return ;
}
if ( idAsyncNetwork : : verbose . GetInteger ( ) ) {
common - > Printf ( " sending empty to server, gameInitId = %d \n " , mapLoad ? GAME_INIT_ID_MAP_LOAD : gameInitId ) ;
}
msg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
2012-06-28 11:15:40 +00:00
msg . WriteInt ( serverMessageSequence ) ;
msg . WriteInt ( mapLoad ? GAME_INIT_ID_MAP_LOAD : gameInitId ) ;
msg . WriteInt ( snapshotSequence ) ;
2011-11-22 21:28:15 +00:00
msg . WriteByte ( CLIENT_UNRELIABLE_MESSAGE_EMPTY ) ;
channel . SendMessage ( clientPort , clientTime , msg ) ;
while ( channel . UnsentFragmentsLeft ( ) ) {
channel . SendNextFragment ( clientPort , clientTime ) ;
}
lastEmptyTime = realTime ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : SendPingResponseToServer
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : SendPingResponseToServer ( int time ) {
idBitMsg msg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
if ( idAsyncNetwork : : verbose . GetInteger ( ) = = 2 ) {
common - > Printf ( " sending ping response to server, gameInitId = %d \n " , gameInitId ) ;
}
msg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
2012-06-28 11:15:40 +00:00
msg . WriteInt ( serverMessageSequence ) ;
msg . WriteInt ( gameInitId ) ;
msg . WriteInt ( snapshotSequence ) ;
2011-11-22 21:28:15 +00:00
msg . WriteByte ( CLIENT_UNRELIABLE_MESSAGE_PINGRESPONSE ) ;
2012-06-28 11:15:40 +00:00
msg . WriteInt ( time ) ;
2011-11-22 21:28:15 +00:00
channel . SendMessage ( clientPort , clientTime , msg ) ;
while ( channel . UnsentFragmentsLeft ( ) ) {
channel . SendNextFragment ( clientPort , clientTime ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : SendUsercmdsToServer
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : SendUsercmdsToServer ( void ) {
int i , numUsercmds , index ;
idBitMsg msg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
usercmd_t * last ;
if ( idAsyncNetwork : : verbose . GetInteger ( ) = = 2 ) {
common - > Printf ( " sending usercmd to server: gameInitId = %d, gameFrame = %d, gameTime = %d \n " , gameInitId , gameFrame , gameTime ) ;
}
// generate user command for this client
index = gameFrame & ( MAX_USERCMD_BACKUP - 1 ) ;
userCmds [ index ] [ clientNum ] = usercmdGen - > GetDirectUsercmd ( ) ;
userCmds [ index ] [ clientNum ] . gameFrame = gameFrame ;
userCmds [ index ] [ clientNum ] . gameTime = gameTime ;
// send the user commands to the server
msg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
2012-06-28 11:15:40 +00:00
msg . WriteInt ( serverMessageSequence ) ;
msg . WriteInt ( gameInitId ) ;
msg . WriteInt ( snapshotSequence ) ;
2011-11-22 21:28:15 +00:00
msg . WriteByte ( CLIENT_UNRELIABLE_MESSAGE_USERCMD ) ;
msg . WriteShort ( clientPrediction ) ;
numUsercmds = idMath : : ClampInt ( 0 , 10 , idAsyncNetwork : : clientUsercmdBackup . GetInteger ( ) ) + 1 ;
// write the user commands
2012-06-28 11:15:40 +00:00
msg . WriteInt ( gameFrame ) ;
2011-11-22 21:28:15 +00:00
msg . WriteByte ( numUsercmds ) ;
for ( last = NULL , i = gameFrame - numUsercmds + 1 ; i < = gameFrame ; i + + ) {
index = i & ( MAX_USERCMD_BACKUP - 1 ) ;
idAsyncNetwork : : WriteUserCmdDelta ( msg , userCmds [ index ] [ clientNum ] , last ) ;
last = & userCmds [ index ] [ clientNum ] ;
}
channel . SendMessage ( clientPort , clientTime , msg ) ;
while ( channel . UnsentFragmentsLeft ( ) ) {
channel . SendNextFragment ( clientPort , clientTime ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : InitGame
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : InitGame ( int serverGameInitId , int serverGameFrame , int serverGameTime , const idDict & serverSI ) {
gameInitId = serverGameInitId ;
gameFrame = snapshotGameFrame = serverGameFrame ;
gameTime = snapshotGameTime = serverGameTime ;
gameTimeResidual = 0 ;
memset ( userCmds , 0 , sizeof ( userCmds ) ) ;
for ( int i = 0 ; i < MAX_ASYNC_CLIENTS ; i + + ) {
sessLocal . mapSpawnData . userInfo [ i ] . Clear ( ) ;
}
sessLocal . mapSpawnData . serverInfo = serverSI ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ProcessUnreliableServerMessage
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ProcessUnreliableServerMessage ( const idBitMsg & msg ) {
int i , j , index , id , numDuplicatedUsercmds , aheadOfServer , numUsercmds , delta ;
int serverGameInitId , serverGameFrame , serverGameTime ;
idDict serverSI ;
usercmd_t * last ;
bool pureWait ;
2012-06-28 11:19:14 +00:00
serverGameInitId = msg . ReadInt ( ) ;
2011-11-22 21:28:15 +00:00
id = msg . ReadByte ( ) ;
switch ( id ) {
case SERVER_UNRELIABLE_MESSAGE_EMPTY : {
if ( idAsyncNetwork : : verbose . GetInteger ( ) ) {
common - > Printf ( " received empty message from server \n " ) ;
}
break ;
}
case SERVER_UNRELIABLE_MESSAGE_PING : {
if ( idAsyncNetwork : : verbose . GetInteger ( ) = = 2 ) {
common - > Printf ( " received ping message from server \n " ) ;
}
2012-06-28 11:19:14 +00:00
SendPingResponseToServer ( msg . ReadInt ( ) ) ;
2011-11-22 21:28:15 +00:00
break ;
}
case SERVER_UNRELIABLE_MESSAGE_GAMEINIT : {
2012-06-28 11:19:14 +00:00
serverGameFrame = msg . ReadInt ( ) ;
serverGameTime = msg . ReadInt ( ) ;
2011-11-22 21:28:15 +00:00
msg . ReadDeltaDict ( serverSI , NULL ) ;
pureWait = serverSI . GetBool ( " si_pure " ) ;
InitGame ( serverGameInitId , serverGameFrame , serverGameTime , serverSI ) ;
channel . ResetRate ( ) ;
if ( idAsyncNetwork : : verbose . GetInteger ( ) ) {
common - > Printf ( " received gameinit, gameInitId = %d, gameFrame = %d, gameTime = %d \n " , gameInitId , gameFrame , gameTime ) ;
}
// mute sound
soundSystem - > SetMute ( true ) ;
// ensure chat icon goes away when the GUI is changed...
//cvarSystem->SetCVarBool( "ui_chat", false );
if ( pureWait ) {
guiNetMenu = uiManager - > FindGui ( " guis/netmenu.gui " , true , false , true ) ;
session - > SetGUI ( guiNetMenu , HandleGuiCommand ) ;
session - > MessageBox ( MSG_ABORT , common - > GetLanguageDict ( ) - > GetString ( " #str_04317 " ) , common - > GetLanguageDict ( ) - > GetString ( " #str_04318 " ) , false , " pure_abort " ) ;
} else {
// load map
session - > SetGUI ( NULL , NULL ) ;
sessLocal . ExecuteMapChange ( ) ;
}
break ;
}
case SERVER_UNRELIABLE_MESSAGE_SNAPSHOT : {
// if the snapshot is from a different game
if ( serverGameInitId ! = gameInitId ) {
if ( idAsyncNetwork : : verbose . GetInteger ( ) ) {
common - > Printf ( " ignoring snapshot with != gameInitId \n " ) ;
}
break ;
}
2012-06-28 11:19:14 +00:00
snapshotSequence = msg . ReadInt ( ) ;
snapshotGameFrame = msg . ReadInt ( ) ;
snapshotGameTime = msg . ReadInt ( ) ;
2011-11-22 21:28:15 +00:00
numDuplicatedUsercmds = msg . ReadByte ( ) ;
aheadOfServer = msg . ReadShort ( ) ;
// read the game snapshot
game - > ClientReadSnapshot ( clientNum , snapshotSequence , snapshotGameFrame , snapshotGameTime , numDuplicatedUsercmds , aheadOfServer , msg ) ;
// read user commands of other clients from the snapshot
for ( last = NULL , i = msg . ReadByte ( ) ; i < MAX_ASYNC_CLIENTS ; i = msg . ReadByte ( ) ) {
numUsercmds = msg . ReadByte ( ) ;
if ( numUsercmds > MAX_USERCMD_RELAY ) {
common - > Error ( " snapshot %d contains too many user commands for client %d " , snapshotSequence , i ) ;
break ;
}
for ( j = 0 ; j < numUsercmds ; j + + ) {
index = ( snapshotGameFrame + j ) & ( MAX_USERCMD_BACKUP - 1 ) ;
idAsyncNetwork : : ReadUserCmdDelta ( msg , userCmds [ index ] [ i ] , last ) ;
userCmds [ index ] [ i ] . gameFrame = snapshotGameFrame + j ;
userCmds [ index ] [ i ] . duplicateCount = 0 ;
last = & userCmds [ index ] [ i ] ;
}
// clear all user commands after the ones just read from the snapshot
for ( j = numUsercmds ; j < MAX_USERCMD_BACKUP ; j + + ) {
index = ( snapshotGameFrame + j ) & ( MAX_USERCMD_BACKUP - 1 ) ;
userCmds [ index ] [ i ] . gameFrame = 0 ;
userCmds [ index ] [ i ] . gameTime = 0 ;
}
}
// if this is the first snapshot after a game init was received
if ( clientState = = CS_CONNECTED ) {
gameTimeResidual = 0 ;
clientState = CS_INGAME ;
assert ( ! sessLocal . GetActiveMenu ( ) ) ;
if ( idAsyncNetwork : : verbose . GetInteger ( ) ) {
common - > Printf ( " received first snapshot, gameInitId = %d, gameFrame %d gameTime %d \n " , gameInitId , snapshotGameFrame , snapshotGameTime ) ;
}
}
// if the snapshot is newer than the clients current game time
if ( gameTime < snapshotGameTime | | gameTime > snapshotGameTime + idAsyncNetwork : : clientMaxPrediction . GetInteger ( ) ) {
gameFrame = snapshotGameFrame ;
gameTime = snapshotGameTime ;
gameTimeResidual = idMath : : ClampInt ( - idAsyncNetwork : : clientMaxPrediction . GetInteger ( ) , idAsyncNetwork : : clientMaxPrediction . GetInteger ( ) , gameTimeResidual ) ;
clientPredictTime = idMath : : ClampInt ( - idAsyncNetwork : : clientMaxPrediction . GetInteger ( ) , idAsyncNetwork : : clientMaxPrediction . GetInteger ( ) , clientPredictTime ) ;
}
// adjust the client prediction time based on the snapshot time
clientPrediction - = ( 1 - ( INTSIGNBITSET ( aheadOfServer - idAsyncNetwork : : clientPrediction . GetInteger ( ) ) < < 1 ) ) ;
clientPrediction = idMath : : ClampInt ( idAsyncNetwork : : clientPrediction . GetInteger ( ) , idAsyncNetwork : : clientMaxPrediction . GetInteger ( ) , clientPrediction ) ;
delta = gameTime - ( snapshotGameTime + clientPrediction ) ;
clientPredictTime - = ( delta / PREDICTION_FAST_ADJUST ) + ( 1 - ( INTSIGNBITSET ( delta ) < < 1 ) ) ;
lastSnapshotTime = clientTime ;
if ( idAsyncNetwork : : verbose . GetInteger ( ) = = 2 ) {
common - > Printf ( " received snapshot, gameInitId = %d, gameFrame = %d, gameTime = %d \n " , gameInitId , gameFrame , gameTime ) ;
}
if ( numDuplicatedUsercmds & & ( idAsyncNetwork : : verbose . GetInteger ( ) = = 2 ) ) {
common - > Printf ( " server duplicated %d user commands before snapshot %d \n " , numDuplicatedUsercmds , snapshotGameFrame ) ;
}
break ;
}
default : {
common - > Printf ( " unknown unreliable server message %d \n " , id ) ;
break ;
}
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ProcessReliableMessagePure
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ProcessReliableMessagePure ( const idBitMsg & msg ) {
idBitMsg outMsg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
int inChecksums [ MAX_PURE_PAKS ] ;
int i ;
int serverGameInitId ;
session - > SetGUI ( NULL , NULL ) ;
2012-06-28 11:19:14 +00:00
serverGameInitId = msg . ReadInt ( ) ;
2011-11-22 21:28:15 +00:00
if ( serverGameInitId ! = gameInitId ) {
common - > DPrintf ( " ignoring pure server checksum from an outdated gameInitId (%d) \n " , serverGameInitId ) ;
return ;
}
if ( ! ValidatePureServerChecksums ( serverAddress , msg ) ) {
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
return ;
}
if ( idAsyncNetwork : : verbose . GetInteger ( ) ) {
common - > Printf ( " received new pure server info. ExecuteMapChange and report back \n " ) ;
}
// it is now ok to load the next map with updated pure checksums
sessLocal . ExecuteMapChange ( true ) ;
// upon receiving our pure list, the server will send us SCS_INGAME and we'll start getting snapshots
2012-07-03 21:52:35 +00:00
fileSystem - > GetPureServerChecksums ( inChecksums ) ;
2011-11-22 21:28:15 +00:00
outMsg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
outMsg . WriteByte ( CLIENT_RELIABLE_MESSAGE_PURE ) ;
2012-06-28 11:15:40 +00:00
outMsg . WriteInt ( gameInitId ) ;
2011-11-22 21:28:15 +00:00
i = 0 ;
while ( inChecksums [ i ] ) {
2012-06-28 11:15:40 +00:00
outMsg . WriteInt ( inChecksums [ i + + ] ) ;
2011-11-22 21:28:15 +00:00
}
2012-06-28 11:15:40 +00:00
outMsg . WriteInt ( 0 ) ;
2011-11-22 21:28:15 +00:00
if ( ! channel . SendReliableMessage ( outMsg ) ) {
common - > Error ( " client->server reliable messages overflow \n " ) ;
}
}
/*
= = = = = = = = = = = = = = =
idAsyncClient : : ReadLocalizedServerString
= = = = = = = = = = = = = = =
*/
void idAsyncClient : : ReadLocalizedServerString ( const idBitMsg & msg , char * out , int maxLen ) {
msg . ReadString ( out , maxLen ) ;
// look up localized string. if the message is not an #str_ format, we'll just get it back unchanged
idStr : : snPrintf ( out , maxLen - 1 , " %s " , common - > GetLanguageDict ( ) - > GetString ( out ) ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ProcessReliableServerMessages
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ProcessReliableServerMessages ( void ) {
idBitMsg msg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
byte id ;
msg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
while ( channel . GetReliableMessage ( msg ) ) {
id = msg . ReadByte ( ) ;
switch ( id ) {
case SERVER_RELIABLE_MESSAGE_CLIENTINFO : {
int clientNum ;
clientNum = msg . ReadByte ( ) ;
idDict & info = sessLocal . mapSpawnData . userInfo [ clientNum ] ;
bool haveBase = ( msg . ReadBits ( 1 ) ! = 0 ) ;
# if ID_CLIENTINFO_TAGS
int checksum = info . Checksum ( ) ;
2012-06-28 11:19:14 +00:00
int srv_checksum = msg . ReadInt ( ) ;
2011-11-22 21:28:15 +00:00
if ( checksum ! = srv_checksum ) {
common - > DPrintf ( " SERVER_RELIABLE_MESSAGE_CLIENTINFO %d (haveBase: %s): != checksums srv: 0x%x local: 0x%x \n " , clientNum , haveBase ? " true " : " false " , checksum , srv_checksum ) ;
info . Print ( ) ;
} else {
common - > DPrintf ( " SERVER_RELIABLE_MESSAGE_CLIENTINFO %d (haveBase: %s): checksums ok 0x%x \n " , clientNum , haveBase ? " true " : " false " , checksum ) ;
}
# endif
if ( haveBase ) {
msg . ReadDeltaDict ( info , & info ) ;
} else {
msg . ReadDeltaDict ( info , NULL ) ;
}
// server forces us to a different userinfo
if ( clientNum = = idAsyncClient : : clientNum ) {
common - > DPrintf ( " local user info modified by server \n " ) ;
cvarSystem - > SetCVarsFromDict ( info ) ;
cvarSystem - > ClearModifiedFlags ( CVAR_USERINFO ) ; // don't emit back
}
game - > SetUserInfo ( clientNum , info , true , false ) ;
break ;
}
case SERVER_RELIABLE_MESSAGE_SYNCEDCVARS : {
idDict & info = sessLocal . mapSpawnData . syncedCVars ;
msg . ReadDeltaDict ( info , & info ) ;
cvarSystem - > SetCVarsFromDict ( info ) ;
if ( ! idAsyncNetwork : : allowCheats . GetBool ( ) ) {
cvarSystem - > ResetFlaggedVariables ( CVAR_CHEAT ) ;
}
break ;
}
case SERVER_RELIABLE_MESSAGE_PRINT : {
char string [ MAX_STRING_CHARS ] ;
msg . ReadString ( string , MAX_STRING_CHARS ) ;
common - > Printf ( " %s \n " , string ) ;
break ;
}
case SERVER_RELIABLE_MESSAGE_DISCONNECT : {
int clientNum ;
char string [ MAX_STRING_CHARS ] ;
2012-06-28 11:19:14 +00:00
clientNum = msg . ReadInt ( ) ;
2011-11-22 21:28:15 +00:00
ReadLocalizedServerString ( msg , string , MAX_STRING_CHARS ) ;
if ( clientNum = = idAsyncClient : : clientNum ) {
session - > Stop ( ) ;
session - > MessageBox ( MSG_OK , string , common - > GetLanguageDict ( ) - > GetString ( " #str_04319 " ) , true ) ;
session - > StartMenu ( ) ;
} else {
common - > Printf ( " client %d %s \n " , clientNum , string ) ;
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , va ( " addChatLine \" %s^0 %s \" " , sessLocal . mapSpawnData . userInfo [ clientNum ] . GetString ( " ui_name " ) , string ) ) ;
sessLocal . mapSpawnData . userInfo [ clientNum ] . Clear ( ) ;
}
break ;
}
case SERVER_RELIABLE_MESSAGE_APPLYSNAPSHOT : {
int sequence ;
2012-06-28 11:19:14 +00:00
sequence = msg . ReadInt ( ) ;
2011-11-22 21:28:15 +00:00
if ( ! game - > ClientApplySnapshot ( clientNum , sequence ) ) {
session - > Stop ( ) ;
common - > Error ( " couldn't apply snapshot %d " , sequence ) ;
}
break ;
}
case SERVER_RELIABLE_MESSAGE_PURE : {
ProcessReliableMessagePure ( msg ) ;
break ;
}
case SERVER_RELIABLE_MESSAGE_RELOAD : {
if ( idAsyncNetwork : : verbose . GetBool ( ) ) {
common - > Printf ( " got MESSAGE_RELOAD from server \n " ) ;
}
// simply reconnect, so that if the server restarts in pure mode we can get the right list and avoid spurious reloads
cmdSystem - > BufferCommandText ( CMD_EXEC_APPEND , " reconnect \n " ) ;
break ;
}
case SERVER_RELIABLE_MESSAGE_ENTERGAME : {
SendUserInfoToServer ( ) ;
game - > SetUserInfo ( clientNum , sessLocal . mapSpawnData . userInfo [ clientNum ] , true , false ) ;
cvarSystem - > ClearModifiedFlags ( CVAR_USERINFO ) ;
break ;
}
default : {
// pass reliable message on to game code
game - > ClientProcessReliableMessage ( clientNum , msg ) ;
break ;
}
}
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ProcessChallengeResponseMessage
= = = = = = = = = = = = = = = = = =
*/
2011-12-06 18:20:15 +00:00
void idAsyncClient : : ProcessChallengeResponseMessage ( const netadr_t from , const idBitMsg & msg ) {
2011-11-22 21:28:15 +00:00
char serverGame [ MAX_STRING_CHARS ] , serverGameBase [ MAX_STRING_CHARS ] ;
if ( clientState ! = CS_CHALLENGING ) {
common - > Printf ( " Unwanted challenge response received. \n " ) ;
return ;
}
2012-06-28 11:19:14 +00:00
serverChallenge = msg . ReadInt ( ) ;
2011-11-22 21:28:15 +00:00
serverId = msg . ReadShort ( ) ;
msg . ReadString ( serverGameBase , MAX_STRING_CHARS ) ;
msg . ReadString ( serverGame , MAX_STRING_CHARS ) ;
// the server is running a different game... we need to reload in the correct fs_game
// even pure pak checks would fail if we didn't, as there are files we may not even see atm
// NOTE: we could read the pure list from the server at the same time and set it up for the restart
// ( if the client can restart directly with the right pak order, then we avoid an extra reloadEngine later.. )
if ( idStr : : Icmp ( cvarSystem - > GetCVarString ( " fs_game_base " ) , serverGameBase ) | |
idStr : : Icmp ( cvarSystem - > GetCVarString ( " fs_game " ) , serverGame ) ) {
// bug #189 - if the server is running ROE and ROE is not locally installed, refuse to connect or we might crash
if ( ! fileSystem - > HasD3XP ( ) & & ( ! idStr : : Icmp ( serverGameBase , " d3xp " ) | | ! idStr : : Icmp ( serverGame , " d3xp " ) ) ) {
common - > Printf ( " The server is running Doom3: Resurrection of Evil expansion pack. RoE is not installed on this client. Aborting the connection.. \n " ) ;
cmdSystem - > BufferCommandText ( CMD_EXEC_APPEND , " disconnect \n " ) ;
return ;
}
common - > Printf ( " The server is running a different mod (%s-%s). Restarting.. \n " , serverGameBase , serverGame ) ;
cvarSystem - > SetCVarString ( " fs_game_base " , serverGameBase ) ;
cvarSystem - > SetCVarString ( " fs_game " , serverGame ) ;
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , " reloadEngine " ) ;
cmdSystem - > BufferCommandText ( CMD_EXEC_APPEND , " reconnect \n " ) ;
return ;
}
common - > Printf ( " received challenge response 0x%x from %s \n " , serverChallenge , Sys_NetAdrToString ( from ) ) ;
// start sending connect packets instead of challenge request packets
clientState = CS_CONNECTING ;
lastConnectTime = - 9999 ;
// take this address as the new server address. This allows
// a server proxy to hand off connections to multiple servers
serverAddress = from ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ProcessConnectResponseMessage
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ProcessConnectResponseMessage ( const netadr_t from , const idBitMsg & msg ) {
int serverGameInitId , serverGameFrame , serverGameTime ;
idDict serverSI ;
if ( clientState > = CS_CONNECTED ) {
common - > Printf ( " Duplicate connect received. \n " ) ;
return ;
}
if ( clientState ! = CS_CONNECTING ) {
common - > Printf ( " Connect response packet while not connecting. \n " ) ;
return ;
}
if ( ! Sys_CompareNetAdrBase ( from , serverAddress ) ) {
common - > Printf ( " Connect response from a different server. \n " ) ;
common - > Printf ( " %s should have been %s \n " , Sys_NetAdrToString ( from ) , Sys_NetAdrToString ( serverAddress ) ) ;
return ;
}
common - > Printf ( " received connect response from %s \n " , Sys_NetAdrToString ( from ) ) ;
channel . Init ( from , clientId ) ;
2012-06-28 11:19:14 +00:00
clientNum = msg . ReadInt ( ) ;
2011-11-22 21:28:15 +00:00
clientState = CS_CONNECTED ;
lastPacketTime = - 9999 ;
2012-06-28 11:19:14 +00:00
serverGameInitId = msg . ReadInt ( ) ;
serverGameFrame = msg . ReadInt ( ) ;
serverGameTime = msg . ReadInt ( ) ;
2011-11-22 21:28:15 +00:00
msg . ReadDeltaDict ( serverSI , NULL ) ;
InitGame ( serverGameInitId , serverGameFrame , serverGameTime , serverSI ) ;
// load map
session - > SetGUI ( NULL , NULL ) ;
sessLocal . ExecuteMapChange ( ) ;
clientPredictTime = clientPrediction = idMath : : ClampInt ( 0 , idAsyncNetwork : : clientMaxPrediction . GetInteger ( ) , clientTime - lastConnectTime ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ProcessDisconnectMessage
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ProcessDisconnectMessage ( const netadr_t from , const idBitMsg & msg ) {
if ( clientState = = CS_DISCONNECTED ) {
common - > Printf ( " Disconnect packet while not connected. \n " ) ;
return ;
}
if ( ! Sys_CompareNetAdrBase ( from , serverAddress ) ) {
common - > Printf ( " Disconnect packet from unknown server. \n " ) ;
return ;
}
session - > Stop ( ) ;
session - > MessageBox ( MSG_OK , common - > GetLanguageDict ( ) - > GetString ( " #str_04320 " ) , NULL , true ) ;
session - > StartMenu ( ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ProcessInfoResponseMessage
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ProcessInfoResponseMessage ( const netadr_t from , const idBitMsg & msg ) {
int i , protocol , index ;
networkServer_t serverInfo ;
bool verbose = false ;
if ( from . type = = NA_LOOPBACK | | cvarSystem - > GetCVarBool ( " developer " ) ) {
verbose = true ;
}
serverInfo . clients = 0 ;
serverInfo . adr = from ;
2012-06-28 11:19:14 +00:00
serverInfo . challenge = msg . ReadInt ( ) ; // challenge
protocol = msg . ReadInt ( ) ;
2011-11-22 21:28:15 +00:00
if ( protocol ! = ASYNC_PROTOCOL_VERSION ) {
common - > Printf ( " server %s ignored - protocol %d.%d, expected %d.%d \n " , Sys_NetAdrToString ( serverInfo . adr ) , protocol > > 16 , protocol & 0xffff , ASYNC_PROTOCOL_MAJOR , ASYNC_PROTOCOL_MINOR ) ;
return ;
}
msg . ReadDeltaDict ( serverInfo . serverInfo , NULL ) ;
if ( verbose ) {
common - > Printf ( " server IP = %s \n " , Sys_NetAdrToString ( serverInfo . adr ) ) ;
serverInfo . serverInfo . Print ( ) ;
}
for ( i = msg . ReadByte ( ) ; i < MAX_ASYNC_CLIENTS ; i = msg . ReadByte ( ) ) {
serverInfo . pings [ serverInfo . clients ] = msg . ReadShort ( ) ;
2012-06-28 11:19:14 +00:00
serverInfo . rate [ serverInfo . clients ] = msg . ReadInt ( ) ;
2011-11-22 21:28:15 +00:00
msg . ReadString ( serverInfo . nickname [ serverInfo . clients ] , MAX_NICKLEN ) ;
if ( verbose ) {
common - > Printf ( " client %2d: %s, ping = %d, rate = %d \n " , i , serverInfo . nickname [ serverInfo . clients ] , serverInfo . pings [ serverInfo . clients ] , serverInfo . rate [ serverInfo . clients ] ) ;
}
serverInfo . clients + + ;
}
index = serverList . InfoResponse ( serverInfo ) ;
common - > Printf ( " %d: server %s - protocol %d.%d - %s \n " , index , Sys_NetAdrToString ( serverInfo . adr ) , protocol > > 16 , protocol & 0xffff , serverInfo . serverInfo . GetString ( " si_name " ) ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ProcessPrintMessage
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ProcessPrintMessage ( const netadr_t from , const idBitMsg & msg ) {
char string [ MAX_STRING_CHARS ] ;
int opcode ;
int game_opcode = ALLOW_YES ;
const char * retpass ;
2012-06-28 11:19:14 +00:00
opcode = msg . ReadInt ( ) ;
2011-11-22 21:28:15 +00:00
if ( opcode = = SERVER_PRINT_GAMEDENY ) {
2012-06-28 11:19:14 +00:00
game_opcode = msg . ReadInt ( ) ;
2011-11-22 21:28:15 +00:00
}
ReadLocalizedServerString ( msg , string , MAX_STRING_CHARS ) ;
common - > Printf ( " %s \n " , string ) ;
guiNetMenu - > SetStateString ( " status " , string ) ;
if ( opcode = = SERVER_PRINT_GAMEDENY ) {
if ( game_opcode = = ALLOW_BADPASS ) {
retpass = session - > MessageBox ( MSG_PROMPT , common - > GetLanguageDict ( ) - > GetString ( " #str_04321 " ) , string , true , " passprompt_ok " ) ;
ClearPendingPackets ( ) ;
guiNetMenu - > SetStateString ( " status " , common - > GetLanguageDict ( ) - > GetString ( " #str_04322 " ) ) ;
if ( retpass ) {
// #790
cvarSystem - > SetCVarString ( " password " , " " ) ;
2011-12-06 18:20:15 +00:00
cvarSystem - > SetCVarString ( " password " , retpass ) ;
2011-11-22 21:28:15 +00:00
} else {
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , " disconnect " ) ;
}
} else if ( game_opcode = = ALLOW_NO ) {
session - > MessageBox ( MSG_OK , string , common - > GetLanguageDict ( ) - > GetString ( " #str_04323 " ) , true ) ;
ClearPendingPackets ( ) ;
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , " disconnect " ) ;
}
// ALLOW_NOTYET just keeps running as usual. The GUI has an abort button
} else if ( opcode = = SERVER_PRINT_BADCHALLENGE & & clientState > = CS_CONNECTING ) {
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , " reconnect " ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ProcessServersListMessage
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ProcessServersListMessage ( const netadr_t from , const idBitMsg & msg ) {
if ( ! Sys_CompareNetAdrBase ( idAsyncNetwork : : GetMasterAddress ( ) , from ) ) {
common - > DPrintf ( " received a server list from %s - not a valid master \n " , Sys_NetAdrToString ( from ) ) ;
return ;
}
while ( msg . GetRemaingData ( ) ) {
int a , b , c , d ;
a = msg . ReadByte ( ) ; b = msg . ReadByte ( ) ; c = msg . ReadByte ( ) ; d = msg . ReadByte ( ) ;
serverList . AddServer ( serverList . Num ( ) , va ( " %i.%i.%i.%i:%i " , a , b , c , d , msg . ReadShort ( ) ) ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ProcessAuthKeyMessage
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ProcessAuthKeyMessage ( const netadr_t from , const idBitMsg & msg ) {
authKeyMsg_t authMsg ;
char read_string [ MAX_STRING_CHARS ] ;
const char * retkey ;
authBadKeyStatus_t authBadStatus ;
int key_index ;
bool valid [ 2 ] ;
idStr auth_msg ;
if ( clientState ! = CS_CONNECTING & & ! session - > WaitingForGameAuth ( ) ) {
common - > Printf ( " clientState != CS_CONNECTING, not waiting for game auth, authKey ignored \n " ) ;
return ;
}
authMsg = ( authKeyMsg_t ) msg . ReadByte ( ) ;
if ( authMsg = = AUTHKEY_BADKEY ) {
valid [ 0 ] = valid [ 1 ] = true ;
key_index = 0 ;
authBadStatus = ( authBadKeyStatus_t ) msg . ReadByte ( ) ;
switch ( authBadStatus ) {
case AUTHKEY_BAD_INVALID :
valid [ 0 ] = ( msg . ReadByte ( ) = = 1 ) ;
valid [ 1 ] = ( msg . ReadByte ( ) = = 1 ) ;
idAsyncNetwork : : BuildInvalidKeyMsg ( auth_msg , valid ) ;
break ;
case AUTHKEY_BAD_BANNED :
key_index = msg . ReadByte ( ) ;
auth_msg = common - > GetLanguageDict ( ) - > GetString ( va ( " #str_0719%1d " , 6 + key_index ) ) ;
auth_msg + = " \n " ;
auth_msg + = common - > GetLanguageDict ( ) - > GetString ( " #str_04304 " ) ;
valid [ key_index ] = false ;
break ;
case AUTHKEY_BAD_INUSE :
key_index = msg . ReadByte ( ) ;
auth_msg = common - > GetLanguageDict ( ) - > GetString ( va ( " #str_0719%1d " , 8 + key_index ) ) ;
auth_msg + = " \n " ;
auth_msg + = common - > GetLanguageDict ( ) - > GetString ( " #str_04304 " ) ;
valid [ key_index ] = false ;
break ;
case AUTHKEY_BAD_MSG :
// a general message explaining why this key is denied
// no specific use for this atm. let's not clear the keys either
msg . ReadString ( read_string , MAX_STRING_CHARS ) ;
auth_msg = read_string ;
break ;
}
common - > DPrintf ( " auth deny: %s \n " , auth_msg . c_str ( ) ) ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
// keys to be cleared. applies to both net connect and game auth
session - > ClearCDKey ( valid ) ;
// get rid of the bad key - at least that's gonna annoy people who stole a fake key
if ( clientState = = CS_CONNECTING ) {
while ( 1 ) {
// here we use the auth status message
retkey = session - > MessageBox ( MSG_CDKEY , auth_msg , common - > GetLanguageDict ( ) - > GetString ( " #str_04325 " ) , true ) ;
if ( retkey ) {
if ( session - > CheckKey ( retkey , true , valid ) ) {
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , " reconnect " ) ;
} else {
// build a more precise message about the offline check failure
idAsyncNetwork : : BuildInvalidKeyMsg ( auth_msg , valid ) ;
session - > MessageBox ( MSG_OK , auth_msg . c_str ( ) , common - > GetLanguageDict ( ) - > GetString ( " #str_04327 " ) , true ) ;
continue ;
}
} else {
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , " disconnect " ) ;
}
break ;
}
} else {
// forward the auth status information to the session code
session - > CDKeysAuthReply ( false , auth_msg ) ;
}
} else {
msg . ReadString ( read_string , MAX_STRING_CHARS ) ;
cvarSystem - > SetCVarString ( " com_guid " , read_string ) ;
common - > Printf ( " guid set to %s \n " , read_string ) ;
session - > CDKeysAuthReply ( true , NULL ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ProcessVersionMessage
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ProcessVersionMessage ( const netadr_t from , const idBitMsg & msg ) {
char string [ MAX_STRING_CHARS ] ;
if ( updateState ! = UPDATE_SENT ) {
common - > Printf ( " ProcessVersionMessage: version reply, != UPDATE_SENT \n " ) ;
return ;
}
common - > Printf ( " A new version is available \n " ) ;
msg . ReadString ( string , MAX_STRING_CHARS ) ;
updateMSG = string ;
updateDirectDownload = ( msg . ReadByte ( ) ! = 0 ) ;
msg . ReadString ( string , MAX_STRING_CHARS ) ;
updateURL = string ;
updateMime = ( dlMime_t ) msg . ReadByte ( ) ;
msg . ReadString ( string , MAX_STRING_CHARS ) ;
updateFallback = string ;
updateState = UPDATE_READY ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ValidatePureServerChecksums
= = = = = = = = = = = = = = = = = =
*/
bool idAsyncClient : : ValidatePureServerChecksums ( const netadr_t from , const idBitMsg & msg ) {
int i , numChecksums , numMissingChecksums ;
int inChecksums [ MAX_PURE_PAKS ] ;
int missingChecksums [ MAX_PURE_PAKS ] ;
idBitMsg dlmsg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
// read checksums
// pak checksums, in a 0-terminated list
numChecksums = 0 ;
do {
2012-06-28 11:19:14 +00:00
i = msg . ReadInt ( ) ;
2011-11-22 21:28:15 +00:00
inChecksums [ numChecksums + + ] = i ;
// just to make sure a broken message doesn't crash us
if ( numChecksums > = MAX_PURE_PAKS ) {
common - > Warning ( " MAX_PURE_PAKS ( %d ) exceeded in idAsyncClient::ProcessPureMessage \n " , MAX_PURE_PAKS ) ;
return false ;
}
} while ( i ) ;
inChecksums [ numChecksums ] = 0 ;
2012-07-03 21:52:35 +00:00
fsPureReply_t reply = fileSystem - > SetPureServerChecksums ( inChecksums , missingChecksums ) ;
2011-11-22 21:28:15 +00:00
switch ( reply ) {
case PURE_RESTART :
// need to restart the filesystem with a different pure configuration
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , " disconnect " ) ;
// restart with the right FS configuration and get back to the server
2011-12-06 18:20:15 +00:00
clientState = CS_PURERESTART ;
2012-07-03 21:52:35 +00:00
fileSystem - > SetRestartChecksums ( inChecksums ) ;
2011-11-22 21:28:15 +00:00
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , " reloadEngine " ) ;
return false ;
case PURE_MISSING : {
idStr checksums ;
i = 0 ;
while ( missingChecksums [ i ] ) {
checksums + = va ( " 0x%x " , missingChecksums [ i + + ] ) ;
}
numMissingChecksums = i ;
if ( idAsyncNetwork : : clientDownload . GetInteger ( ) = = 0 ) {
// never any downloads
idStr message = va ( common - > GetLanguageDict ( ) - > GetString ( " #str_07210 " ) , Sys_NetAdrToString ( from ) ) ;
if ( numMissingChecksums > 0 ) {
message + = va ( common - > GetLanguageDict ( ) - > GetString ( " #str_06751 " ) , numMissingChecksums , checksums . c_str ( ) ) ;
}
2022-12-29 04:38:13 +00:00
common - > Printf ( " %s " , message . c_str ( ) ) ;
2011-11-22 21:28:15 +00:00
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , " disconnect " ) ;
session - > MessageBox ( MSG_OK , message , common - > GetLanguageDict ( ) - > GetString ( " #str_06735 " ) , true ) ;
} else {
if ( clientState > = CS_CONNECTED ) {
// we are already connected, reconnect to negociate the paks in connectionless mode
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , " reconnect " ) ;
return false ;
}
// ask the server to send back download info
2012-07-03 21:05:24 +00:00
common - > DPrintf ( " missing %d paks: %s \n " , numMissingChecksums , checksums . c_str ( ) ) ;
2011-11-22 21:28:15 +00:00
// store the requested downloads
2012-07-03 21:52:35 +00:00
GetDownloadRequest ( missingChecksums , numMissingChecksums ) ;
2011-11-22 21:28:15 +00:00
// build the download request message
// NOTE: in a specific function?
dlmsg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
dlmsg . WriteShort ( CONNECTIONLESS_MESSAGE_ID ) ;
dlmsg . WriteString ( " downloadRequest " ) ;
2012-06-28 11:15:40 +00:00
dlmsg . WriteInt ( serverChallenge ) ;
2011-11-22 21:28:15 +00:00
dlmsg . WriteShort ( clientId ) ;
// used to make sure the server replies to the same download request
2012-06-28 11:15:40 +00:00
dlmsg . WriteInt ( dlRequest ) ;
2011-11-22 21:28:15 +00:00
// special case the code pak - if we have a 0 checksum then we don't need to download it
// 0-terminated list of missing paks
i = 0 ;
while ( missingChecksums [ i ] ) {
2012-06-28 11:15:40 +00:00
dlmsg . WriteInt ( missingChecksums [ i + + ] ) ;
2011-11-22 21:28:15 +00:00
}
2012-06-28 11:15:40 +00:00
dlmsg . WriteInt ( 0 ) ;
2011-11-22 21:28:15 +00:00
clientPort . SendPacket ( from , dlmsg . GetData ( ) , dlmsg . GetSize ( ) ) ;
}
return false ;
}
default :
2012-01-15 12:39:23 +00:00
break ;
2011-11-22 21:28:15 +00:00
}
2012-01-15 12:39:23 +00:00
2011-11-22 21:28:15 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ProcessPureMessage
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ProcessPureMessage ( const netadr_t from , const idBitMsg & msg ) {
idBitMsg outMsg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
int i ;
int inChecksums [ MAX_PURE_PAKS ] ;
if ( clientState ! = CS_CONNECTING ) {
common - > Printf ( " clientState != CS_CONNECTING, pure msg ignored \n " ) ;
return ;
}
if ( ! ValidatePureServerChecksums ( from , msg ) ) {
return ;
}
2012-07-03 21:52:35 +00:00
fileSystem - > GetPureServerChecksums ( inChecksums ) ;
2011-11-22 21:28:15 +00:00
outMsg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
outMsg . WriteShort ( CONNECTIONLESS_MESSAGE_ID ) ;
outMsg . WriteString ( " pureClient " ) ;
2012-06-28 11:15:40 +00:00
outMsg . WriteInt ( serverChallenge ) ;
2011-11-22 21:28:15 +00:00
outMsg . WriteShort ( clientId ) ;
i = 0 ;
while ( inChecksums [ i ] ) {
2012-06-28 11:15:40 +00:00
outMsg . WriteInt ( inChecksums [ i + + ] ) ;
2011-11-22 21:28:15 +00:00
}
2012-06-28 11:15:40 +00:00
outMsg . WriteInt ( 0 ) ;
2012-07-03 21:05:24 +00:00
2011-11-22 21:28:15 +00:00
clientPort . SendPacket ( from , outMsg . GetData ( ) , outMsg . GetSize ( ) ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : ConnectionlessMessage
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ConnectionlessMessage ( const netadr_t from , const idBitMsg & msg ) {
char string [ MAX_STRING_CHARS * 2 ] ; // M. Quinn - Even Balance - PB packets can go beyond 1024
msg . ReadString ( string , sizeof ( string ) ) ;
// info response from a server, are accepted from any source
if ( idStr : : Icmp ( string , " infoResponse " ) = = 0 ) {
ProcessInfoResponseMessage ( from , msg ) ;
return ;
}
// from master server:
if ( Sys_CompareNetAdrBase ( from , idAsyncNetwork : : GetMasterAddress ( ) ) ) {
// server list
if ( idStr : : Icmp ( string , " servers " ) = = 0 ) {
ProcessServersListMessage ( from , msg ) ;
return ;
}
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
if ( idStr : : Icmp ( string , " authKey " ) = = 0 ) {
ProcessAuthKeyMessage ( from , msg ) ;
return ;
}
if ( idStr : : Icmp ( string , " newVersion " ) = = 0 ) {
ProcessVersionMessage ( from , msg ) ;
return ;
}
}
// ignore if not from the current/last server
if ( ! Sys_CompareNetAdrBase ( from , serverAddress ) & & ( lastRconTime + 10000 < realTime | | ! Sys_CompareNetAdrBase ( from , lastRconAddress ) ) ) {
common - > DPrintf ( " got message '%s' from bad source: %s \n " , string , Sys_NetAdrToString ( from ) ) ;
return ;
}
// challenge response from the server we are connecting to
if ( idStr : : Icmp ( string , " challengeResponse " ) = = 0 ) {
ProcessChallengeResponseMessage ( from , msg ) ;
return ;
}
// connect response from the server we are connecting to
if ( idStr : : Icmp ( string , " connectResponse " ) = = 0 ) {
ProcessConnectResponseMessage ( from , msg ) ;
return ;
}
// a disconnect message from the server, which will happen if the server
// dropped the connection but is still getting packets from this client
if ( idStr : : Icmp ( string , " disconnect " ) = = 0 ) {
ProcessDisconnectMessage ( from , msg ) ;
return ;
}
// print request from server
if ( idStr : : Icmp ( string , " print " ) = = 0 ) {
ProcessPrintMessage ( from , msg ) ;
return ;
}
// server pure list
if ( idStr : : Icmp ( string , " pureServer " ) = = 0 ) {
ProcessPureMessage ( from , msg ) ;
return ;
}
if ( idStr : : Icmp ( string , " downloadInfo " ) = = 0 ) {
ProcessDownloadInfoMessage ( from , msg ) ;
}
if ( idStr : : Icmp ( string , " authrequired " ) = = 0 ) {
// server telling us that he's expecting an auth mode connect, just in case we're trying to connect in LAN mode
if ( idAsyncNetwork : : LANServer . GetBool ( ) ) {
common - > Warning ( " server %s requests master authorization for this client. Turning off LAN mode \n " , Sys_NetAdrToString ( from ) ) ;
idAsyncNetwork : : LANServer . SetBool ( false ) ;
}
}
common - > DPrintf ( " ignored message from %s: %s \n " , Sys_NetAdrToString ( from ) , string ) ;
}
/*
= = = = = = = = = = = = = = = = =
idAsyncClient : : ProcessMessage
= = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : ProcessMessage ( const netadr_t from , idBitMsg & msg ) {
int id ;
id = msg . ReadShort ( ) ;
// check for a connectionless packet
if ( id = = CONNECTIONLESS_MESSAGE_ID ) {
ConnectionlessMessage ( from , msg ) ;
return ;
}
if ( clientState < CS_CONNECTED ) {
return ; // can't be a valid sequenced packet
}
if ( msg . GetRemaingData ( ) < 4 ) {
common - > DPrintf ( " %s: tiny packet \n " , Sys_NetAdrToString ( from ) ) ;
return ;
}
// is this a packet from the server
if ( ! Sys_CompareNetAdrBase ( from , channel . GetRemoteAddress ( ) ) | | id ! = serverId ) {
common - > DPrintf ( " %s: sequenced server packet without connection \n " , Sys_NetAdrToString ( from ) ) ;
return ;
}
if ( ! channel . Process ( from , clientTime , msg , serverMessageSequence ) ) {
return ; // out of order, duplicated, fragment, etc.
}
lastPacketTime = clientTime ;
ProcessReliableServerMessages ( ) ;
ProcessUnreliableServerMessage ( msg ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : SetupConnection
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : SetupConnection ( void ) {
idBitMsg msg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
if ( clientTime - lastConnectTime < SETUP_CONNECTION_RESEND_TIME ) {
return ;
}
if ( clientState = = CS_CHALLENGING ) {
common - > Printf ( " sending challenge to %s \n " , Sys_NetAdrToString ( serverAddress ) ) ;
msg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
msg . WriteShort ( CONNECTIONLESS_MESSAGE_ID ) ;
msg . WriteString ( " challenge " ) ;
2012-06-28 11:15:40 +00:00
msg . WriteInt ( clientId ) ;
2011-11-22 21:28:15 +00:00
clientPort . SendPacket ( serverAddress , msg . GetData ( ) , msg . GetSize ( ) ) ;
} else if ( clientState = = CS_CONNECTING ) {
common - > Printf ( " sending connect to %s with challenge 0x%x \n " , Sys_NetAdrToString ( serverAddress ) , serverChallenge ) ;
msg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
msg . WriteShort ( CONNECTIONLESS_MESSAGE_ID ) ;
msg . WriteString ( " connect " ) ;
2012-06-28 11:15:40 +00:00
msg . WriteInt ( ASYNC_PROTOCOL_VERSION ) ;
msg . WriteInt ( clientDataChecksum ) ;
msg . WriteInt ( serverChallenge ) ;
2011-11-22 21:28:15 +00:00
msg . WriteShort ( clientId ) ;
2012-06-28 11:15:40 +00:00
msg . WriteInt ( cvarSystem - > GetCVarInteger ( " net_clientMaxRate " ) ) ;
2011-11-22 21:28:15 +00:00
msg . WriteString ( cvarSystem - > GetCVarString ( " com_guid " ) ) ;
msg . WriteString ( cvarSystem - > GetCVarString ( " password " ) , - 1 , false ) ;
// do not make the protocol depend on PB
msg . WriteShort ( 0 ) ;
clientPort . SendPacket ( serverAddress , msg . GetData ( ) , msg . GetSize ( ) ) ;
2021-03-08 09:59:26 +00:00
# if ID_ENFORCE_KEY_CLIENT
2011-11-22 21:28:15 +00:00
if ( idAsyncNetwork : : LANServer . GetBool ( ) ) {
common - > Printf ( " net_LANServer is set, connecting in LAN mode \n " ) ;
} else {
// emit a cd key authorization request
// modified at protocol 1.37 for XP key addition
msg . BeginWriting ( ) ;
msg . WriteShort ( CONNECTIONLESS_MESSAGE_ID ) ;
msg . WriteString ( " clAuth " ) ;
2012-06-28 11:15:40 +00:00
msg . WriteInt ( ASYNC_PROTOCOL_VERSION ) ;
2011-11-22 21:28:15 +00:00
msg . WriteNetadr ( serverAddress ) ;
// if we don't have a com_guid, this will request a direct reply from auth with it
msg . WriteByte ( cvarSystem - > GetCVarString ( " com_guid " ) [ 0 ] ? 1 : 0 ) ;
// send the main key, and flag an extra byte to add XP key
msg . WriteString ( session - > GetCDKey ( false ) ) ;
const char * xpkey = session - > GetCDKey ( true ) ;
msg . WriteByte ( xpkey ? 1 : 0 ) ;
if ( xpkey ) {
msg . WriteString ( xpkey ) ;
}
clientPort . SendPacket ( idAsyncNetwork : : GetMasterAddress ( ) , msg . GetData ( ) , msg . GetSize ( ) ) ;
}
2012-11-13 22:47:35 +00:00
# else
if ( ! Sys_IsLANAddress ( serverAddress ) ) {
common - > Printf ( " Build Does not have CD Key Enforcement enabled. The Server ( %s ) is not within the lan addresses. Attemting to connect. \n " , Sys_NetAdrToString ( serverAddress ) ) ;
}
common - > Printf ( " Not Testing key. \n " ) ;
# endif
2011-11-22 21:28:15 +00:00
} else {
return ;
}
lastConnectTime = clientTime ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : SendReliableGameMessage
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : SendReliableGameMessage ( const idBitMsg & msg ) {
idBitMsg outMsg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
if ( clientState < CS_INGAME ) {
return ;
}
outMsg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
outMsg . WriteByte ( CLIENT_RELIABLE_MESSAGE_GAME ) ;
outMsg . WriteData ( msg . GetData ( ) , msg . GetSize ( ) ) ;
if ( ! channel . SendReliableMessage ( outMsg ) ) {
common - > Error ( " client->server reliable messages overflow \n " ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : Idle
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : Idle ( void ) {
// also need to read mouse for the connecting guis
usercmdGen - > GetDirectUsercmd ( ) ;
SendEmptyToServer ( ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : UpdateTime
= = = = = = = = = = = = = = = = = =
*/
int idAsyncClient : : UpdateTime ( int clamp ) {
int time , msec ;
time = Sys_Milliseconds ( ) ;
msec = idMath : : ClampInt ( 0 , clamp , time - realTime ) ;
realTime = time ;
clientTime + = msec ;
return msec ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : RunFrame
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : RunFrame ( void ) {
int msec , size ;
bool newPacket ;
idBitMsg msg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
netadr_t from ;
msec = UpdateTime ( 100 ) ;
if ( ! clientPort . GetPort ( ) ) {
return ;
}
// handle ongoing pk4 downloads and patch downloads
HandleDownloads ( ) ;
gameTimeResidual + = msec ;
// spin in place processing incoming packets until enough time lapsed to run a new game frame
do {
do {
// blocking read with game time residual timeout
newPacket = clientPort . GetPacketBlocking ( from , msgBuf , size , sizeof ( msgBuf ) , USERCMD_MSEC - ( gameTimeResidual + clientPredictTime ) - 1 ) ;
if ( newPacket ) {
msg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
msg . SetSize ( size ) ;
msg . BeginReading ( ) ;
ProcessMessage ( from , msg ) ;
}
msec = UpdateTime ( 100 ) ;
gameTimeResidual + = msec ;
} while ( newPacket ) ;
} while ( gameTimeResidual + clientPredictTime < USERCMD_MSEC ) ;
// update server list
serverList . RunFrame ( ) ;
if ( clientState = = CS_DISCONNECTED ) {
usercmdGen - > GetDirectUsercmd ( ) ;
gameTimeResidual = USERCMD_MSEC - 1 ;
clientPredictTime = 0 ;
return ;
}
if ( clientState = = CS_PURERESTART ) {
clientState = CS_DISCONNECTED ;
Reconnect ( ) ;
gameTimeResidual = USERCMD_MSEC - 1 ;
clientPredictTime = 0 ;
return ;
}
// if not connected setup a connection
if ( clientState < CS_CONNECTED ) {
// also need to read mouse for the connecting guis
usercmdGen - > GetDirectUsercmd ( ) ;
SetupConnection ( ) ;
gameTimeResidual = USERCMD_MSEC - 1 ;
clientPredictTime = 0 ;
return ;
}
if ( CheckTimeout ( ) ) {
return ;
}
// if not yet in the game send empty messages to keep data flowing through the channel
if ( clientState < CS_INGAME ) {
Idle ( ) ;
gameTimeResidual = 0 ;
return ;
}
// check for user info changes
if ( cvarSystem - > GetModifiedFlags ( ) & CVAR_USERINFO ) {
game - > ThrottleUserInfo ( ) ;
SendUserInfoToServer ( ) ;
game - > SetUserInfo ( clientNum , sessLocal . mapSpawnData . userInfo [ clientNum ] , true , false ) ;
cvarSystem - > ClearModifiedFlags ( CVAR_USERINFO ) ;
}
if ( gameTimeResidual + clientPredictTime > = USERCMD_MSEC ) {
lastFrameDelta = 0 ;
}
// generate user commands for the predicted time
while ( gameTimeResidual + clientPredictTime > = USERCMD_MSEC ) {
// send the user commands of this client to the server
SendUsercmdsToServer ( ) ;
// update time
gameFrame + + ;
gameTime + = USERCMD_MSEC ;
gameTimeResidual - = USERCMD_MSEC ;
// run from the snapshot up to the local game frame
while ( snapshotGameFrame < gameFrame ) {
lastFrameDelta + + ;
// duplicate usercmds for clients if no new ones are available
DuplicateUsercmds ( snapshotGameFrame , snapshotGameTime ) ;
// indicate the last prediction frame before a render
bool lastPredictFrame = ( snapshotGameFrame + 1 > = gameFrame & & gameTimeResidual + clientPredictTime < USERCMD_MSEC ) ;
// run client prediction
gameReturn_t ret = game - > ClientPrediction ( clientNum , userCmds [ snapshotGameFrame & ( MAX_USERCMD_BACKUP - 1 ) ] , lastPredictFrame ) ;
idAsyncNetwork : : ExecuteSessionCommand ( ret . sessionCommand ) ;
snapshotGameFrame + + ;
snapshotGameTime + = USERCMD_MSEC ;
}
}
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : PacifierUpdate
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : PacifierUpdate ( void ) {
if ( ! IsActive ( ) ) {
return ;
}
realTime = Sys_Milliseconds ( ) ;
SendEmptyToServer ( false , true ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : SendVersionCheck
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : SendVersionCheck ( bool fromMenu ) {
idBitMsg msg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
if ( updateState ! = UPDATE_NONE & & ! fromMenu ) {
common - > DPrintf ( " up-to-date check was already performed \n " ) ;
return ;
}
InitPort ( ) ;
msg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
msg . WriteShort ( CONNECTIONLESS_MESSAGE_ID ) ;
msg . WriteString ( " versionCheck " ) ;
2012-06-28 11:15:40 +00:00
msg . WriteInt ( ASYNC_PROTOCOL_VERSION ) ;
2011-11-22 21:28:15 +00:00
msg . WriteString ( cvarSystem - > GetCVarString ( " si_version " ) ) ;
msg . WriteString ( cvarSystem - > GetCVarString ( " com_guid " ) ) ;
clientPort . SendPacket ( idAsyncNetwork : : GetMasterAddress ( ) , msg . GetData ( ) , msg . GetSize ( ) ) ;
common - > DPrintf ( " sent a version check request \n " ) ;
updateState = UPDATE_SENT ;
updateSentTime = clientTime ;
showUpdateMessage = fromMenu ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : SendVersionDLUpdate
sending those packets is not strictly necessary . just a way to tell the update server
about what is going on . allows the update server to have a more precise view of the overall
network load for the updates
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : SendVersionDLUpdate ( int state ) {
idBitMsg msg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
msg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
msg . WriteShort ( CONNECTIONLESS_MESSAGE_ID ) ;
msg . WriteString ( " versionDL " ) ;
2012-06-28 11:15:40 +00:00
msg . WriteInt ( ASYNC_PROTOCOL_VERSION ) ;
2011-11-22 21:28:15 +00:00
msg . WriteShort ( state ) ;
clientPort . SendPacket ( idAsyncNetwork : : GetMasterAddress ( ) , msg . GetData ( ) , msg . GetSize ( ) ) ;
}
/*
= = = = = = = = = = = = = = = = = =
idAsyncClient : : HandleDownloads
= = = = = = = = = = = = = = = = = =
*/
void idAsyncClient : : HandleDownloads ( void ) {
if ( updateState = = UPDATE_SENT & & clientTime > updateSentTime + 2000 ) {
// timing out on no reply
updateState = UPDATE_DONE ;
if ( showUpdateMessage ) {
session - > MessageBox ( MSG_OK , common - > GetLanguageDict ( ) - > GetString ( " #str_04839 " ) , common - > GetLanguageDict ( ) - > GetString ( " #str_04837 " ) , true ) ;
showUpdateMessage = false ;
}
common - > DPrintf ( " No update available \n " ) ;
} else if ( backgroundDownload . completed ) {
// only enter these if the download slot is free
if ( updateState = = UPDATE_READY ) {
2011-12-06 18:20:15 +00:00
//
2011-11-22 21:28:15 +00:00
if ( session - > MessageBox ( MSG_YESNO , updateMSG , common - > GetLanguageDict ( ) - > GetString ( " #str_04330 " ) , true , " yes " ) [ 0 ] ) {
if ( ! updateDirectDownload ) {
sys - > OpenURL ( updateURL , true ) ;
updateState = UPDATE_DONE ;
} else {
// we're just creating the file at toplevel inside fs_savepath
updateURL . ExtractFileName ( updateFile ) ;
idFile_Permanent * f = static_cast < idFile_Permanent * > ( fileSystem - > OpenFileWrite ( updateFile ) ) ;
dltotal = 0 ;
dlnow = 0 ;
backgroundDownload . completed = false ;
backgroundDownload . opcode = DLTYPE_URL ;
backgroundDownload . f = f ;
backgroundDownload . url . status = DL_WAIT ;
backgroundDownload . url . dlnow = 0 ;
backgroundDownload . url . dltotal = 0 ;
backgroundDownload . url . url = updateURL ;
fileSystem - > BackgroundDownload ( & backgroundDownload ) ;
updateState = UPDATE_DLING ;
SendVersionDLUpdate ( 0 ) ;
session - > DownloadProgressBox ( & backgroundDownload , va ( " Downloading %s \n " , updateFile . c_str ( ) ) ) ;
updateState = UPDATE_DONE ;
2011-12-06 18:20:15 +00:00
if ( backgroundDownload . url . status = = DL_DONE ) {
2011-11-22 21:28:15 +00:00
SendVersionDLUpdate ( 1 ) ;
idStr fullPath = f - > GetFullPath ( ) ;
fileSystem - > CloseFile ( f ) ;
if ( session - > MessageBox ( MSG_YESNO , common - > GetLanguageDict ( ) - > GetString ( " #str_04331 " ) , common - > GetLanguageDict ( ) - > GetString ( " #str_04332 " ) , true , " yes " ) [ 0 ] ) {
2012-01-07 14:30:03 +00:00
if ( updateMime = = DL_FILE_EXEC ) {
2011-11-22 21:28:15 +00:00
sys - > StartProcess ( fullPath , true ) ;
} else {
sys - > OpenURL ( va ( " file://%s " , fullPath . c_str ( ) ) , true ) ;
}
} else {
session - > MessageBox ( MSG_OK , va ( common - > GetLanguageDict ( ) - > GetString ( " #str_04333 " ) , fullPath . c_str ( ) ) , common - > GetLanguageDict ( ) - > GetString ( " #str_04334 " ) , true ) ;
}
} else {
if ( backgroundDownload . url . dlerror [ 0 ] ) {
common - > Warning ( " update download failed. curl error: %s " , backgroundDownload . url . dlerror ) ;
}
SendVersionDLUpdate ( 2 ) ;
idStr name = f - > GetName ( ) ;
fileSystem - > CloseFile ( f ) ;
fileSystem - > RemoveFile ( name ) ;
session - > MessageBox ( MSG_OK , common - > GetLanguageDict ( ) - > GetString ( " #str_04335 " ) , common - > GetLanguageDict ( ) - > GetString ( " #str_04336 " ) , true ) ;
if ( updateFallback . Length ( ) ) {
sys - > OpenURL ( updateFallback . c_str ( ) , true ) ;
} else {
common - > Printf ( " no fallback URL \n " ) ;
}
}
}
} else {
updateState = UPDATE_DONE ;
}
} else if ( dlList . Num ( ) ) {
int numPaks = dlList . Num ( ) ;
int pakCount = 1 ;
int progress_start , progress_end ;
currentDlSize = 0 ;
do {
if ( dlList [ 0 ] . url [ 0 ] = = ' \0 ' ) {
// ignore empty files
dlList . RemoveIndex ( 0 ) ;
continue ;
}
common - > Printf ( " start download for %s \n " , dlList [ 0 ] . url . c_str ( ) ) ;
idFile_Permanent * f = static_cast < idFile_Permanent * > ( fileSystem - > MakeTemporaryFile ( ) ) ;
if ( ! f ) {
common - > Warning ( " could not create temporary file " ) ;
dlList . Clear ( ) ;
return ;
}
backgroundDownload . completed = false ;
backgroundDownload . opcode = DLTYPE_URL ;
backgroundDownload . f = f ;
backgroundDownload . url . status = DL_WAIT ;
backgroundDownload . url . dlnow = 0 ;
backgroundDownload . url . dltotal = dlList [ 0 ] . size ;
backgroundDownload . url . url = dlList [ 0 ] . url ;
fileSystem - > BackgroundDownload ( & backgroundDownload ) ;
idStr dltitle ;
// "Downloading %s"
sprintf ( dltitle , common - > GetLanguageDict ( ) - > GetString ( " #str_07213 " ) , dlList [ 0 ] . filename . c_str ( ) ) ;
if ( numPaks > 1 ) {
dltitle + = va ( " (%d/%d) " , pakCount , numPaks ) ;
}
if ( totalDlSize ) {
progress_start = ( int ) ( ( float ) currentDlSize * 100.0f / ( float ) totalDlSize ) ;
progress_end = ( int ) ( ( float ) ( currentDlSize + dlList [ 0 ] . size ) * 100.0f / ( float ) totalDlSize ) ;
} else {
progress_start = 0 ;
progress_end = 100 ;
}
session - > DownloadProgressBox ( & backgroundDownload , dltitle , progress_start , progress_end ) ;
2011-12-06 18:20:15 +00:00
if ( backgroundDownload . url . status = = DL_DONE ) {
2011-11-22 21:28:15 +00:00
idFile * saveas ;
const int CHUNK_SIZE = 1024 * 1024 ;
byte * buf ;
int remainlen ;
int readlen ;
int retlen ;
int checksum ;
common - > Printf ( " file downloaded \n " ) ;
idStr finalPath = cvarSystem - > GetCVarString ( " fs_savepath " ) ;
finalPath . AppendPath ( dlList [ 0 ] . filename ) ;
fileSystem - > CreateOSPath ( finalPath ) ;
// do the final copy ourselves so we do by small chunks in case the file is big
saveas = fileSystem - > OpenExplicitFileWrite ( finalPath ) ;
buf = ( byte * ) Mem_Alloc ( CHUNK_SIZE ) ;
f - > Seek ( 0 , FS_SEEK_END ) ;
remainlen = f - > Tell ( ) ;
f - > Seek ( 0 , FS_SEEK_SET ) ;
while ( remainlen ) {
readlen = Min ( remainlen , CHUNK_SIZE ) ;
retlen = f - > Read ( buf , readlen ) ;
if ( retlen ! = readlen ) {
common - > FatalError ( " short read %d of %d in idFileSystem::HandleDownload " , retlen , readlen ) ;
}
retlen = saveas - > Write ( buf , readlen ) ;
if ( retlen ! = readlen ) {
common - > FatalError ( " short write %d of %d in idFileSystem::HandleDownload " , retlen , readlen ) ;
}
remainlen - = readlen ;
}
fileSystem - > CloseFile ( f ) ;
fileSystem - > CloseFile ( saveas ) ;
common - > Printf ( " saved as %s \n " , finalPath . c_str ( ) ) ;
Mem_Free ( buf ) ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
// add that file to our paks list
checksum = fileSystem - > AddZipFile ( dlList [ 0 ] . filename ) ;
// verify the checksum to be what the server says
if ( ! checksum | | checksum ! = dlList [ 0 ] . checksum ) {
// "pak is corrupted ( checksum 0x%x, expected 0x%x )"
session - > MessageBox ( MSG_OK , va ( common - > GetLanguageDict ( ) - > GetString ( " #str_07214 " ) , checksum , dlList [ 0 ] . checksum ) , " Download failed " , true ) ;
fileSystem - > RemoveFile ( dlList [ 0 ] . filename ) ;
dlList . Clear ( ) ;
return ;
}
currentDlSize + = dlList [ 0 ] . size ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
} else {
common - > Warning ( " download failed: %s " , dlList [ 0 ] . url . c_str ( ) ) ;
if ( backgroundDownload . url . dlerror [ 0 ] ) {
common - > Warning ( " curl error: %s " , backgroundDownload . url . dlerror ) ;
}
// "The download failed or was cancelled"
// "Download failed"
session - > MessageBox ( MSG_OK , common - > GetLanguageDict ( ) - > GetString ( " #str_07215 " ) , common - > GetLanguageDict ( ) - > GetString ( " #str_07216 " ) , true ) ;
dlList . Clear ( ) ;
return ;
}
pakCount + + ;
2011-12-06 18:20:15 +00:00
dlList . RemoveIndex ( 0 ) ;
2011-11-22 21:28:15 +00:00
} while ( dlList . Num ( ) ) ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
// all downloads successful - do the dew
cmdSystem - > BufferCommandText ( CMD_EXEC_APPEND , " reconnect \n " ) ;
}
}
}
/*
= = = = = = = = = = = = = = =
idAsyncClient : : SendAuthCheck
= = = = = = = = = = = = = = =
*/
bool idAsyncClient : : SendAuthCheck ( const char * cdkey , const char * xpkey ) {
idBitMsg msg ;
byte msgBuf [ MAX_MESSAGE_SIZE ] ;
msg . Init ( msgBuf , sizeof ( msgBuf ) ) ;
msg . WriteShort ( CONNECTIONLESS_MESSAGE_ID ) ;
msg . WriteString ( " gameAuth " ) ;
2012-06-28 11:15:40 +00:00
msg . WriteInt ( ASYNC_PROTOCOL_VERSION ) ;
2011-11-22 21:28:15 +00:00
msg . WriteByte ( cdkey ? 1 : 0 ) ;
msg . WriteString ( cdkey ? cdkey : " " ) ;
msg . WriteByte ( xpkey ? 1 : 0 ) ;
msg . WriteString ( xpkey ? xpkey : " " ) ;
InitPort ( ) ;
clientPort . SendPacket ( idAsyncNetwork : : GetMasterAddress ( ) , msg . GetData ( ) , msg . GetSize ( ) ) ;
return true ;
}
/*
= = = = = = = = = = = = = = =
idAsyncClient : : CheckTimeout
= = = = = = = = = = = = = = =
*/
bool idAsyncClient : : CheckTimeout ( void ) {
if ( lastPacketTime > 0 & & ( lastPacketTime + idAsyncNetwork : : clientServerTimeout . GetInteger ( ) * 1000 < clientTime ) ) {
session - > StopBox ( ) ;
session - > MessageBox ( MSG_OK , common - > GetLanguageDict ( ) - > GetString ( " #str_04328 " ) , common - > GetLanguageDict ( ) - > GetString ( " #str_04329 " ) , true ) ;
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , " disconnect " ) ;
return true ;
}
return false ;
}
/*
= = = = = = = = = = = = = = =
idAsyncClient : : ProcessDownloadInfoMessage
= = = = = = = = = = = = = = =
*/
void idAsyncClient : : ProcessDownloadInfoMessage ( const netadr_t from , const idBitMsg & msg ) {
char buf [ MAX_STRING_CHARS ] ;
2012-06-28 11:19:14 +00:00
int srvDlRequest = msg . ReadInt ( ) ;
2011-11-22 21:28:15 +00:00
int infoType = msg . ReadByte ( ) ;
int pakDl ;
int pakIndex ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
pakDlEntry_t entry ;
bool gotAllFiles = true ;
idStr sizeStr ;
bool gotGame = false ;
if ( dlRequest = = - 1 | | srvDlRequest ! = dlRequest ) {
common - > Warning ( " bad download id from server, ignored " ) ;
return ;
}
// mark the dlRequest as dead now whatever how we process it
dlRequest = - 1 ;
if ( infoType = = SERVER_DL_REDIRECT ) {
msg . ReadString ( buf , MAX_STRING_CHARS ) ;
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , " disconnect " ) ;
// "You are missing required pak files to connect to this server.\nThe server gave a web page though:\n%s\nDo you want to go there now?"
// "Missing required files"
if ( session - > MessageBox ( MSG_YESNO , va ( common - > GetLanguageDict ( ) - > GetString ( " #str_07217 " ) , buf ) ,
common - > GetLanguageDict ( ) - > GetString ( " #str_07218 " ) , true , " yes " ) [ 0 ] ) {
sys - > OpenURL ( buf , true ) ;
}
} else if ( infoType = = SERVER_DL_LIST ) {
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , " disconnect " ) ;
if ( dlList . Num ( ) ) {
common - > Warning ( " tried to process a download list while already busy downloading things " ) ;
return ;
}
// read the URLs, check against what we requested, prompt for download
pakIndex = - 1 ;
totalDlSize = 0 ;
do {
pakIndex + + ;
pakDl = msg . ReadByte ( ) ;
if ( pakDl = = SERVER_PAK_YES ) {
if ( pakIndex = = 0 ) {
gotGame = true ;
}
msg . ReadString ( buf , MAX_STRING_CHARS ) ;
entry . filename = buf ;
msg . ReadString ( buf , MAX_STRING_CHARS ) ;
entry . url = buf ;
2012-06-28 11:19:14 +00:00
entry . size = msg . ReadInt ( ) ;
2011-11-22 21:28:15 +00:00
// checksums are not transmitted, we read them from the dl request we sent
entry . checksum = dlChecksums [ pakIndex ] ;
totalDlSize + = entry . size ;
dlList . Append ( entry ) ;
common - > Printf ( " download %s from %s ( 0x%x ) \n " , entry . filename . c_str ( ) , entry . url . c_str ( ) , entry . checksum ) ;
} else if ( pakDl = = SERVER_PAK_NO ) {
msg . ReadString ( buf , MAX_STRING_CHARS ) ;
entry . filename = buf ;
entry . url = " " ;
entry . size = 0 ;
entry . checksum = 0 ;
dlList . Append ( entry ) ;
// first pak is game pak, only fail it if we actually requested it
if ( pakIndex ! = 0 | | dlChecksums [ 0 ] ! = 0 ) {
common - > Printf ( " no download offered for %s ( 0x%x ) \n " , entry . filename . c_str ( ) , dlChecksums [ pakIndex ] ) ;
gotAllFiles = false ;
}
} else {
assert ( pakDl = = SERVER_PAK_END ) ;
2011-12-06 18:20:15 +00:00
}
2011-11-22 21:28:15 +00:00
} while ( pakDl ! = SERVER_PAK_END ) ;
if ( dlList . Num ( ) < dlCount ) {
common - > Printf ( " %d files were ignored by the server \n " , dlCount - dlList . Num ( ) ) ;
gotAllFiles = false ;
}
sizeStr . BestUnit ( " %.2f " , totalDlSize , MEASURE_SIZE ) ;
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , " disconnect " ) ;
if ( totalDlSize = = 0 ) {
// was no downloadable stuff for us
// "Can't connect to the pure server: no downloads offered"
// "Missing required files"
dlList . Clear ( ) ;
session - > MessageBox ( MSG_OK , common - > GetLanguageDict ( ) - > GetString ( " #str_07219 " ) , common - > GetLanguageDict ( ) - > GetString ( " #str_07218 " ) , true ) ;
return ;
}
bool asked = false ;
if ( gotGame ) {
asked = true ;
// "You need to download game code to connect to this server. Are you sure? You should only answer yes if you trust the server administrators."
// "Missing game binaries"
if ( ! session - > MessageBox ( MSG_YESNO , common - > GetLanguageDict ( ) - > GetString ( " #str_07220 " ) , common - > GetLanguageDict ( ) - > GetString ( " #str_07221 " ) , true , " yes " ) [ 0 ] ) {
dlList . Clear ( ) ;
return ;
}
}
if ( ! gotAllFiles ) {
asked = true ;
// "The server only offers to download some of the files required to connect ( %s ). Download anyway?"
// "Missing required files"
if ( ! session - > MessageBox ( MSG_YESNO , va ( common - > GetLanguageDict ( ) - > GetString ( " #str_07222 " ) , sizeStr . c_str ( ) ) ,
common - > GetLanguageDict ( ) - > GetString ( " #str_07218 " ) , true , " yes " ) [ 0 ] ) {
dlList . Clear ( ) ;
return ;
}
}
if ( ! asked & & idAsyncNetwork : : clientDownload . GetInteger ( ) = = 1 ) {
// "You need to download some files to connect to this server ( %s ), proceed?"
// "Missing required files"
if ( ! session - > MessageBox ( MSG_YESNO , va ( common - > GetLanguageDict ( ) - > GetString ( " #str_07224 " ) , sizeStr . c_str ( ) ) ,
common - > GetLanguageDict ( ) - > GetString ( " #str_07218 " ) , true , " yes " ) [ 0 ] ) {
dlList . Clear ( ) ;
return ;
}
}
} else {
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , " disconnect " ) ;
// "You are missing some files to connect to this server, and the server doesn't provide downloads."
// "Missing required files"
session - > MessageBox ( MSG_OK , common - > GetLanguageDict ( ) - > GetString ( " #str_07223 " ) , common - > GetLanguageDict ( ) - > GetString ( " #str_07218 " ) , true ) ;
}
}
/*
= = = = = = = = = = = = = = =
idAsyncClient : : GetDownloadRequest
= = = = = = = = = = = = = = =
*/
2012-07-03 21:52:35 +00:00
int idAsyncClient : : GetDownloadRequest ( const int checksums [ MAX_PURE_PAKS ] , int count ) {
2011-11-22 21:28:15 +00:00
assert ( ! checksums [ count ] ) ; // 0-terminated
2012-07-03 21:05:24 +00:00
if ( memcmp ( dlChecksums , checksums , sizeof ( int ) * count ) ) {
2011-11-22 21:28:15 +00:00
idRandom newreq ;
2012-07-03 21:05:24 +00:00
memcpy ( dlChecksums , checksums , sizeof ( int ) * MAX_PURE_PAKS ) ;
2011-11-22 21:28:15 +00:00
newreq . SetSeed ( Sys_Milliseconds ( ) ) ;
dlRequest = newreq . RandomInt ( ) ;
2012-07-03 21:05:24 +00:00
dlCount = count ;
2011-11-22 21:28:15 +00:00
return dlRequest ;
}
// this is the same dlRequest, we haven't heard from the server. keep the same id
return dlRequest ;
}