//----------------------------------------------------------------------------- // Purpose: // Input : playerIndex - // ping - // packetloss - //----------------------------------------------------------------------------- void UTIL_GetPlayerConnectionInfo( int playerIndex, int& ping, int &packetloss ) { edict_t *pEntity = pAdminOP.GetEntityList()+playerIndex; CBasePlayer *player = (CBasePlayer *)VFuncs::Instance(pEntity); INetChannelInfo *nci = engine->GetPlayerNetInfo(playerIndex); if ( nci && player && pAdminOP.pAOPPlayers[playerIndex-1].NotBot() ) { float latency = nci->GetAvgLatency( FLOW_OUTGOING ); // in seconds // that should be the correct latency, we assume that cmdrate is higher // then updaterate, what is the case for default settings const char * szCmdRate = engine->GetClientConVarValue( playerIndex, "cl_cmdrate" ); int nCmdRate = max( 1, Q_atoi( szCmdRate ) ); latency -= (0.5f/nCmdRate) + TICKS_TO_TIME( 1.0f ); // correct latency // in GoldSrc we had a different, not fixed tickrate. so we have to adjust // Source pings by half a tick to match the old GoldSrc pings. latency -= TICKS_TO_TIME( 0.5f ); ping = latency * 1000.0f; // as msecs ping = clamp( ping, 5, 1000 ); // set bounds, dont show pings under 5 msecs packetloss = 100.0f * nci->GetAvgLoss( FLOW_INCOMING ); // loss in percentage packetloss = clamp( packetloss, 0, 100 ); } else { ping = 0; packetloss = 0; } }
// Called during player movement to set up/restore after lag compensation void CLagCompensationManager::StartLagCompensation( CBasePlayer *player, CUserCmd *cmd ) { //DONT LAG COMP AGAIN THIS FRAME IF THERES ALREADY ONE IN PROGRESS //IF YOU'RE HITTING THIS THEN IT MEANS THERES A CODE BUG if ( m_pCurrentPlayer ) { Assert( m_pCurrentPlayer == NULL ); Warning( "Trying to start a new lag compensation session while one is already active!\n" ); return; } // sort out any changes to the AI indexing if ( m_bNeedsAIUpdate ) // to be called once per frame... must happen BEFORE lag compensation - {// if that happens, that is. if not its called at the end of the frame m_bNeedsAIUpdate = false; UpdateAIIndexes(); } // Assume no players or entities need to be restored m_RestorePlayer.ClearAll(); m_RestoreEntity.ClearAll(); m_bNeedToRestore = false; m_pCurrentPlayer = player; if ( !player->m_bLagCompensation // Player not wanting lag compensation || (gpGlobals->maxClients <= 1) // no lag compensation in single player || !sv_unlag.GetBool() // disabled by server admin || player->IsBot() // not for bots || player->IsObserver() // not for spectators ) return; // NOTE: Put this here so that it won't show up in single player mode. VPROF_BUDGET( "StartLagCompensation", VPROF_BUDGETGROUP_OTHER_NETWORKING ); Q_memset( m_RestoreData, 0, sizeof( m_RestoreData ) ); Q_memset( m_ChangeData, 0, sizeof( m_ChangeData ) ); Q_memset( m_EntityRestoreData, 0, sizeof( m_EntityRestoreData ) ); Q_memset( m_EntityChangeData, 0, sizeof( m_EntityChangeData ) ); // Get true latency // correct is the amout of time we have to correct game time float correct = 0.0f; INetChannelInfo *nci = engine->GetPlayerNetInfo( player->entindex() ); if ( nci ) { // add network latency correct+= nci->GetLatency( FLOW_OUTGOING ); } // calc number of view interpolation ticks - 1 int lerpTicks = TIME_TO_TICKS( player->m_fLerpTime ); // add view interpolation latency see C_BaseEntity::GetInterpolationAmount() correct += TICKS_TO_TIME( lerpTicks ); // check bouns [0,sv_maxunlag] correct = clamp( correct, 0.0f, sv_maxunlag.GetFloat() ); // correct tick send by player int targettick = cmd->tick_count - lerpTicks; // calc difference between tick send by player and our latency based tick float deltaTime = correct - TICKS_TO_TIME(gpGlobals->tickcount - targettick); if ( fabs( deltaTime ) > 0.2f ) { // difference between cmd time and latency is too big > 200ms, use time correction based on latency // DevMsg("StartLagCompensation: delta too big (%.3f)\n", deltaTime ); targettick = gpGlobals->tickcount - TIME_TO_TICKS( correct ); } // Iterate all active players const CBitVec<MAX_EDICTS> *pEntityTransmitBits = engine->GetEntityTransmitBitsForClient( player->entindex() - 1 ); for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBasePlayer *pPlayer = UTIL_PlayerByIndex( i ); if ( !pPlayer || player == pPlayer ) continue; // Custom checks for if things should lag compensate (based on things like what team the player is on). if ( !player->WantsLagCompensationOnEntity( pPlayer, cmd, pEntityTransmitBits ) ) continue; // Move other player back in time BacktrackPlayer( pPlayer, TICKS_TO_TIME( targettick ) ); } // also iterate all monsters CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs(); int nAIs = g_AI_Manager.NumAIs(); for ( int i = 0; i < nAIs; i++ ) { CAI_BaseNPC *pNPC = ppAIs[i]; // Custom checks for if things should lag compensate if ( !pNPC || !player->WantsLagCompensationOnEntity( pNPC, cmd, pEntityTransmitBits ) ) continue; // Move NPC back in time BacktrackEntity( pNPC, TICKS_TO_TIME( targettick ) ); } }
//--------------------------------------------------------------------------------- // Purpose: Do timed afk if needed //--------------------------------------------------------------------------------- void ManiPing::GameFrame(void) { if (war_mode) return; if (mani_high_ping_kick.GetInt() == 0) return; // High ping kicker enabled if (next_check > gpGlobals->curtime) { return; } next_check = gpGlobals->curtime + 1.5; bool all_pings_high = true; // Use 80% of limit as global ping spikes may not bring all players over the // spike ping limit although all players will have their pings increase int global_ping_limit = (int) (mani_high_ping_kick_ping_limit.GetFloat() * 0.8); for (int i = 0; i < max_players; i++) { ping_player_t *ptr = &(ping_player_list[i]); ptr->in_use = true; ptr->player.index = i + 1; if (!FindPlayerByIndex(&ptr->player)) { ptr->in_use = false; continue; } if (ptr->player.is_bot) { ptr->in_use = false; continue; } // Valid player INetChannelInfo *nci = engine->GetPlayerNetInfo(i + 1); float ping = nci->GetAvgLatency(0); const char * szCmdRate = engine->GetClientConVarValue( i + 1, "cl_cmdrate" ); int nCmdRate = (20 > Q_atoi( szCmdRate )) ? 20 : Q_atoi(szCmdRate); ping -= (0.5f/nCmdRate) + TICKS_TO_TIME( 1.0f ); // correct latency // in GoldSrc we had a different, not fixed tickrate. so we have to adjust // Source pings by half a tick to match the old GoldSrc pings. ping -= TICKS_TO_TIME( 0.5f ); ping = ping * 1000.0f; // as msecs ptr->current_ping = clamp( ping, 5, 1000 ); // set bounds, dont show pings under 5 msecs // Crude attempt to protect against all pings from being high and kicking everyone if (ptr->current_ping < global_ping_limit) { all_pings_high = false; } } for (int i = 0; i < max_players; i++) { if (!ping_list[i].check_ping || !ping_player_list[i].in_use) { continue; } if (all_pings_high) { ping_player_list[i].current_ping = mani_high_ping_kick_ping_limit.GetInt() / 2; } if (ping_list[i].count == 0) { // Init ping ping_list[i].average_ping = ping_player_list[i].current_ping; } else { ping_list[i].average_ping += ping_player_list[i].current_ping; } // Bump up average ping ping_list[i].count += 1; if (ping_list[i].count > mani_high_ping_kick_samples_required.GetInt()) { if ((ping_list[i].average_ping / ping_list[i].count) > mani_high_ping_kick_ping_limit.GetInt()) { player_t *ptr = &(ping_player_list[i].player); SayToAll (ORANGE_CHAT, false, "Player %s was autokicked for breaking the %ims ping limit on this server\n", ptr->name, mani_high_ping_kick_ping_limit.GetInt() ); char log_reason[256]; snprintf(log_reason, sizeof(log_reason), "[MANI_ADMIN_PLUGIN] Kicked player [%s] steam id [%s] for exceeding ping limit\n", ptr->name, ptr->steam_id); UTIL_KickPlayer(ptr, (char *) mani_high_ping_kick_message.GetString(), (char *) mani_high_ping_kick_message.GetString(), log_reason); ping_list[i].check_ping = false; } else { ping_list[i].count = 0; } } } }
//--------------------------------------------------------------------------------- // Purpose: Builds up a list of players that are 'kickable' //--------------------------------------------------------------------------------- void ManiReservedSlot::BuildPlayerKickList( player_t *player_ptr, int *players_on_server ) { player_t temp_player; active_player_t active_player; FreeList((void **) &active_player_list, &active_player_list_size); for (int i = 1; i <= max_players; i ++) { #if defined ( GAME_CSGO ) edict_t *pEntity = PEntityOfEntIndex(i); #else edict_t *pEntity = engine->PEntityOfEntIndex(i); #endif if( pEntity && !pEntity->IsFree()) { if ( player_ptr && ( pEntity == player_ptr->entity ) ) continue; IPlayerInfo *playerinfo = playerinfomanager->GetPlayerInfo( pEntity ); if (playerinfo && playerinfo->IsConnected()) { Q_strcpy(active_player.steam_id, playerinfo->GetNetworkIDString()); if (FStrEq("BOT", active_player.steam_id)) { continue; } INetChannelInfo *nci = engine->GetPlayerNetInfo(i); if (!nci) { continue; } active_player.entity = pEntity; active_player.ping = nci->GetAvgLatency(0); const char * szCmdRate = engine->GetClientConVarValue( i, "cl_cmdrate" ); int nCmdRate = (20 > Q_atoi( szCmdRate )) ? 20 : Q_atoi(szCmdRate); active_player.ping -= (0.5f/nCmdRate) + TICKS_TO_TIME( 1.0f ); // correct latency // in GoldSrc we had a different, not fixed tickrate. so we have to adjust // Source pings by half a tick to match the old GoldSrc pings. active_player.ping -= TICKS_TO_TIME( 0.5f ); active_player.ping = active_player.ping * 1000.0f; // as msecs active_player.ping = ((5 > active_player.ping) ? 5:active_player.ping); // set bounds, dont show pings under 5 msecs active_player.time_connected = nci->GetTimeConnected(); Q_strcpy(active_player.ip_address, nci->GetAddress()); if (gpManiGameType->IsSpectatorAllowed() && playerinfo->GetTeamIndex () == gpManiGameType->GetSpectatorIndex()) { active_player.is_spectator = true; } else { active_player.is_spectator = false; } active_player.user_id = playerinfo->GetUserID(); Q_strcpy(active_player.name, playerinfo->GetName()); if ( players_on_server ) *players_on_server = *players_on_server + 1; active_player.kills = playerinfo->GetFragCount(); active_player.deaths = playerinfo->GetDeathCount(); Q_strcpy(temp_player.steam_id, active_player.steam_id); Q_strcpy(temp_player.ip_address, active_player.ip_address); Q_strcpy(temp_player.name, active_player.name); temp_player.is_bot = false; if (IsPlayerInReserveList(&temp_player)) { continue; } active_player.index = i; if (mani_reserve_slots_include_admin.GetInt() == 1 && gpManiClient->HasAccess(active_player.index, ADMIN, ADMIN_BASIC_ADMIN)) { continue; } if (gpManiClient->HasAccess(active_player.index, IMMUNITY, IMMUNITY_RESERVE)) { continue; } AddToList((void **) &active_player_list, sizeof(active_player_t), &active_player_list_size); active_player_list[active_player_list_size - 1] = active_player; } } } }
void CHLTVDirector::StartNewShot() { // we can remove all events the int smallestTick = MAX(0, gpGlobals->tickcount - TIME_TO_TICKS(HLTV_MAX_DELAY) ); RemoveEventsFromHistory( smallestTick ); if ( m_iCameraMan > 0 ) { // we already have an active camera man, // wait until he releases the "record" lock FinishCameraManShot(); return; } if ( StartCameraManShot() ) { // now we have an active camera man return; } // ok, no camera man active, now check how much time // we have for the next shot, if the time diff to the next // important event we have to switch to is too short (<2sec) // just extent the current shot and don't start a new one // check the next 8 seconds for interrupts/important events m_nNextShotTick = m_nBroadcastTick + TIME_TO_TICKS( MAX_SHOT_LENGTH ); if ( m_nBroadcastTick <= 0 ) { // game hasn't started yet, we are still in the broadcast delay hole IGameEvent *msg = gameeventmanager->CreateEvent( "hltv_message", true ); if ( msg ) { msg->SetString("text", "Please wait for broadcast to start ..." ); // send spectators the HLTV director command as a game event m_pHLTVServer->BroadcastEvent( msg ); gameeventmanager->FreeEvent( msg ); } StartBestFixedCameraShot( true ); return; } int index = FindFirstEvent( m_nBroadcastTick ); while( index != m_EventHistory.InvalidIndex() ) { CGameEvent &dc = m_EventHistory[index]; if ( dc.m_Tick >= m_nNextShotTick ) break; // we have searched enough // a camera man is always interrupting auto director if ( Q_strcmp( dc.m_Event->GetName(), "hltv_cameraman") == 0 ) { if ( dc.m_Event->GetInt("index") > 0 ) { // stop the next cut when this cameraman starts recording m_nNextShotTick = dc.m_Tick; break; } } index = m_EventHistory.NextInorder( index ); } float flDuration = TICKS_TO_TIME(m_nNextShotTick - m_nBroadcastTick); if ( flDuration < MIN_SHOT_LENGTH ) return; // not enough time for a new shot // find the most intesting game event for next shot CGameEvent *dc = FindBestGameEvent(); if ( dc ) { // show the game event CreateShotFromEvent( dc ); } else { // no interesting events found, start random shot StartRandomShot(); } }