/* ================= SV_MasterGameCompleteStatus NERVE - SMF - Sends gameCompleteStatus messages to all master servers ================= */ void SV_MasterGameCompleteStatus() { static netadr_t adr[MAX_MASTER_SERVERS]; int i; if ( SV_GameIsSinglePlayer() ) { return; // no master game status for SP } // "dedicated 1" is for lan play, "dedicated 2" is for inet public play if ( !com_dedicated || com_dedicated->integer != 2 ) { return; // only dedicated servers send master game status } // send to group masters for ( i = 0 ; i < MAX_MASTER_SERVERS ; i++ ) { if ( !sv_master[i]->string[0] ) { continue; } // see if we haven't already resolved the name // resolving usually causes hitches on win95, so only // do it when needed if ( sv_master[i]->modified ) { sv_master[i]->modified = qfalse; Com_Printf( "Resolving %s\n", sv_master[i]->string ); if ( !NET_StringToAdr( sv_master[i]->string, &adr[i] ) ) { // if the address failed to resolve, clear it // so we don't take repeated dns hits Com_Printf( "Couldn't resolve address: %s\n", sv_master[i]->string ); Cvar_Set( sv_master[i]->name, "" ); sv_master[i]->modified = qfalse; continue; } if ( !strstr( ":", sv_master[i]->string ) ) { adr[i].port = BigShort( PORT_MASTER ); } Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", sv_master[i]->string, adr[i].ip[0], adr[i].ip[1], adr[i].ip[2], adr[i].ip[3], BigShort( adr[i].port ) ); } Com_Printf( "Sending gameCompleteStatus to %s\n", sv_master[i]->string ); // this command should be changed if the server info / status format // ever incompatably changes SVC_GameCompleteStatus( adr[i] ); } }
/* ================= SV_SendServerCommand Sends a reliable command string to be interpreted by the client game module: "cp", "print", "chat", etc A NULL client will broadcast to all clients ================= */ void QDECL SV_SendServerCommand( client_t *cl, const char *fmt, ... ) { va_list argptr; byte message[MAX_MSGLEN]; client_t *client; int j; va_start( argptr,fmt ); #if defined RTCW_SP vsprintf( (char *)message, fmt,argptr ); #else Q_vsnprintf( (char *)message, sizeof( message ), fmt, argptr ); #endif // RTCW_XX va_end( argptr ); #if !defined RTCW_SP // do not forward server command messages that would be too big to clients // ( q3infoboom / q3msgboom stuff ) if ( strlen( (char *)message ) > 1022 ) { return; } #endif // RTCW_XX if ( cl != NULL ) { SV_AddServerCommand( cl, (char *)message ); return; } // hack to echo broadcast prints to console if ( com_dedicated->integer && !strncmp( (char *)message, "print", 5 ) ) { Com_Printf( "broadcast: %s\n", SV_ExpandNewlines( (char *)message ) ); } // send the data to all relevent clients for ( j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++ ) { if ( client->state < CS_PRIMED ) { continue; } // Ridah, don't need to send messages to AI #if !defined RTCW_ET if ( client->gentity && client->gentity->r.svFlags & SVF_CASTAI ) { #else if ( client->gentity && client->gentity->r.svFlags & SVF_BOT ) { #endif // RTCW_XX continue; } // done. SV_AddServerCommand( client, (char *)message ); } } /* ============================================================================== MASTER SERVER FUNCTIONS ============================================================================== */ /* ================ SV_MasterHeartbeat Send a message to the masters every few minutes to let it know we are alive, and log information. We will also have a heartbeat sent when a server changes from empty to non-empty, and full to non-full, but not on every player enter or exit. ================ */ #define HEARTBEAT_MSEC 300 * 1000 #if !defined RTCW_ET #define HEARTBEAT_GAME "Wolfenstein-1" #else //#define HEARTBEAT_GAME "Wolfenstein-1" //#define HEARTBEAT_DEAD "WolfFlatline-1" // NERVE - SMF #define HEARTBEAT_GAME "EnemyTerritory-1" #endif // RTCW_XX #if defined RTCW_SP void SV_MasterHeartbeat( void ) { #else #if !defined RTCW_ET #define HEARTBEAT_DEAD "WolfFlatline-1" // NERVE - SMF #else #define HEARTBEAT_DEAD "ETFlatline-1" // NERVE - SMF #endif // RTCW_XX void SV_MasterHeartbeat( const char *hbname ) { #endif // RTCW_XX static netadr_t adr[MAX_MASTER_SERVERS]; int i; #if defined RTCW_MP // DHM - Nerve :: Update Server doesn't send heartbeat #ifdef UPDATE_SERVER return; #endif #endif // RTCW_XX #if defined RTCW_ET if ( SV_GameIsSinglePlayer() ) { return; // no heartbeats for SP } #endif // RTCW_XX // "dedicated 1" is for lan play, "dedicated 2" is for inet public play if ( !com_dedicated || com_dedicated->integer != 2 ) { return; // only dedicated servers send heartbeats } // if not time yet, don't send anything if ( svs.time < svs.nextHeartbeatTime ) { return; } svs.nextHeartbeatTime = svs.time + HEARTBEAT_MSEC; // send to group masters for ( i = 0 ; i < MAX_MASTER_SERVERS ; i++ ) { if ( !sv_master[i]->string[0] ) { continue; } // see if we haven't already resolved the name // resolving usually causes hitches on win95, so only // do it when needed if ( sv_master[i]->modified ) { sv_master[i]->modified = qfalse; Com_Printf( "Resolving %s\n", sv_master[i]->string ); if ( !NET_StringToAdr( sv_master[i]->string, &adr[i] ) ) { // if the address failed to resolve, clear it // so we don't take repeated dns hits Com_Printf( "Couldn't resolve address: %s\n", sv_master[i]->string ); Cvar_Set( sv_master[i]->name, "" ); sv_master[i]->modified = qfalse; continue; } if ( !strstr( ":", sv_master[i]->string ) ) { adr[i].port = rtcw::Endian::be( PORT_MASTER ); } Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", sv_master[i]->string, adr[i].ip[0], adr[i].ip[1], adr[i].ip[2], adr[i].ip[3], rtcw::Endian::be( adr[i].port ) ); } Com_Printf( "Sending heartbeat to %s\n", sv_master[i]->string ); // this command should be changed if the server info / status format // ever incompatably changes #if defined RTCW_SP NET_OutOfBandPrint( NS_SERVER, adr[i], "heartbeat %s\n", HEARTBEAT_GAME ); #else NET_OutOfBandPrint( NS_SERVER, adr[i], "heartbeat %s\n", hbname ); #endif // RTCW_XX } } #if !defined RTCW_SP /* ================= SV_MasterGameCompleteStatus NERVE - SMF - Sends gameCompleteStatus messages to all master servers ================= */ void SV_MasterGameCompleteStatus() { static netadr_t adr[MAX_MASTER_SERVERS]; int i; #if defined RTCW_ET if ( SV_GameIsSinglePlayer() ) { return; // no master game status for SP } #endif // RTCW_XX // "dedicated 1" is for lan play, "dedicated 2" is for inet public play if ( !com_dedicated || com_dedicated->integer != 2 ) { return; // only dedicated servers send master game status } // send to group masters for ( i = 0 ; i < MAX_MASTER_SERVERS ; i++ ) { if ( !sv_master[i]->string[0] ) { continue; } // see if we haven't already resolved the name // resolving usually causes hitches on win95, so only // do it when needed if ( sv_master[i]->modified ) { sv_master[i]->modified = qfalse; Com_Printf( "Resolving %s\n", sv_master[i]->string ); if ( !NET_StringToAdr( sv_master[i]->string, &adr[i] ) ) { // if the address failed to resolve, clear it // so we don't take repeated dns hits Com_Printf( "Couldn't resolve address: %s\n", sv_master[i]->string ); Cvar_Set( sv_master[i]->name, "" ); sv_master[i]->modified = qfalse; continue; } if ( !strstr( ":", sv_master[i]->string ) ) { adr[i].port = rtcw::Endian::be ( PORT_MASTER ); } Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", sv_master[i]->string, adr[i].ip[0], adr[i].ip[1], adr[i].ip[2], adr[i].ip[3], rtcw::Endian::be ( adr[i].port ) ); } Com_Printf( "Sending gameCompleteStatus to %s\n", sv_master[i]->string ); // this command should be changed if the server info / status format // ever incompatably changes SVC_GameCompleteStatus( adr[i] ); } } #endif // RTCW_XX /* ================= SV_MasterShutdown Informs all masters that this server is going down ================= */ void SV_MasterShutdown( void ) { // send a hearbeat right now svs.nextHeartbeatTime = -9999; #if defined RTCW_SP SV_MasterHeartbeat(); #else SV_MasterHeartbeat( HEARTBEAT_DEAD ); // NERVE - SMF - changed to flatline #endif // RTCW_XX // send it again to minimize chance of drops #if defined RTCW_SP svs.nextHeartbeatTime = -9999; SV_MasterHeartbeat(); #else // svs.nextHeartbeatTime = -9999; // SV_MasterHeartbeat( HEARTBEAT_DEAD ); #endif // RTCW_XX // when the master tries to poll the server, it won't respond, so // it will be removed from the list }