mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Filter bot logins by level range
This commit is contained in:
@@ -491,7 +491,7 @@ AiPlayerbot.AutoGearQualityLimit = 3
|
|||||||
# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 1.5(ZA) = 138 | Phase 2(SC, TK) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164
|
# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 1.5(ZA) = 138 | Phase 2(SC, TK) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164
|
||||||
# Wotlk
|
# Wotlk
|
||||||
# Max iLVL Tier 7(10/25) = 200/213 | Tier 8(10/25) = 225/232 | Tier 9(10/25) = 232/245 | Tier 10(10/25/HC) = 251/264/290
|
# Max iLVL Tier 7(10/25) = 200/213 | Tier 8(10/25) = 225/232 | Tier 9(10/25) = 232/245 | Tier 10(10/25/HC) = 251/264/290
|
||||||
# Max iLVL Phase 1(Naxx) = 224 | Phase 2(Ulduar) = 245 | Phase 3(ToC) = 258 | Phase 4(ICC) = 290
|
# Max iLVL Phase 1(Naxx) = 224 | Phase 2(Ulduar) = 245 | Phase 3(ToC) = 258 | Phase 4(ICC) = 290
|
||||||
# Default: 0 (no limit)
|
# Default: 0 (no limit)
|
||||||
AiPlayerbot.AutoGearScoreLimit = 0
|
AiPlayerbot.AutoGearScoreLimit = 0
|
||||||
|
|
||||||
@@ -500,11 +500,11 @@ AiPlayerbot.AutoGearScoreLimit = 0
|
|||||||
# "health" (bots have infinite health)
|
# "health" (bots have infinite health)
|
||||||
# "mana" (bots have infinite mana)
|
# "mana" (bots have infinite mana)
|
||||||
# "power" (bots have infinite energy, rage, and runic power)
|
# "power" (bots have infinite energy, rage, and runic power)
|
||||||
# "taxi" (bots may use all flight paths, though they will not actually learn them)
|
# "taxi" (bots may use all flight paths, though they will not actually learn them)
|
||||||
# "raid" (bots use cheats implemented into raid strategies)
|
# "raid" (bots use cheats implemented into raid strategies)
|
||||||
# To use multiple cheats, separate them by commas below (e.g., to enable all, use "gold,health,mana,power,taxi")
|
# To use multiple cheats, separate them by commas below (e.g., to enable all, use "gold,health,mana,power,taxi")
|
||||||
# Default: taxi is enabled
|
# Default: taxi is enabled
|
||||||
AiPlayerbot.BotCheats = "taxi,raid"
|
AiPlayerbot.BotCheats = "taxi,raid"
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
@@ -550,10 +550,18 @@ AiPlayerbot.RandomBotRandomPassword = 0
|
|||||||
# Prefix for account names to create for randombots
|
# Prefix for account names to create for randombots
|
||||||
AiPlayerbot.RandomBotAccountPrefix = "rndbot"
|
AiPlayerbot.RandomBotAccountPrefix = "rndbot"
|
||||||
|
|
||||||
# Minimum and maximum levels for randombots
|
# Minimum and maximum initialization levels for randombots
|
||||||
AiPlayerbot.RandomBotMinLevel = 1
|
AiPlayerbot.RandomBotMinLevel = 1
|
||||||
AiPlayerbot.RandomBotMaxLevel = 80
|
AiPlayerbot.RandomBotMaxLevel = 80
|
||||||
|
|
||||||
|
# Minimum and maximum level range for randombots allowed to login
|
||||||
|
AiPlayerbot.RandomBotMinLoginLevel = 1
|
||||||
|
AiPlayerbot.RandomBotMaxLoginLevel = 80
|
||||||
|
|
||||||
|
# log-out randombots if they they level outside the allowed login range
|
||||||
|
# Default: 0 (disabled)
|
||||||
|
AiPlayerbot.RandomBotLogoutOutsideLoginRange = 0
|
||||||
|
|
||||||
# Sync max randombot level with max level of online players
|
# Sync max randombot level with max level of online players
|
||||||
# Default: 0 (disabled)
|
# Default: 0 (disabled)
|
||||||
AiPlayerbot.SyncLevelWithPlayers = 0
|
AiPlayerbot.SyncLevelWithPlayers = 0
|
||||||
@@ -654,7 +662,7 @@ AiPlayerbot.RandomGearQualityLimit = 3
|
|||||||
# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 1.5(ZA) = 138 | Phase 2(SC, TK) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164
|
# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 1.5(ZA) = 138 | Phase 2(SC, TK) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164
|
||||||
# Wotlk
|
# Wotlk
|
||||||
# Max iLVL Tier 7(10/25) = 200/213 | Tier 8(10/25) = 225/232 | Tier 9(10/25) = 232/245 | Tier 10(10/25/HC) = 251/264/290
|
# Max iLVL Tier 7(10/25) = 200/213 | Tier 8(10/25) = 225/232 | Tier 9(10/25) = 232/245 | Tier 10(10/25/HC) = 251/264/290
|
||||||
# Max iLVL Phase 1(Naxx) = 224 | Phase 2(Ulduar) = 245 | Phase 3(ToC) = 258 | Phase 4(ICC) = 290
|
# Max iLVL Phase 1(Naxx) = 224 | Phase 2(Ulduar) = 245 | Phase 3(ToC) = 258 | Phase 4(ICC) = 290
|
||||||
# Default: 0 (no limit)
|
# Default: 0 (no limit)
|
||||||
AiPlayerbot.RandomGearScoreLimit = 0
|
AiPlayerbot.RandomGearScoreLimit = 0
|
||||||
|
|
||||||
|
|||||||
@@ -83,6 +83,9 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
lootDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.LootDelay", 1000);
|
lootDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.LootDelay", 1000);
|
||||||
disabledWithoutRealPlayerLoginDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.DisabledWithoutRealPlayerLoginDelay", 30);
|
disabledWithoutRealPlayerLoginDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.DisabledWithoutRealPlayerLoginDelay", 30);
|
||||||
disabledWithoutRealPlayerLogoutDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.DisabledWithoutRealPlayerLogoutDelay", 300);
|
disabledWithoutRealPlayerLogoutDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.DisabledWithoutRealPlayerLogoutDelay", 300);
|
||||||
|
randomBotMinLoginLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotMinLoginLevel", 1);
|
||||||
|
randomBotMaxLoginLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotMaxLoginLevel", 80);
|
||||||
|
randomBotLogoutOutsideLoginRange = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotLogoutOutsideLoginRange", false);
|
||||||
|
|
||||||
farDistance = sConfigMgr->GetOption<float>("AiPlayerbot.FarDistance", 20.0f);
|
farDistance = sConfigMgr->GetOption<float>("AiPlayerbot.FarDistance", 20.0f);
|
||||||
sightDistance = sConfigMgr->GetOption<float>("AiPlayerbot.SightDistance", 75.0f);
|
sightDistance = sConfigMgr->GetOption<float>("AiPlayerbot.SightDistance", 75.0f);
|
||||||
@@ -198,7 +201,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
"575,576,578,595,599,600,601,602,604,608,619,632,650,658,668,409,469,509,"
|
"575,576,578,595,599,600,601,602,604,608,619,632,650,658,668,409,469,509,"
|
||||||
"531,532,534,544,548,550,564,565,580,249,533,603,615,616,624,631,649,724"),
|
"531,532,534,544,548,550,564,565,580,249,533,603,615,616,624,631,649,724"),
|
||||||
restrictedHealerDPSMaps);
|
restrictedHealerDPSMaps);
|
||||||
|
|
||||||
//////////////////////////// ICC
|
//////////////////////////// ICC
|
||||||
|
|
||||||
EnableICCBuffs = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableICCBuffs", true);
|
EnableICCBuffs = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableICCBuffs", true);
|
||||||
|
|||||||
@@ -229,6 +229,8 @@ public:
|
|||||||
std::string randomBotCombatStrategies, randomBotNonCombatStrategies;
|
std::string randomBotCombatStrategies, randomBotNonCombatStrategies;
|
||||||
bool applyInstanceStrategies;
|
bool applyInstanceStrategies;
|
||||||
uint32 randomBotMinLevel, randomBotMaxLevel;
|
uint32 randomBotMinLevel, randomBotMaxLevel;
|
||||||
|
uint32 randomBotMinLoginLevel, randomBotMaxLoginLevel;
|
||||||
|
bool randomBotLogoutOutsideLoginRange;
|
||||||
float randomChangeMultiplier;
|
float randomChangeMultiplier;
|
||||||
|
|
||||||
// std::string premadeLevelSpec[MAX_CLASSES][10][91]; //lvl 10 - 100
|
// std::string premadeLevelSpec[MAX_CLASSES][10][91]; //lvl 10 - 100
|
||||||
|
|||||||
@@ -87,7 +87,8 @@ public:
|
|||||||
PLAYERHOOK_ON_BEFORE_CRITERIA_PROGRESS,
|
PLAYERHOOK_ON_BEFORE_CRITERIA_PROGRESS,
|
||||||
PLAYERHOOK_ON_BEFORE_ACHI_COMPLETE,
|
PLAYERHOOK_ON_BEFORE_ACHI_COMPLETE,
|
||||||
PLAYERHOOK_CAN_PLAYER_USE_PRIVATE_CHAT,
|
PLAYERHOOK_CAN_PLAYER_USE_PRIVATE_CHAT,
|
||||||
PLAYERHOOK_ON_GIVE_EXP
|
PLAYERHOOK_ON_GIVE_EXP,
|
||||||
|
PLAYERHOOK_ON_LEVEL_CHANGED
|
||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
void OnPlayerLogin(Player* player) override
|
void OnPlayerLogin(Player* player) override
|
||||||
@@ -115,12 +116,39 @@ public:
|
|||||||
roundedTime = roundedTime.substr(0, roundedTime.find('.') + 2);
|
roundedTime = roundedTime.substr(0, roundedTime.find('.') + 2);
|
||||||
|
|
||||||
ChatHandler(player->GetSession()).SendSysMessage(
|
ChatHandler(player->GetSession()).SendSysMessage(
|
||||||
"|cff00ff00Playerbots:|r bot initialization at server startup takes about '"
|
"|cff00ff00Playerbots:|r bot initialization at server startup takes about '"
|
||||||
+ roundedTime + "' minutes.");
|
+ roundedTime + "' minutes.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnPlayerLevelChanged(Player* player, uint8 oldLevel) override
|
||||||
|
{
|
||||||
|
// Check if feature is enabled and required objects are valid
|
||||||
|
if (!sPlayerbotAIConfig || !sPlayerbotAIConfig->randomBotLogoutOutsideLoginRange || !sRandomPlayerbotMgr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Only apply to bots from rndBotTypeAccounts (type 1)
|
||||||
|
uint32 accountId = player->GetSession()->GetAccountId();
|
||||||
|
if (!sRandomPlayerbotMgr->IsAccountType(accountId, 1))
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint32 newLevel = player->GetLevel();
|
||||||
|
|
||||||
|
// Check if the new level is outside the allowed login range
|
||||||
|
if (newLevel < sPlayerbotAIConfig->randomBotMinLoginLevel ||
|
||||||
|
newLevel > sPlayerbotAIConfig->randomBotMaxLoginLevel)
|
||||||
|
{
|
||||||
|
LOG_INFO("playerbots", "Bot {} changed levels from {} to {}, outside login range ({}-{}). Marking for logout",
|
||||||
|
player->GetName(), oldLevel, newLevel,
|
||||||
|
sPlayerbotAIConfig->randomBotMinLoginLevel, sPlayerbotAIConfig->randomBotMaxLoginLevel);
|
||||||
|
|
||||||
|
// Mark the bot for removal in the next update cycle
|
||||||
|
sRandomPlayerbotMgr->MarkBotForLogout(player->GetGUID().GetCounter());
|
||||||
|
sRandomPlayerbotMgr->ForceRecount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OnPlayerAfterUpdate(Player* player, uint32 diff) override
|
void OnPlayerAfterUpdate(Player* player, uint32 diff) override
|
||||||
{
|
{
|
||||||
if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(player))
|
if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(player))
|
||||||
@@ -211,7 +239,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (!player->GetSession()->IsBot())
|
if (!player->GetSession()->IsBot())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!sRandomPlayerbotMgr->IsRandomBot(player))
|
if (!sRandomPlayerbotMgr->IsRandomBot(player))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -281,7 +309,7 @@ public:
|
|||||||
LOG_INFO("server.loading", "╚══════════════════════════════════════════════════════════╝");
|
LOG_INFO("server.loading", "╚══════════════════════════════════════════════════════════╝");
|
||||||
|
|
||||||
uint32 oldMSTime = getMSTime();
|
uint32 oldMSTime = getMSTime();
|
||||||
|
|
||||||
LOG_INFO("server.loading", " ");
|
LOG_INFO("server.loading", " ");
|
||||||
LOG_INFO("server.loading", "Load Playerbots Config...");
|
LOG_INFO("server.loading", "Load Playerbots Config...");
|
||||||
|
|
||||||
|
|||||||
@@ -332,13 +332,73 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/)
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
uint32 maxAllowedBotCount = GetEventValue(0, "bot_count");
|
uint32 maxAllowedBotCount = GetEventValue(0, "bot_count");
|
||||||
if (!maxAllowedBotCount || (maxAllowedBotCount < sPlayerbotAIConfig->minRandomBots ||
|
|
||||||
maxAllowedBotCount > sPlayerbotAIConfig->maxRandomBots))
|
// Check if level filtering is active and populate eligible bots
|
||||||
|
if (!levelFilterAdjusted && IsLevelFilterActive())
|
||||||
{
|
{
|
||||||
maxAllowedBotCount = urand(sPlayerbotAIConfig->minRandomBots, sPlayerbotAIConfig->maxRandomBots);
|
PopulateEligibleBots();
|
||||||
SetEventValue(0, "bot_count", maxAllowedBotCount,
|
|
||||||
urand(sPlayerbotAIConfig->randomBotCountChangeMinInterval,
|
// Count total eligible bots from RNDbot accounts
|
||||||
sPlayerbotAIConfig->randomBotCountChangeMaxInterval));
|
uint32 eligibleBotCount = 0;
|
||||||
|
|
||||||
|
for (uint32 accountId : rndBotTypeAccounts)
|
||||||
|
{
|
||||||
|
QueryResult result = CharacterDatabase.Query(
|
||||||
|
"SELECT COUNT(*) FROM characters WHERE account = {} AND level >= {} AND level <= {}",
|
||||||
|
accountId, sPlayerbotAIConfig->randomBotMinLoginLevel, sPlayerbotAIConfig->randomBotMaxLoginLevel
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
Field* fields = result->Fetch();
|
||||||
|
eligibleBotCount += fields[0].Get<uint32>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eligibleBotCount > 0)
|
||||||
|
{
|
||||||
|
// Cap eligible bots by maxRandomBots
|
||||||
|
uint32 effectiveMaxBots = std::min(eligibleBotCount, sPlayerbotAIConfig->maxRandomBots);
|
||||||
|
|
||||||
|
LOG_INFO("playerbots", "Level filter active: {} eligible bots found in range {}-{}. Effective maximum: {} bots",
|
||||||
|
eligibleBotCount, sPlayerbotAIConfig->randomBotMinLoginLevel,
|
||||||
|
sPlayerbotAIConfig->randomBotMaxLoginLevel, effectiveMaxBots);
|
||||||
|
|
||||||
|
if (effectiveMaxBots >= sPlayerbotAIConfig->minRandomBots)
|
||||||
|
{
|
||||||
|
maxAllowedBotCount = urand(sPlayerbotAIConfig->minRandomBots, effectiveMaxBots);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
maxAllowedBotCount = effectiveMaxBots;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetEventValue(0, "bot_count", maxAllowedBotCount,
|
||||||
|
urand(sPlayerbotAIConfig->randomBotCountChangeMinInterval,
|
||||||
|
sPlayerbotAIConfig->randomBotCountChangeMaxInterval));
|
||||||
|
|
||||||
|
currentBots.clear();
|
||||||
|
levelFilterAdjusted = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_ERROR("playerbots", "No eligible bots found with level filter {}-{}",
|
||||||
|
sPlayerbotAIConfig->randomBotMinLoginLevel, sPlayerbotAIConfig->randomBotMaxLoginLevel);
|
||||||
|
levelFilterAdjusted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!levelFilterAdjusted)
|
||||||
|
{
|
||||||
|
// Normal bot count logic (no level filtering)
|
||||||
|
if (!maxAllowedBotCount || (maxAllowedBotCount < sPlayerbotAIConfig->minRandomBots ||
|
||||||
|
maxAllowedBotCount > sPlayerbotAIConfig->maxRandomBots))
|
||||||
|
{
|
||||||
|
maxAllowedBotCount = urand(sPlayerbotAIConfig->minRandomBots, sPlayerbotAIConfig->maxRandomBots);
|
||||||
|
SetEventValue(0, "bot_count", maxAllowedBotCount,
|
||||||
|
urand(sPlayerbotAIConfig->randomBotCountChangeMinInterval,
|
||||||
|
sPlayerbotAIConfig->randomBotCountChangeMaxInterval));
|
||||||
|
}
|
||||||
|
levelFilterAdjusted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GetBots();
|
GetBots();
|
||||||
@@ -730,23 +790,41 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
|
|||||||
|
|
||||||
for (uint32 accountId : accountsToUse)
|
for (uint32 accountId : accountsToUse)
|
||||||
{
|
{
|
||||||
CharacterDatabasePreparedStatement* stmt =
|
// Lambda to process results regardless of query type
|
||||||
CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID);
|
auto processResults = [&](auto result)
|
||||||
stmt->SetData(0, accountId);
|
|
||||||
PreparedQueryResult result = CharacterDatabase.Query(stmt);
|
|
||||||
if (!result)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
Field* fields = result->Fetch();
|
if (!result)
|
||||||
CharacterInfo info;
|
return;
|
||||||
info.guid = fields[0].Get<uint32>();
|
|
||||||
info.rClass = fields[1].Get<uint8>();
|
do
|
||||||
info.rRace = fields[2].Get<uint8>();
|
{
|
||||||
info.accountId = accountId;
|
Field* fields = result->Fetch();
|
||||||
allCharacters.push_back(info);
|
CharacterInfo info;
|
||||||
} while (result->NextRow());
|
info.guid = fields[0].Get<uint32>();
|
||||||
|
info.rClass = fields[1].Get<uint8>();
|
||||||
|
info.rRace = fields[2].Get<uint8>();
|
||||||
|
info.accountId = accountId;
|
||||||
|
allCharacters.push_back(info);
|
||||||
|
} while (result->NextRow());
|
||||||
|
};
|
||||||
|
|
||||||
|
if (IsLevelFilterActive())
|
||||||
|
{
|
||||||
|
// Custom query with level filtering
|
||||||
|
auto result = CharacterDatabase.Query(
|
||||||
|
"SELECT guid, class, race FROM characters WHERE account = {} AND level >= {} AND level <= {}",
|
||||||
|
accountId, sPlayerbotAIConfig->randomBotMinLoginLevel, sPlayerbotAIConfig->randomBotMaxLoginLevel
|
||||||
|
);
|
||||||
|
processResults(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CharacterDatabasePreparedStatement* stmt =
|
||||||
|
CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID);
|
||||||
|
stmt->SetData(0, accountId);
|
||||||
|
auto result = CharacterDatabase.Query(stmt);
|
||||||
|
processResults(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shuffle for class balance
|
// Shuffle for class balance
|
||||||
@@ -2548,17 +2626,55 @@ void RandomPlayerbotMgr::GetBots()
|
|||||||
stmt->SetData(0, 0);
|
stmt->SetData(0, 0);
|
||||||
stmt->SetData(1, "add");
|
stmt->SetData(1, "add");
|
||||||
uint32 maxAllowedBotCount = GetEventValue(0, "bot_count");
|
uint32 maxAllowedBotCount = GetEventValue(0, "bot_count");
|
||||||
|
|
||||||
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
|
if (PreparedQueryResult result = PlayerbotsDatabase.Query(stmt))
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
Field* fields = result->Fetch();
|
Field* fields = result->Fetch();
|
||||||
uint32 bot = fields[0].Get<uint32>();
|
uint32 bot = fields[0].Get<uint32>();
|
||||||
|
|
||||||
if (GetEventValue(bot, "add"))
|
if (GetEventValue(bot, "add"))
|
||||||
|
{
|
||||||
|
// Single query to get both account and level
|
||||||
|
QueryResult charResult = CharacterDatabase.Query("SELECT account, level FROM characters WHERE guid = {}", bot);
|
||||||
|
if (!charResult)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Field* charFields = charResult->Fetch();
|
||||||
|
uint32 botAccountId = charFields[0].Get<uint32>();
|
||||||
|
uint32 botLevel = charFields[1].Get<uint32>();
|
||||||
|
|
||||||
|
// Skip if not an RNDbot account
|
||||||
|
bool isRndBotAccount = false;
|
||||||
|
for (uint32 accountId : rndBotTypeAccounts)
|
||||||
|
{
|
||||||
|
if (accountId == botAccountId)
|
||||||
|
{
|
||||||
|
isRndBotAccount = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isRndBotAccount)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If level filtering is active, check bot level
|
||||||
|
if (IsLevelFilterActive())
|
||||||
|
{
|
||||||
|
// Skip bots outside the allowed level range
|
||||||
|
if (botLevel < sPlayerbotAIConfig->randomBotMinLoginLevel ||
|
||||||
|
botLevel > sPlayerbotAIConfig->randomBotMaxLoginLevel)
|
||||||
|
{
|
||||||
|
continue; // Skip this bot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
currentBots.push_back(bot);
|
currentBots.push_back(bot);
|
||||||
|
|
||||||
if (currentBots.size() >= maxAllowedBotCount)
|
if (currentBots.size() >= maxAllowedBotCount)
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
} while (result->NextRow());
|
} while (result->NextRow());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2586,6 +2702,51 @@ std::vector<uint32> RandomPlayerbotMgr::GetBgBots(uint32 bracket)
|
|||||||
return std::move(BgBots);
|
return std::move(BgBots);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RandomPlayerbotMgr::PopulateEligibleBots()
|
||||||
|
{
|
||||||
|
if (!sPlayerbotAIConfig || !(sPlayerbotAIConfig->randomBotMinLoginLevel > 1 ||
|
||||||
|
sPlayerbotAIConfig->randomBotMaxLoginLevel < 80))
|
||||||
|
return;
|
||||||
|
|
||||||
|
LOG_INFO("playerbots", "Populating eligible bots for level filter ({}-{})...",
|
||||||
|
sPlayerbotAIConfig->randomBotMinLoginLevel, sPlayerbotAIConfig->randomBotMaxLoginLevel);
|
||||||
|
|
||||||
|
bool botsAdded = false;
|
||||||
|
|
||||||
|
// Use only RNDbot type accounts (type 1)
|
||||||
|
for (uint32 accountId : rndBotTypeAccounts)
|
||||||
|
{
|
||||||
|
QueryResult result = CharacterDatabase.Query(
|
||||||
|
"SELECT guid, level, online FROM characters WHERE account = {} AND level >= {} AND level <= {}",
|
||||||
|
accountId, sPlayerbotAIConfig->randomBotMinLoginLevel, sPlayerbotAIConfig->randomBotMaxLoginLevel
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Field* fields = result->Fetch();
|
||||||
|
uint32 botGuid = fields[0].Get<uint32>();
|
||||||
|
bool isOnline = fields[2].Get<bool>();
|
||||||
|
|
||||||
|
// Skip bots that are already online or already have "add" event
|
||||||
|
if (isOnline || GetEventValue(botGuid, "add"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint32 add_time = urand(sPlayerbotAIConfig->minRandomBotInWorldTime,
|
||||||
|
sPlayerbotAIConfig->maxRandomBotInWorldTime);
|
||||||
|
SetEventValue(botGuid, "add", 1, add_time);
|
||||||
|
botsAdded = true;
|
||||||
|
} while (result->NextRow());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (botsAdded)
|
||||||
|
{
|
||||||
|
currentBots.clear(); // Force reload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint32 RandomPlayerbotMgr::GetEventValue(uint32 bot, std::string const event)
|
uint32 RandomPlayerbotMgr::GetEventValue(uint32 bot, std::string const event)
|
||||||
{
|
{
|
||||||
// load all events at once on first event load
|
// load all events at once on first event load
|
||||||
@@ -2613,23 +2774,13 @@ uint32 RandomPlayerbotMgr::GetEventValue(uint32 bot, std::string const event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CachedEvent& e = eventCache[bot][event];
|
CachedEvent& e = eventCache[bot][event];
|
||||||
/*if (e.IsEmpty())
|
|
||||||
{
|
|
||||||
QueryResult results = PlayerbotsDatabase.Query("SELECT `value`, `time`, validIn, `data` FROM
|
|
||||||
playerbots_random_bots WHERE owner = 0 AND bot = {} AND event = {}", bot, event.c_str());
|
|
||||||
|
|
||||||
if (results)
|
bool shouldExpire = (time(0) - e.lastChangeTime) >= e.validIn &&
|
||||||
{
|
event != "specNo" &&
|
||||||
Field* fields = results->Fetch();
|
event != "specLink" &&
|
||||||
e.value = fields[0].Get<uint32>();
|
!(event == "bot_count" && IsLevelFilterActive()); // Don't expire bot_count when level filtering is active
|
||||||
e.lastChangeTime = fields[1].Get<uint32>();
|
|
||||||
e.validIn = fields[2].Get<uint32>();
|
|
||||||
e.data = fields[3].Get<std::string>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ((time(0) - e.lastChangeTime) >= e.validIn && event != "specNo" && event != "specLink")
|
if (shouldExpire)
|
||||||
e.value = 0;
|
e.value = 0;
|
||||||
|
|
||||||
return e.value;
|
return e.value;
|
||||||
|
|||||||
@@ -189,6 +189,14 @@ public:
|
|||||||
void AssignAccountTypes();
|
void AssignAccountTypes();
|
||||||
bool IsAccountType(uint32 accountId, uint8 accountType);
|
bool IsAccountType(uint32 accountId, uint8 accountType);
|
||||||
|
|
||||||
|
// Allowed login range management
|
||||||
|
void ForceRecount() { SetEventValue(0, "bot_count", 0, 0); }
|
||||||
|
void MarkBotForLogout(uint32 bot)
|
||||||
|
{
|
||||||
|
SetEventValue(bot, "add", 0, 0); // Clear the "add" event to trigger logout
|
||||||
|
SetEventValue(bot, "logout", 1, 1); // Also set logout for clarity
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnBotLoginInternal(Player* const bot) override;
|
void OnBotLoginInternal(Player* const bot) override;
|
||||||
|
|
||||||
@@ -233,6 +241,16 @@ private:
|
|||||||
std::vector<uint32> rndBotTypeAccounts; // Accounts marked as RNDbot (type 1)
|
std::vector<uint32> rndBotTypeAccounts; // Accounts marked as RNDbot (type 1)
|
||||||
std::vector<uint32> addClassTypeAccounts; // Accounts marked as AddClass (type 2)
|
std::vector<uint32> addClassTypeAccounts; // Accounts marked as AddClass (type 2)
|
||||||
|
|
||||||
|
// Login level filtering
|
||||||
|
bool levelFilterAdjusted = false;
|
||||||
|
void PopulateEligibleBots();
|
||||||
|
bool IsLevelFilterActive() const
|
||||||
|
{
|
||||||
|
return sPlayerbotAIConfig &&
|
||||||
|
(sPlayerbotAIConfig->randomBotMinLoginLevel > 1 ||
|
||||||
|
sPlayerbotAIConfig->randomBotMaxLoginLevel < 80);
|
||||||
|
}
|
||||||
|
|
||||||
//void ScaleBotActivity(); // Deprecated function
|
//void ScaleBotActivity(); // Deprecated function
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user