# UNDF: UNDF-2026-000001005 --- a/regamedll/game_shared/bot/bot_profile.cpp +++ b/regamedll/game_shared/bot/bot_profile.cpp @@ -590,13 +590,24 @@ } // Return random unused profile that matches the given difficulty level +// DEFECT: UTIL_IsNameTaken called per-profile O(P*C) where P=profiles, C=clients +// FIX: build taken-name set once O(C), then check O(1) per profile const BotProfile *BotProfileManager::GetRandomProfile(BotDifficultyType difficulty, BotProfileTeamType team) const { #ifdef RANDOM_LONG BotProfileList::const_iterator iter; + // Build set of taken names once, instead of scanning players per profile + std::set takenNames; + for (int i = 1; i <= gpGlobals->maxClients; ++i) + { + CBasePlayer *player = static_cast(UTIL_PlayerByIndex(i)); + if (player && player->IsBot()) + takenNames.insert(static_cast(player)->GetProfile()->GetName()); + else if (player && !FNullEnt(player->pev) && STRING(player->pev->netname)[0]) + takenNames.insert(STRING(player->pev->netname)); + } + // count up valid profiles int validCount = 0; for (iter = m_profileList.begin(); iter != m_profileList.end(); ++iter) @@ -604,7 +615,7 @@ const BotProfile *profile = (*iter); - if (profile->IsDifficulty(difficulty) && !UTIL_IsNameTaken(profile->GetName()) && profile->IsValidForTeam(team)) + if (profile->IsDifficulty(difficulty) && takenNames.find(profile->GetName()) == takenNames.end() && profile->IsValidForTeam(team)) ++validCount; } @@ -616,7 +627,7 @@ { const BotProfile *profile = (*iter); - if (profile->IsDifficulty(difficulty) && !UTIL_IsNameTaken(profile->GetName()) && profile->IsValidForTeam(team)) + if (profile->IsDifficulty(difficulty) && takenNames.find(profile->GetName()) == takenNames.end() && profile->IsValidForTeam(team)) { if (which-- == 0) return profile;