336 lines
9.8 KiB
C++
336 lines
9.8 KiB
C++
|
|
||
|
#include "precompiled.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#ifdef SD_SUPPORT_REPEATER
|
||
|
|
||
|
#include "rules/GameRules.h"
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
idGameLocal::RepeaterClientDisconnect
|
||
|
============
|
||
|
*/
|
||
|
void idGameLocal::RepeaterClientDisconnect( int clientNum ) {
|
||
|
if ( clientNum >= repeaterNetworkInfo.Num() ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ShutdownRepeatersNetworkState( clientNum );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
idGameLocal::RepeaterWriteInitialReliableMessages
|
||
|
============
|
||
|
*/
|
||
|
void idGameLocal::RepeaterWriteInitialReliableMessages( int clientNum ) {
|
||
|
WriteInitialReliableMessages( sdReliableMessageClientInfoRepeater( clientNum ) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
idGameLocal::RepeaterWriteSnapshot
|
||
|
============
|
||
|
*/
|
||
|
void idGameLocal::RepeaterWriteSnapshot( int clientNum, int sequence, idBitMsg &msg, idBitMsg &ucmdmsg, const repeaterUserOrigin_t& userOrigin, bool clientIsRepeater ) {
|
||
|
bool useAOR = net_useAOR.GetBool() && !clientIsRepeater;
|
||
|
|
||
|
snapShotClientIsRepeater = clientIsRepeater;
|
||
|
SetSnapShotClient( NULL );
|
||
|
SetSnapShotPlayer( NULL );
|
||
|
|
||
|
idPlayer* followPlayer = NULL;
|
||
|
if ( !clientIsRepeater ) {
|
||
|
if ( userOrigin.followClient >= 0 && userOrigin.followClient < MAX_CLIENTS ) {
|
||
|
followPlayer = GetClient( userOrigin.followClient );
|
||
|
}
|
||
|
}
|
||
|
if ( followPlayer != NULL ) {
|
||
|
SetSnapShotPlayer( followPlayer );
|
||
|
aorManager.SetClient( followPlayer );
|
||
|
msg.WriteByte( followPlayer->entityNumber + 1 );
|
||
|
} else {
|
||
|
aorManager.SetPosition( userOrigin.origin );
|
||
|
msg.WriteByte( 0 );
|
||
|
}
|
||
|
|
||
|
clientNetworkInfo_t& nwInfo = GetRepeaterNetworkInfo( clientNum );
|
||
|
|
||
|
// free too old snapshots
|
||
|
FreeSnapshotsOlderThanSequence( nwInfo, sequence - 64 );
|
||
|
|
||
|
snapshot_t* snapshot = AllocateSnapshot( sequence, nwInfo );
|
||
|
WriteSnapshotGameStates( snapshot, nwInfo, msg );
|
||
|
WriteSnapshotEntityStates( snapshot, nwInfo, -1, msg, useAOR );
|
||
|
WriteUnreliableEntityNetEvents( clientNum, false, msg );
|
||
|
WriteSnapshotUserCmds( snapshot, ucmdmsg, -1, useAOR );
|
||
|
|
||
|
snapShotClientIsRepeater = false;
|
||
|
SetSnapShotClient( NULL );
|
||
|
SetSnapShotPlayer( NULL );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
idGameLocal::RepeaterAllowClient
|
||
|
============
|
||
|
*/
|
||
|
allowReply_t idGameLocal::RepeaterAllowClient( int numViewers, int maxViewers, const clientNetworkAddress_t& address, const sdNetClientId& netClientId, const char *guid, const char *password, allowFailureReason_t& reason, bool isRepeater ) {
|
||
|
clientGUIDLookup_t lookup;
|
||
|
lookup.ip = ( *( int* )address.ip );
|
||
|
lookup.pbid = 0;
|
||
|
lookup.clientId = netClientId;
|
||
|
|
||
|
sdGUIDFile::banState_t banState = guidFile.CheckForBan( lookup );
|
||
|
switch ( banState ) {
|
||
|
case sdGUIDFile::BS_PERM_BAN:
|
||
|
reason = ALLOWFAIL_PERMBAN;
|
||
|
return ALLOW_NO;
|
||
|
case sdGUIDFile::BS_TEMP_BAN:
|
||
|
reason = ALLOWFAIL_TEMPBAN;
|
||
|
return ALLOW_NO;
|
||
|
case sdGUIDFile::BS_NOT_BANNED:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( serverInfo.GetInt( "si_pure" ) && ( rules == NULL || !rules->IsPureReady() ) ) {
|
||
|
reason = ALLOWFAIL_SERVERSPAWNING;
|
||
|
return ALLOW_NOTYET;
|
||
|
}
|
||
|
|
||
|
bool isPrivateClient = false;
|
||
|
const char* privatePass = g_privateViewerPassword.GetString();
|
||
|
if ( *privatePass != '\0' && idStr::Cmp( privatePass, password ) == 0 ) {
|
||
|
isPrivateClient = true;
|
||
|
} else if ( isRepeater ) {
|
||
|
const char* pass = g_repeaterPassword.GetString();
|
||
|
if ( *pass != '\0' ) {
|
||
|
if ( idStr::Cmp( pass, password ) != 0 ) {
|
||
|
reason = ALLOWFAIL_INVALIDPASSWORD;
|
||
|
Printf( "Rejecting client %s from IP '%i.%i.%i.%i': invalid password\n", guid, address.ip[ 0 ], address.ip[ 1 ], address.ip[ 2 ], address.ip[ 3 ] );
|
||
|
return ALLOW_BADPASS;
|
||
|
}
|
||
|
}
|
||
|
} else if ( ri_useViewerPass.GetBool() ) {
|
||
|
const char* pass = g_viewerPassword.GetString();
|
||
|
if ( *pass == '\0' ) {
|
||
|
// Gordon: FIXME: This is rubbish
|
||
|
gameLocal.Warning( "ri_useViewerPass is set but g_password is empty" );
|
||
|
cmdSystem->BufferCommandText( CMD_EXEC_NOW, "say ri_useViewerPass is set but g_viewerPassword is empty" );
|
||
|
// avoids silent misconfigured state
|
||
|
reason = ALLOWFAIL_SERVERMISCONFIGURED;
|
||
|
return ALLOW_NOTYET;
|
||
|
}
|
||
|
|
||
|
if ( idStr::Cmp( pass, password ) != 0 ) {
|
||
|
reason = ALLOWFAIL_INVALIDPASSWORD;
|
||
|
Printf( "Rejecting client %s from IP '%i.%i.%i.%i': invalid password\n", guid, address.ip[ 0 ], address.ip[ 1 ], address.ip[ 2 ], address.ip[ 3 ] );
|
||
|
return ALLOW_BADPASS;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int maxPrivatePlayers = ri_privateViewers.GetInteger();
|
||
|
if ( maxPrivatePlayers > maxViewers ) {
|
||
|
maxPrivatePlayers = maxViewers;
|
||
|
}
|
||
|
int maxRegularPlayers = maxViewers - maxPrivatePlayers;
|
||
|
int numAvailableSlots = maxRegularPlayers;
|
||
|
if ( isPrivateClient ) {
|
||
|
numAvailableSlots = maxViewers; // with private password, any slot is available
|
||
|
}
|
||
|
|
||
|
if ( numViewers >= numAvailableSlots ) {
|
||
|
if ( numViewers >= maxPrivatePlayers ) {
|
||
|
reason = ALLOWFAIL_SERVERFULL;
|
||
|
return ALLOW_NOTYET;
|
||
|
}
|
||
|
reason = ALLOWFAIL_INVALIDPASSWORD;
|
||
|
return ALLOW_BADPASS;
|
||
|
}
|
||
|
|
||
|
return ALLOW_YES;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
idGameLocal::RepeaterClientBegin
|
||
|
============
|
||
|
*/
|
||
|
void idGameLocal::RepeaterClientBegin( int clientNum ) {
|
||
|
if ( clientNum >= repeaterNetworkInfo.Num() ) {
|
||
|
int oldSize = repeaterNetworkInfo.Num();
|
||
|
repeaterNetworkInfo.SetNum( clientNum + 1 );
|
||
|
for ( int i = oldSize; i <= clientNum; i++ ) {
|
||
|
repeaterNetworkInfo[ i ] = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( repeaterNetworkInfo[ clientNum ] == NULL ) {
|
||
|
repeaterNetworkInfo[ clientNum ] = new clientNetworkInfo_t();
|
||
|
}
|
||
|
|
||
|
SetupGameStateBase( *repeaterNetworkInfo[ clientNum ] );
|
||
|
SetupEntityStateBase( *repeaterNetworkInfo[ clientNum ] );
|
||
|
|
||
|
// client needs to get this straight away
|
||
|
sdReliableServerMessage ruleMsg( GAME_RELIABLE_SMESSAGE_RULES_DATA );
|
||
|
ruleMsg.WriteLong( sdGameRules::EVENT_CREATE );
|
||
|
ruleMsg.WriteLong( rules->GetType()->typeNum );
|
||
|
ruleMsg.Send( sdReliableMessageClientInfoRepeater( clientNum ) );
|
||
|
rules->WriteInitialReliableMessages( sdReliableMessageClientInfoRepeater( clientNum ) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
idGameLocal::SetRepeaterState
|
||
|
============
|
||
|
*/
|
||
|
void idGameLocal::SetRepeaterState( bool isRepeater ) {
|
||
|
this->isRepeater = isRepeater;
|
||
|
|
||
|
if ( net_serverDownload.GetInteger() == 3 ) {
|
||
|
networkSystem->HTTPEnable( this->isServer || this->isRepeater );
|
||
|
}
|
||
|
|
||
|
UpdateRepeaterInfo();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===========
|
||
|
idGameLocal::UpdateRepeaterInfo
|
||
|
============
|
||
|
*/
|
||
|
void idGameLocal::UpdateRepeaterInfo( void ) {
|
||
|
if ( !isRepeater ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
idDict repeaterInfo;
|
||
|
|
||
|
BuildRepeaterInfo( repeaterInfo );
|
||
|
|
||
|
networkSystem->RepeaterSetInfo( repeaterInfo );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===========
|
||
|
idGameLocal::BuildRepeaterInfo
|
||
|
============
|
||
|
*/
|
||
|
void idGameLocal::BuildRepeaterInfo( idDict &repeaterInfo ) {
|
||
|
repeaterInfo = serverInfo;
|
||
|
repeaterInfo.SetBool( "si_tv", true );
|
||
|
repeaterInfo.SetBool( "si_usePass", ri_useViewerPass.GetBool() );
|
||
|
repeaterInfo.SetInt( "si_privateClients", ri_privateViewers.GetInteger() );
|
||
|
|
||
|
const char* ri_name = cvarSystem->GetCVarString( "ri_name" );
|
||
|
if ( *ri_name != '\0' ) {
|
||
|
if ( *serverInfo.GetString( "ri_origName" ) == '\0' ) {
|
||
|
repeaterInfo.Set( "ri_origName", serverInfo.GetString( "si_name" ) );
|
||
|
}
|
||
|
repeaterInfo.Set( "si_name", ri_name );
|
||
|
}
|
||
|
|
||
|
const char *si_serverURL = cvarSystem->GetCVarString( "si_serverURL" );
|
||
|
if ( *si_serverURL != '\0' ) {
|
||
|
if ( *serverInfo.GetString( "ri_origServerURL" ) == '\0' ) {
|
||
|
repeaterInfo.Set( "ri_origServerURL", serverInfo.GetString( "si_serverURL" ) );
|
||
|
}
|
||
|
repeaterInfo.Set( "si_serverURL", si_serverURL );
|
||
|
}
|
||
|
|
||
|
repeaterInfo.Copy( *cvarSystem->MoveCVarsToDict( CVAR_REPEATERINFO ) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===========
|
||
|
idGameLocal::GetNumRepeaterClients
|
||
|
============
|
||
|
*/
|
||
|
int idGameLocal::GetNumRepeaterClients( void ) const {
|
||
|
return repeaterNetworkInfo.Num();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===========
|
||
|
idGameLocal::IsRepeaterClientConnected
|
||
|
============
|
||
|
*/
|
||
|
bool idGameLocal::IsRepeaterClientConnected( int clientNum ) const {
|
||
|
return repeaterNetworkInfo[ clientNum ] != NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===========
|
||
|
idGameLocal::ShutdownRepeatersNetworkStates
|
||
|
============
|
||
|
*/
|
||
|
void idGameLocal::ShutdownRepeatersNetworkStates( void ) {
|
||
|
for ( int i = 0; i < repeaterNetworkInfo.Num(); i++ ) {
|
||
|
ShutdownRepeatersNetworkState( i );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===========
|
||
|
idGameLocal::ShutdownRepeatersNetworkState
|
||
|
============
|
||
|
*/
|
||
|
void idGameLocal::ShutdownRepeatersNetworkState( int clientNum ) {
|
||
|
if ( repeaterNetworkInfo[ clientNum ] != NULL ) {
|
||
|
repeaterNetworkInfo[ clientNum ]->Reset();
|
||
|
delete repeaterNetworkInfo[ clientNum ];
|
||
|
repeaterNetworkInfo[ clientNum ] = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idGameLocal::RepeaterApplySnapshot
|
||
|
================
|
||
|
*/
|
||
|
bool idGameLocal::RepeaterApplySnapshot( int clientNum, int sequence ) {
|
||
|
return ApplySnapshot( GetRepeaterNetworkInfo( clientNum ), sequence );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
idGameLocal::RepeaterProcessReliableMessage
|
||
|
================
|
||
|
*/
|
||
|
void idGameLocal::RepeaterProcessReliableMessage( int clientNum, const idBitMsg &msg ) {
|
||
|
gameReliableClientMessage_t id = static_cast< gameReliableClientMessage_t >( msg.ReadBits( idMath::BitsForInteger( GAME_RELIABLE_CMESSAGE_NUM_MESSAGES ) ) );
|
||
|
|
||
|
switch( id ) {
|
||
|
case GAME_RELIABLE_CMESSAGE_CHAT:
|
||
|
case GAME_RELIABLE_CMESSAGE_TEAM_CHAT: {
|
||
|
case GAME_RELIABLE_CMESSAGE_FIRETEAM_CHAT:
|
||
|
if ( g_noTVChat.GetBool() ) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
wchar_t text[ 128 ];
|
||
|
msg.ReadString( text, sizeof( text ) / sizeof( wchar_t ) );
|
||
|
|
||
|
const idDict& clientInfo = networkSystem->RepeaterGetClientInfo( clientNum );
|
||
|
idStr playerName = clientInfo.GetString( "ui_name" );
|
||
|
idStr cleanName = playerName;
|
||
|
cleanName.RemoveColors();
|
||
|
cleanName.StripLeadingWhiteSpace();
|
||
|
cleanName.StripTrailingWhiteSpace();
|
||
|
if ( cleanName.IsEmpty() ) {
|
||
|
playerName = "Player";
|
||
|
}
|
||
|
|
||
|
sdReliableServerMessage outMsg( GAME_RELIABLE_SMESSAGE_REPEATER_CHAT );
|
||
|
outMsg.WriteString( playerName.c_str(), 128, false );
|
||
|
outMsg.WriteLong( clientNum );
|
||
|
outMsg.WriteString( text, 128 );
|
||
|
outMsg.Send( sdReliableMessageClientInfoRepeaterLocal() );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif // SD_SUPPORT_REPEATER
|