mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Fix: Properly track RNDbot and AddClass accounts, and login faction balance issue (#1434)
* AssignAccountTypes & AddRandomBots Fix: Properly track RNDbot and AddClass accounts, and login faction balance issue * code style edits * fix addclass init on first build of playerbots_account_type
This commit is contained in:
8
data/sql/playerbots/base/playerbots_account_type.sql
Normal file
8
data/sql/playerbots/base/playerbots_account_type.sql
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
DROP TABLE IF EXISTS `playerbots_account_type`;
|
||||||
|
CREATE TABLE `playerbots_account_type` (
|
||||||
|
`account_id` int unsigned NOT NULL,
|
||||||
|
`account_type` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '0 = unassigned, 1 = RNDbot, 2 = AddClass',
|
||||||
|
`assignment_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`account_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Playerbot account type assignments';
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
-- Create playerbots_account_type table for tracking accounts assignments
|
||||||
|
DROP TABLE IF EXISTS `playerbots_account_type`;
|
||||||
|
CREATE TABLE `playerbots_account_type` (
|
||||||
|
`account_id` int unsigned NOT NULL,
|
||||||
|
`account_type` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '0 = unassigned, 1 = RNDbot, 2 = AddClass',
|
||||||
|
`assignment_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`account_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Playerbot account type assignments';
|
||||||
|
|
||||||
@@ -118,7 +118,6 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
tellWhenAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.TellWhenAvoidAoe", false);
|
tellWhenAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.TellWhenAvoidAoe", false);
|
||||||
|
|
||||||
randomGearLoweringChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomGearLoweringChance", 0.0f);
|
randomGearLoweringChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomGearLoweringChance", 0.0f);
|
||||||
|
|
||||||
incrementalGearInit = sConfigMgr->GetOption<bool>("AiPlayerbot.IncrementalGearInit", true);
|
incrementalGearInit = sConfigMgr->GetOption<bool>("AiPlayerbot.IncrementalGearInit", true);
|
||||||
randomGearQualityLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomGearQualityLimit", 3);
|
randomGearQualityLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomGearQualityLimit", 3);
|
||||||
randomGearScoreLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomGearScoreLimit", 0);
|
randomGearScoreLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomGearScoreLimit", 0);
|
||||||
@@ -157,7 +156,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
LoadList<std::vector<uint32>>(
|
LoadList<std::vector<uint32>>(
|
||||||
sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotQuestIds", "7848,3802,5505,6502,7761"),
|
sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotQuestIds", "7848,3802,5505,6502,7761"),
|
||||||
randomBotQuestIds);
|
randomBotQuestIds);
|
||||||
|
|
||||||
LoadSet<std::set<uint32>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.DisallowedGameObjects", "176213,17155"),
|
LoadSet<std::set<uint32>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.DisallowedGameObjects", "176213,17155"),
|
||||||
disallowedGameObjects);
|
disallowedGameObjects);
|
||||||
botAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.BotAutologin", false);
|
botAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.BotAutologin", false);
|
||||||
@@ -190,7 +189,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
maxRandomBotsPriceChangeInterval =
|
maxRandomBotsPriceChangeInterval =
|
||||||
sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotsPriceChangeInterval", 48 * HOUR);
|
sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotsPriceChangeInterval", 48 * HOUR);
|
||||||
randomBotJoinLfg = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotJoinLfg", true);
|
randomBotJoinLfg = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotJoinLfg", true);
|
||||||
|
|
||||||
//////////////////////////// ICC
|
//////////////////////////// ICC
|
||||||
|
|
||||||
EnableICCBuffs = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableICCBuffs", true);
|
EnableICCBuffs = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableICCBuffs", true);
|
||||||
@@ -346,7 +345,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
{
|
{
|
||||||
std::string setting = "AiPlayerbot.ZoneBracket." + std::to_string(zoneId);
|
std::string setting = "AiPlayerbot.ZoneBracket." + std::to_string(zoneId);
|
||||||
std::string value = sConfigMgr->GetOption<std::string>(setting, "");
|
std::string value = sConfigMgr->GetOption<std::string>(setting, "");
|
||||||
|
|
||||||
if (!value.empty())
|
if (!value.empty())
|
||||||
{
|
{
|
||||||
size_t commaPos = value.find(',');
|
size_t commaPos = value.find(',');
|
||||||
@@ -618,6 +617,9 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Assign account types after accounts are created
|
||||||
|
sRandomPlayerbotMgr->AssignAccountTypes();
|
||||||
|
|
||||||
if (sPlayerbotAIConfig->enabled)
|
if (sPlayerbotAIConfig->enabled)
|
||||||
{
|
{
|
||||||
sRandomPlayerbotMgr->Init();
|
sRandomPlayerbotMgr->Init();
|
||||||
|
|||||||
@@ -584,8 +584,8 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bot->SaveToDB(false, false);
|
bot->SaveToDB(false, false);
|
||||||
bool addClassBot = sRandomPlayerbotMgr->IsAddclassBot(bot->GetGUID().GetCounter());
|
bool addClassBot = sRandomPlayerbotMgr->IsAccountType(accountId, 2);
|
||||||
if (addClassBot && master && isRandomAccount && abs((int)master->GetLevel() - (int)bot->GetLevel()) > 3)
|
if (addClassBot && master && abs((int)master->GetLevel() - (int)bot->GetLevel()) > 3)
|
||||||
{
|
{
|
||||||
// PlayerbotFactory factory(bot, master->GetLevel());
|
// PlayerbotFactory factory(bot, master->GetLevel());
|
||||||
// factory.Randomize(false);
|
// factory.Randomize(false);
|
||||||
|
|||||||
@@ -393,37 +393,118 @@ std::string const RandomPlayerbotFactory::CreateRandomBotName(NameRaceAndGender
|
|||||||
return std::move(botName);
|
return std::move(botName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculates the total number of required accounts, either using the specified randomBotAccountCount
|
||||||
|
// or determining it dynamically based on MaxRandomBots, EnablePeriodicOnlineOffline and its ratio,
|
||||||
|
// and AddClassAccountPoolSize. The system also factors in the types of existing account, as assigned by
|
||||||
|
// AssignAccountTypes()
|
||||||
uint32 RandomPlayerbotFactory::CalculateTotalAccountCount()
|
uint32 RandomPlayerbotFactory::CalculateTotalAccountCount()
|
||||||
{
|
{
|
||||||
// Calculates the total number of required accounts, either using the specified randomBotAccountCount
|
// Reset account types if features are disabled
|
||||||
// or determining it dynamically based on the WOTLK condition, max random bots, rotation pool size,
|
// Reset is done here to precede needed accounts calculations
|
||||||
// and additional class account pool size.
|
if (sPlayerbotAIConfig->maxRandomBots == 0 || sPlayerbotAIConfig->addClassAccountPoolSize == 0)
|
||||||
|
{
|
||||||
|
if (sPlayerbotAIConfig->maxRandomBots == 0)
|
||||||
|
{
|
||||||
|
PlayerbotsDatabase.Execute("UPDATE playerbots_account_type SET account_type = 0 WHERE account_type = 1");
|
||||||
|
LOG_INFO("playerbots", "MaxRandomBots set to 0, any RNDbot accounts (type 1) will be unassigned (type 0)");
|
||||||
|
}
|
||||||
|
if (sPlayerbotAIConfig->addClassAccountPoolSize == 0)
|
||||||
|
{
|
||||||
|
PlayerbotsDatabase.Execute("UPDATE playerbots_account_type SET account_type = 0 WHERE account_type = 2");
|
||||||
|
LOG_INFO("playerbots", "AddClassAccountPoolSize set to 0, any AddClass accounts (type 2) will be unassigned (type 0)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for DB to reflect the change, up to 1 second max. This is needed to make sure other logs don't show wrong info
|
||||||
|
for (int waited = 0; waited < 1000; waited += 50)
|
||||||
|
{
|
||||||
|
QueryResult res = PlayerbotsDatabase.Query("SELECT COUNT(*) FROM playerbots_account_type WHERE account_type IN ({}, {})",
|
||||||
|
sPlayerbotAIConfig->maxRandomBots == 0 ? 1 : -1,
|
||||||
|
sPlayerbotAIConfig->addClassAccountPoolSize == 0 ? 2 : -1);
|
||||||
|
|
||||||
|
if (!res || res->Fetch()[0].Get<uint64>() == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Extra 50ms fixed delay for safety.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Checks if randomBotAccountCount is set, otherwise calculate it dynamically.
|
// Checks if randomBotAccountCount is set, otherwise calculate it dynamically.
|
||||||
if (sPlayerbotAIConfig->randomBotAccountCount > 0)
|
if (sPlayerbotAIConfig->randomBotAccountCount > 0)
|
||||||
return sPlayerbotAIConfig->randomBotAccountCount;
|
return sPlayerbotAIConfig->randomBotAccountCount;
|
||||||
|
|
||||||
// Avoid creating accounts if both maxRandom & ClassBots are set to zero.
|
// Check existing account types
|
||||||
if (sPlayerbotAIConfig->maxRandomBots == 0 &&
|
uint32 existingRndBotAccounts = 0;
|
||||||
sPlayerbotAIConfig->addClassAccountPoolSize == 0)
|
uint32 existingAddClassAccounts = 0;
|
||||||
return 0;
|
uint32 existingUnassignedAccounts = 0;
|
||||||
|
|
||||||
//bool isWOTLK = sWorld->getIntConfig(CONFIG_EXPANSION) == EXPANSION_WRATH_OF_THE_LICH_KING; //not used, line marked for removal.
|
QueryResult typeCheck = PlayerbotsDatabase.Query("SELECT account_type, COUNT(*) FROM playerbots_account_type GROUP BY account_type");
|
||||||
|
if (typeCheck)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Field* fields = typeCheck->Fetch();
|
||||||
|
uint8 accountType = fields[0].Get<uint8>();
|
||||||
|
uint32 count = fields[1].Get<uint32>();
|
||||||
|
|
||||||
// Determine divisor based on WOTLK condition
|
if (accountType == 0) existingUnassignedAccounts = count;
|
||||||
|
else if (accountType == 1) existingRndBotAccounts = count;
|
||||||
|
else if (accountType == 2) existingAddClassAccounts = count;
|
||||||
|
} while (typeCheck->NextRow());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine divisor based on Death Knight login eligibility and requested A&H faction ratio
|
||||||
int divisor = CalculateAvailableCharsPerAccount();
|
int divisor = CalculateAvailableCharsPerAccount();
|
||||||
|
|
||||||
// Calculate max bots
|
// Calculate max bots
|
||||||
int maxBots = sPlayerbotAIConfig->maxRandomBots;
|
int maxBots = sPlayerbotAIConfig->maxRandomBots;
|
||||||
// Take perodic online - offline into account
|
// Take periodic online - offline into account
|
||||||
if (sPlayerbotAIConfig->enablePeriodicOnlineOffline)
|
if (sPlayerbotAIConfig->enablePeriodicOnlineOffline)
|
||||||
{
|
{
|
||||||
maxBots *= sPlayerbotAIConfig->periodicOnlineOfflineRatio;
|
maxBots *= sPlayerbotAIConfig->periodicOnlineOfflineRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate base accounts, add class account pool size, and add 1 as a fixed offset
|
// Calculate number of accounts needed for RNDbots
|
||||||
uint32 baseAccounts = maxBots / divisor;
|
// Result is rounded up for maxBots not cleanly divisible by the divisor
|
||||||
return baseAccounts + sPlayerbotAIConfig->addClassAccountPoolSize + 1;
|
uint32 neededRndBotAccounts = (maxBots + divisor - 1) / divisor;
|
||||||
|
uint32 neededAddClassAccounts = sPlayerbotAIConfig->addClassAccountPoolSize;
|
||||||
|
|
||||||
|
// Start with existing total
|
||||||
|
uint32 existingTotal = existingRndBotAccounts + existingAddClassAccounts + existingUnassignedAccounts;
|
||||||
|
|
||||||
|
// Calculate shortfalls after using unassigned accounts
|
||||||
|
uint32 availableUnassigned = existingUnassignedAccounts;
|
||||||
|
uint32 additionalAccountsNeeded = 0;
|
||||||
|
|
||||||
|
// Check RNDbot needs
|
||||||
|
if (neededRndBotAccounts > existingRndBotAccounts)
|
||||||
|
{
|
||||||
|
uint32 rndBotShortfall = neededRndBotAccounts - existingRndBotAccounts;
|
||||||
|
if (rndBotShortfall <= availableUnassigned)
|
||||||
|
availableUnassigned -= rndBotShortfall;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
additionalAccountsNeeded += (rndBotShortfall - availableUnassigned);
|
||||||
|
availableUnassigned = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check AddClass needs
|
||||||
|
if (neededAddClassAccounts > existingAddClassAccounts)
|
||||||
|
{
|
||||||
|
uint32 addClassShortfall = neededAddClassAccounts - existingAddClassAccounts;
|
||||||
|
if (addClassShortfall <= availableUnassigned)
|
||||||
|
availableUnassigned -= addClassShortfall;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
additionalAccountsNeeded += (addClassShortfall - availableUnassigned);
|
||||||
|
availableUnassigned = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return existing total plus any additional accounts needed
|
||||||
|
return existingTotal + additionalAccountsNeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 RandomPlayerbotFactory::CalculateAvailableCharsPerAccount()
|
uint32 RandomPlayerbotFactory::CalculateAvailableCharsPerAccount()
|
||||||
@@ -475,8 +556,9 @@ void RandomPlayerbotFactory::CreateRandomBots()
|
|||||||
LOG_INFO("playerbots", "Deleting all random bot characters and accounts...");
|
LOG_INFO("playerbots", "Deleting all random bot characters and accounts...");
|
||||||
|
|
||||||
// First execute all the cleanup SQL commands
|
// First execute all the cleanup SQL commands
|
||||||
// Clear playerbots_random_bots table
|
// Clear playerbots_random_bots and playerbots_account_type
|
||||||
PlayerbotsDatabase.Execute("DELETE FROM playerbots_random_bots");
|
PlayerbotsDatabase.Execute("DELETE FROM playerbots_random_bots");
|
||||||
|
PlayerbotsDatabase.Execute("DELETE FROM playerbots_account_type");
|
||||||
|
|
||||||
// Get the database names dynamically
|
// Get the database names dynamically
|
||||||
std::string loginDBName = LoginDatabase.GetConnectionInfo()->database;
|
std::string loginDBName = LoginDatabase.GetConnectionInfo()->database;
|
||||||
|
|||||||
@@ -515,15 +515,174 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/)
|
|||||||
// setActivityPercentage(activityPercentage);
|
// setActivityPercentage(activityPercentage);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// Assigns accounts as RNDbot accounts (type 1) based on MaxRandomBots and EnablePeriodicOnlineOffline and its ratio,
|
||||||
|
// and assigns accounts as AddClass accounts (type 2) based AddClassAccountPoolSize. Type 1 and 2 assignments are
|
||||||
|
// permenant, unless MaxRandomBots or AddClassAccountPoolSize are set to 0. If so, their associated accounts will
|
||||||
|
// be unassigned (type 0)
|
||||||
|
void RandomPlayerbotMgr::AssignAccountTypes()
|
||||||
|
{
|
||||||
|
LOG_INFO("playerbots", "Assigning account types for random bot accounts...");
|
||||||
|
|
||||||
|
// Clear existing filtered lists
|
||||||
|
rndBotTypeAccounts.clear();
|
||||||
|
addClassTypeAccounts.clear();
|
||||||
|
|
||||||
|
// First, get ALL randombot accounts from the database
|
||||||
|
std::vector<uint32> allRandomBotAccounts;
|
||||||
|
QueryResult allAccounts = LoginDatabase.Query(
|
||||||
|
"SELECT id FROM account WHERE username LIKE '{}%%' ORDER BY id",
|
||||||
|
sPlayerbotAIConfig->randomBotAccountPrefix.c_str());
|
||||||
|
|
||||||
|
if (allAccounts)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Field* fields = allAccounts->Fetch();
|
||||||
|
uint32 accountId = fields[0].Get<uint32>();
|
||||||
|
allRandomBotAccounts.push_back(accountId);
|
||||||
|
} while (allAccounts->NextRow());
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("playerbots", "Found {} total randombot accounts in database", allRandomBotAccounts.size());
|
||||||
|
|
||||||
|
// Check existing assignments
|
||||||
|
QueryResult existingAssignments = PlayerbotsDatabase.Query("SELECT account_id, account_type FROM playerbots_account_type");
|
||||||
|
std::map<uint32, uint8> currentAssignments;
|
||||||
|
|
||||||
|
if (existingAssignments)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Field* fields = existingAssignments->Fetch();
|
||||||
|
uint32 accountId = fields[0].Get<uint32>();
|
||||||
|
uint8 accountType = fields[1].Get<uint8>();
|
||||||
|
currentAssignments[accountId] = accountType;
|
||||||
|
} while (existingAssignments->NextRow());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark ALL randombot accounts as unassigned if not already assigned
|
||||||
|
for (uint32 accountId : allRandomBotAccounts)
|
||||||
|
{
|
||||||
|
if (currentAssignments.find(accountId) == currentAssignments.end())
|
||||||
|
{
|
||||||
|
PlayerbotsDatabase.Execute("INSERT INTO playerbots_account_type (account_id, account_type) VALUES ({}, 0) ON DUPLICATE KEY UPDATE account_type = account_type", accountId);
|
||||||
|
currentAssignments[accountId] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate needed RNDbot accounts
|
||||||
|
uint32 neededRndBotAccounts = 0;
|
||||||
|
if (sPlayerbotAIConfig->maxRandomBots > 0)
|
||||||
|
{
|
||||||
|
int divisor = RandomPlayerbotFactory::CalculateAvailableCharsPerAccount();
|
||||||
|
int maxBots = sPlayerbotAIConfig->maxRandomBots;
|
||||||
|
|
||||||
|
// Take periodic online-offline into account
|
||||||
|
if (sPlayerbotAIConfig->enablePeriodicOnlineOffline)
|
||||||
|
{
|
||||||
|
maxBots *= sPlayerbotAIConfig->periodicOnlineOfflineRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate base accounts needed for RNDbots, ensuring round up for maxBots not cleanly divisible by the divisor
|
||||||
|
neededRndBotAccounts = (maxBots + divisor - 1) / divisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count existing assigned accounts
|
||||||
|
uint32 existingRndBotAccounts = 0;
|
||||||
|
uint32 existingAddClassAccounts = 0;
|
||||||
|
|
||||||
|
for (const auto& [accountId, accountType] : currentAssignments)
|
||||||
|
{
|
||||||
|
if (accountType == 1) existingRndBotAccounts++;
|
||||||
|
else if (accountType == 2) existingAddClassAccounts++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign RNDbot accounts from lowest position if needed
|
||||||
|
if (existingRndBotAccounts < neededRndBotAccounts)
|
||||||
|
{
|
||||||
|
uint32 toAssign = neededRndBotAccounts - existingRndBotAccounts;
|
||||||
|
uint32 assigned = 0;
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < allRandomBotAccounts.size() && assigned < toAssign; i++)
|
||||||
|
{
|
||||||
|
uint32 accountId = allRandomBotAccounts[i];
|
||||||
|
if (currentAssignments[accountId] == 0) // Unassigned
|
||||||
|
{
|
||||||
|
PlayerbotsDatabase.Execute("UPDATE playerbots_account_type SET account_type = 1, assignment_date = NOW() WHERE account_id = {}", accountId);
|
||||||
|
currentAssignments[accountId] = 1;
|
||||||
|
assigned++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assigned < toAssign)
|
||||||
|
{
|
||||||
|
LOG_ERROR("playerbots", "Not enough unassigned accounts to fulfill RNDbot requirements. Need {} more accounts.", toAssign - assigned);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign AddClass accounts from highest position if needed
|
||||||
|
uint32 neededAddClassAccounts = sPlayerbotAIConfig->addClassAccountPoolSize;
|
||||||
|
|
||||||
|
if (existingAddClassAccounts < neededAddClassAccounts)
|
||||||
|
{
|
||||||
|
uint32 toAssign = neededAddClassAccounts - existingAddClassAccounts;
|
||||||
|
uint32 assigned = 0;
|
||||||
|
|
||||||
|
for (int i = allRandomBotAccounts.size() - 1; i >= 0 && assigned < toAssign; i--)
|
||||||
|
{
|
||||||
|
uint32 accountId = allRandomBotAccounts[i];
|
||||||
|
if (currentAssignments[accountId] == 0) // Unassigned
|
||||||
|
{
|
||||||
|
PlayerbotsDatabase.Execute("UPDATE playerbots_account_type SET account_type = 2, assignment_date = NOW() WHERE account_id = {}", accountId);
|
||||||
|
currentAssignments[accountId] = 2;
|
||||||
|
assigned++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assigned < toAssign)
|
||||||
|
{
|
||||||
|
LOG_ERROR("playerbots", "Not enough unassigned accounts to fulfill AddClass requirements. Need {} more accounts.", toAssign - assigned);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate filtered account lists with ALL accounts of each type
|
||||||
|
for (const auto& [accountId, accountType] : currentAssignments)
|
||||||
|
{
|
||||||
|
if (accountType == 1) rndBotTypeAccounts.push_back(accountId);
|
||||||
|
else if (accountType == 2) addClassTypeAccounts.push_back(accountId);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("playerbots", "Account type assignment complete: {} RNDbot accounts, {} AddClass accounts, {} unassigned",
|
||||||
|
rndBotTypeAccounts.size(), addClassTypeAccounts.size(),
|
||||||
|
currentAssignments.size() - rndBotTypeAccounts.size() - addClassTypeAccounts.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RandomPlayerbotMgr::IsAccountType(uint32 accountId, uint8 accountType)
|
||||||
|
{
|
||||||
|
QueryResult result = PlayerbotsDatabase.Query("SELECT 1 FROM playerbots_account_type WHERE account_id = {} AND account_type = {}", accountId, accountType);
|
||||||
|
return result != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logs-in bots in 4 phases. Phase 1 logs Alliance bots up to how much is expected according to the faction ratio,
|
||||||
|
// and Phase 2 logs-in the remainder Horde bots to reach the total maxAllowedBotCount. If maxAllowedBotCount is not
|
||||||
|
// reached after Phase 2, the function goes back to log-in Alliance bots and reach maxAllowedBotCount. This is done
|
||||||
|
// because not every account is guaranteed 5A/5H bots, so the true ratio might be skewed by few percentages. Finally,
|
||||||
|
// Phase 4 is reached if and only if the value of RandomBotAccountCount is lower than it should.
|
||||||
uint32 RandomPlayerbotMgr::AddRandomBots()
|
uint32 RandomPlayerbotMgr::AddRandomBots()
|
||||||
{
|
{
|
||||||
uint32 maxAllowedBotCount = GetEventValue(0, "bot_count");
|
uint32 maxAllowedBotCount = GetEventValue(0, "bot_count");
|
||||||
|
static time_t missingBotsTimer = 0;
|
||||||
|
|
||||||
if (currentBots.size() < maxAllowedBotCount)
|
if (currentBots.size() < maxAllowedBotCount)
|
||||||
{
|
{
|
||||||
|
// Calculate how many bots to add
|
||||||
maxAllowedBotCount -= currentBots.size();
|
maxAllowedBotCount -= currentBots.size();
|
||||||
maxAllowedBotCount = std::min(sPlayerbotAIConfig->randomBotsPerInterval, maxAllowedBotCount);
|
maxAllowedBotCount = std::min(sPlayerbotAIConfig->randomBotsPerInterval, maxAllowedBotCount);
|
||||||
|
|
||||||
|
// Single RNG instance for all shuffling
|
||||||
|
std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
|
||||||
|
|
||||||
|
// Only need to track the Alliance count, as it's in Phase 1
|
||||||
uint32 totalRatio = sPlayerbotAIConfig->randomBotAllianceRatio + sPlayerbotAIConfig->randomBotHordeRatio;
|
uint32 totalRatio = sPlayerbotAIConfig->randomBotAllianceRatio + sPlayerbotAIConfig->randomBotHordeRatio;
|
||||||
uint32 allowedAllianceCount = maxAllowedBotCount * (sPlayerbotAIConfig->randomBotAllianceRatio) / totalRatio;
|
uint32 allowedAllianceCount = maxAllowedBotCount * (sPlayerbotAIConfig->randomBotAllianceRatio) / totalRatio;
|
||||||
|
|
||||||
@@ -535,26 +694,42 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
|
|||||||
allowedAllianceCount++;
|
allowedAllianceCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 allowedHordeCount = maxAllowedBotCount - allowedAllianceCount;
|
// Determine which accounts to use based on EnablePeriodicOnlineOffline
|
||||||
|
std::vector<uint32> accountsToUse;
|
||||||
for (std::vector<uint32>::iterator i = sPlayerbotAIConfig->randomBotAccounts.begin();
|
if (sPlayerbotAIConfig->enablePeriodicOnlineOffline)
|
||||||
i != sPlayerbotAIConfig->randomBotAccounts.end(); i++)
|
|
||||||
{
|
{
|
||||||
uint32 accountId = *i;
|
|
||||||
if (sPlayerbotAIConfig->enablePeriodicOnlineOffline)
|
|
||||||
{
|
|
||||||
// minus addclass bots account
|
|
||||||
int32 baseAccount =
|
|
||||||
RandomPlayerbotFactory::CalculateTotalAccountCount() - sPlayerbotAIConfig->addClassAccountPoolSize;
|
|
||||||
|
|
||||||
if (baseAccount <= 0 || baseAccount > sPlayerbotAIConfig->randomBotAccounts.size())
|
// Calculate how many accounts can be used
|
||||||
{
|
// With enablePeriodicOnlineOffline, don't use all of rndBotTypeAccounts right away. Fraction results are rounded up
|
||||||
LOG_ERROR("playerbots", "Account calculation error with PeriodicOnlineOffline");
|
uint32 accountsToUseCount = (rndBotTypeAccounts.size() + sPlayerbotAIConfig->periodicOnlineOfflineRatio - 1)
|
||||||
return 0;
|
/ sPlayerbotAIConfig->periodicOnlineOfflineRatio;
|
||||||
}
|
|
||||||
uint32 index = urand(0, baseAccount - 1);
|
// Randomly select accounts
|
||||||
accountId = sPlayerbotAIConfig->randomBotAccounts[index];
|
std::vector<uint32> shuffledAccounts = rndBotTypeAccounts;
|
||||||
|
std::shuffle(shuffledAccounts.begin(), shuffledAccounts.end(), rng);
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < accountsToUseCount && i < shuffledAccounts.size(); i++)
|
||||||
|
{
|
||||||
|
accountsToUse.push_back(shuffledAccounts[i]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
accountsToUse = rndBotTypeAccounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pre-map all characters from selected accounts
|
||||||
|
struct CharacterInfo
|
||||||
|
{
|
||||||
|
uint32 guid;
|
||||||
|
uint8 rClass;
|
||||||
|
uint8 rRace;
|
||||||
|
uint32 accountId;
|
||||||
|
};
|
||||||
|
std::vector<CharacterInfo> allCharacters;
|
||||||
|
|
||||||
|
for (uint32 accountId : accountsToUse)
|
||||||
|
{
|
||||||
CharacterDatabasePreparedStatement* stmt =
|
CharacterDatabasePreparedStatement* stmt =
|
||||||
CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID);
|
CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID);
|
||||||
stmt->SetData(0, accountId);
|
stmt->SetData(0, accountId);
|
||||||
@@ -562,87 +737,115 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
|
|||||||
if (!result)
|
if (!result)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::vector<GuidClassRaceInfo> allGuidInfos;
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
Field* fields = result->Fetch();
|
Field* fields = result->Fetch();
|
||||||
GuidClassRaceInfo info;
|
CharacterInfo info;
|
||||||
info.guid = fields[0].Get<uint32>();
|
info.guid = fields[0].Get<uint32>();
|
||||||
info.rClass = fields[1].Get<uint8>();
|
info.rClass = fields[1].Get<uint8>();
|
||||||
info.rRace = fields[2].Get<uint8>();
|
info.rRace = fields[2].Get<uint8>();
|
||||||
allGuidInfos.push_back(info);
|
info.accountId = accountId;
|
||||||
|
allCharacters.push_back(info);
|
||||||
} while (result->NextRow());
|
} while (result->NextRow());
|
||||||
|
|
||||||
// random shuffle for class balance
|
|
||||||
std::mt19937 rnd(time(0));
|
|
||||||
std::shuffle(allGuidInfos.begin(), allGuidInfos.end(), rnd);
|
|
||||||
|
|
||||||
std::vector<uint32> guids;
|
|
||||||
for (const auto& info : allGuidInfos)
|
|
||||||
{
|
|
||||||
ObjectGuid::LowType guid = info.guid;
|
|
||||||
uint32 rClass = info.rClass;
|
|
||||||
uint32 rRace = info.rRace;
|
|
||||||
|
|
||||||
if (GetEventValue(guid, "add"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (GetEventValue(guid, "logout"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (GetPlayerBot(guid))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (std::find(currentBots.begin(), currentBots.end(), guid) != currentBots.end())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (sPlayerbotAIConfig->disableDeathKnightLogin)
|
|
||||||
{
|
|
||||||
if (rClass == CLASS_DEATH_KNIGHT)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 isAlliance = IsAlliance(rRace);
|
|
||||||
bool factionNotAllowed = (!allowedAllianceCount && isAlliance) || (!allowedHordeCount && !isAlliance);
|
|
||||||
|
|
||||||
if (factionNotAllowed)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (isAlliance)
|
|
||||||
{
|
|
||||||
allowedAllianceCount--;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
allowedHordeCount--;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 add_time = sPlayerbotAIConfig->enablePeriodicOnlineOffline
|
|
||||||
? urand(sPlayerbotAIConfig->minRandomBotInWorldTime,
|
|
||||||
sPlayerbotAIConfig->maxRandomBotInWorldTime)
|
|
||||||
: sPlayerbotAIConfig->permanantlyInWorldTime;
|
|
||||||
|
|
||||||
SetEventValue(guid, "add", 1, add_time);
|
|
||||||
SetEventValue(guid, "logout", 0, 0);
|
|
||||||
currentBots.push_back(guid);
|
|
||||||
|
|
||||||
maxAllowedBotCount--;
|
|
||||||
if (!maxAllowedBotCount)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!maxAllowedBotCount)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shuffle for class balance
|
||||||
|
std::shuffle(allCharacters.begin(), allCharacters.end(), rng);
|
||||||
|
|
||||||
|
// Separate characters by faction for phased login
|
||||||
|
std::vector<CharacterInfo> allianceChars;
|
||||||
|
std::vector<CharacterInfo> hordeChars;
|
||||||
|
|
||||||
|
for (const auto& charInfo : allCharacters)
|
||||||
|
{
|
||||||
|
if (IsAlliance(charInfo.rRace))
|
||||||
|
allianceChars.push_back(charInfo);
|
||||||
|
|
||||||
|
else
|
||||||
|
hordeChars.push_back(charInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lambda to handle bot login logic
|
||||||
|
auto tryLoginBot = [&](const CharacterInfo& charInfo) -> bool
|
||||||
|
{
|
||||||
|
if (GetEventValue(charInfo.guid, "add") ||
|
||||||
|
GetEventValue(charInfo.guid, "logout") ||
|
||||||
|
GetPlayerBot(charInfo.guid) ||
|
||||||
|
std::find(currentBots.begin(), currentBots.end(), charInfo.guid) != currentBots.end() ||
|
||||||
|
(sPlayerbotAIConfig->disableDeathKnightLogin && charInfo.rClass == CLASS_DEATH_KNIGHT))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 add_time = sPlayerbotAIConfig->enablePeriodicOnlineOffline
|
||||||
|
? urand(sPlayerbotAIConfig->minRandomBotInWorldTime,
|
||||||
|
sPlayerbotAIConfig->maxRandomBotInWorldTime)
|
||||||
|
: sPlayerbotAIConfig->permanantlyInWorldTime;
|
||||||
|
|
||||||
|
SetEventValue(charInfo.guid, "add", 1, add_time);
|
||||||
|
SetEventValue(charInfo.guid, "logout", 0, 0);
|
||||||
|
currentBots.push_back(charInfo.guid);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// PHASE 1: Log-in Alliance bots up to allowedAllianceCount
|
||||||
|
for (const auto& charInfo : allianceChars)
|
||||||
|
{
|
||||||
|
if (!allowedAllianceCount)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (tryLoginBot(charInfo))
|
||||||
|
{
|
||||||
|
maxAllowedBotCount--;
|
||||||
|
allowedAllianceCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PHASE 2: Log-in Horde bots up to maxAllowedBotCount
|
||||||
|
for (const auto& charInfo : hordeChars)
|
||||||
|
{
|
||||||
|
if (!maxAllowedBotCount)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (tryLoginBot(charInfo))
|
||||||
|
maxAllowedBotCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PHASE 3: If maxAllowedBotCount wasn't reached, log-in more Alliance bots
|
||||||
|
for (const auto& charInfo : allianceChars)
|
||||||
|
{
|
||||||
|
if (!maxAllowedBotCount)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (tryLoginBot(charInfo))
|
||||||
|
maxAllowedBotCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PHASE 4: An error is given if maxAllowedBotCount is still not reached
|
||||||
if (maxAllowedBotCount)
|
if (maxAllowedBotCount)
|
||||||
LOG_ERROR("playerbots",
|
{
|
||||||
"Not enough random bot accounts available. Try to increase RandomBotAccountCount "
|
if (missingBotsTimer == 0)
|
||||||
"in your conf file",
|
missingBotsTimer = time(nullptr);
|
||||||
ceil(maxAllowedBotCount / 10));
|
|
||||||
|
if (time(nullptr) - missingBotsTimer >= 10)
|
||||||
|
{
|
||||||
|
int divisor = RandomPlayerbotFactory::CalculateAvailableCharsPerAccount();
|
||||||
|
uint32 moreAccountsNeeded = (maxAllowedBotCount + divisor - 1) / divisor;
|
||||||
|
LOG_ERROR("playerbots",
|
||||||
|
"Can't log-in all the requested bots. Try increasing RandomBotAccountCount in your conf file.\n"
|
||||||
|
"{} more accounts needed.", moreAccountsNeeded);
|
||||||
|
missingBotsTimer = 0; // Reset timer so error is not spammed every tick
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
missingBotsTimer = 0; // Reset timer if logins for this interval were successful
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
missingBotsTimer = 0; // Reset timer if there's enough bots
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentBots.size();
|
return currentBots.size();
|
||||||
@@ -1165,7 +1368,6 @@ void RandomPlayerbotMgr::ScheduleChangeStrategy(uint32 bot, uint32 time)
|
|||||||
bool RandomPlayerbotMgr::ProcessBot(uint32 bot)
|
bool RandomPlayerbotMgr::ProcessBot(uint32 bot)
|
||||||
{
|
{
|
||||||
ObjectGuid botGUID = ObjectGuid::Create<HighGuid::Player>(bot);
|
ObjectGuid botGUID = ObjectGuid::Create<HighGuid::Player>(bot);
|
||||||
|
|
||||||
Player* player = GetPlayerBot(botGUID);
|
Player* player = GetPlayerBot(botGUID);
|
||||||
PlayerbotAI* botAI = player ? GET_PLAYERBOT_AI(player) : nullptr;
|
PlayerbotAI* botAI = player ? GET_PLAYERBOT_AI(player) : nullptr;
|
||||||
|
|
||||||
@@ -1875,24 +2077,21 @@ void RandomPlayerbotMgr::PrepareTeleportCache()
|
|||||||
|
|
||||||
void RandomPlayerbotMgr::PrepareAddclassCache()
|
void RandomPlayerbotMgr::PrepareAddclassCache()
|
||||||
{
|
{
|
||||||
/// @FIXME: Modifying RandomBotAccountCount may cause the original addclass bots to be converted into rndbots,
|
// Using accounts marked as type 2 (AddClass)
|
||||||
// which needs to be fixed by separating the two accounts in implementation
|
|
||||||
size_t poolSize = sPlayerbotAIConfig->addClassAccountPoolSize;
|
|
||||||
size_t start = sPlayerbotAIConfig->randomBotAccounts.size() > poolSize
|
|
||||||
? sPlayerbotAIConfig->randomBotAccounts.size() - poolSize
|
|
||||||
: 0;
|
|
||||||
int32 collected = 0;
|
int32 collected = 0;
|
||||||
for (size_t i = start; i < sPlayerbotAIConfig->randomBotAccounts.size(); i++)
|
|
||||||
|
for (uint32 accountId : addClassTypeAccounts)
|
||||||
{
|
{
|
||||||
for (uint8 claz = CLASS_WARRIOR; claz <= CLASS_DRUID; claz++)
|
for (uint8 claz = CLASS_WARRIOR; claz <= CLASS_DRUID; claz++)
|
||||||
{
|
{
|
||||||
if (claz == 10)
|
if (claz == 10)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
QueryResult results = CharacterDatabase.Query(
|
QueryResult results = CharacterDatabase.Query(
|
||||||
"SELECT guid, race FROM characters "
|
"SELECT guid, race FROM characters "
|
||||||
"WHERE account = {} AND class = '{}' AND online = 0 "
|
"WHERE account = {} AND class = '{}' AND online = 0",
|
||||||
"ORDER BY account DESC",
|
accountId, claz);
|
||||||
sPlayerbotAIConfig->randomBotAccounts[i], claz);
|
|
||||||
if (results)
|
if (results)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
@@ -1907,7 +2106,8 @@ void RandomPlayerbotMgr::PrepareAddclassCache()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG_INFO("playerbots", ">> {} characters collected for addclass command.", collected);
|
|
||||||
|
LOG_INFO("playerbots", ">> {} characters collected for addclass command from {} AddClass accounts.", collected, addClassTypeAccounts.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RandomPlayerbotMgr::Init()
|
void RandomPlayerbotMgr::Init()
|
||||||
@@ -2286,10 +2486,13 @@ bool RandomPlayerbotMgr::IsRandomBot(ObjectGuid::LowType bot)
|
|||||||
ObjectGuid guid = ObjectGuid::Create<HighGuid::Player>(bot);
|
ObjectGuid guid = ObjectGuid::Create<HighGuid::Player>(bot);
|
||||||
if (!sPlayerbotAIConfig->IsInRandomAccountList(sCharacterCache->GetCharacterAccountIdByGuid(guid)))
|
if (!sPlayerbotAIConfig->IsInRandomAccountList(sCharacterCache->GetCharacterAccountIdByGuid(guid)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (std::find(currentBots.begin(), currentBots.end(), bot) != currentBots.end())
|
if (std::find(currentBots.begin(), currentBots.end(), bot) != currentBots.end())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RandomPlayerbotMgr::IsAddclassBot(Player* bot)
|
bool RandomPlayerbotMgr::IsAddclassBot(Player* bot)
|
||||||
{
|
{
|
||||||
if (bot && GET_PLAYERBOT_AI(bot))
|
if (bot && GET_PLAYERBOT_AI(bot))
|
||||||
@@ -2301,23 +2504,37 @@ bool RandomPlayerbotMgr::IsAddclassBot(Player* bot)
|
|||||||
{
|
{
|
||||||
return IsAddclassBot(bot->GetGUID().GetCounter());
|
return IsAddclassBot(bot->GetGUID().GetCounter());
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RandomPlayerbotMgr::IsAddclassBot(ObjectGuid::LowType bot)
|
bool RandomPlayerbotMgr::IsAddclassBot(ObjectGuid::LowType bot)
|
||||||
{
|
{
|
||||||
ObjectGuid guid = ObjectGuid::Create<HighGuid::Player>(bot);
|
ObjectGuid guid = ObjectGuid::Create<HighGuid::Player>(bot);
|
||||||
|
|
||||||
|
// Check the cache with faction considerations
|
||||||
for (uint8 claz = CLASS_WARRIOR; claz <= CLASS_DRUID; claz++)
|
for (uint8 claz = CLASS_WARRIOR; claz <= CLASS_DRUID; claz++)
|
||||||
{
|
{
|
||||||
if (claz == 10)
|
if (claz == 10)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (uint8 isAlliance = 0; isAlliance <= 1; isAlliance++)
|
for (uint8 isAlliance = 0; isAlliance <= 1; isAlliance++)
|
||||||
{
|
{
|
||||||
if (addclassCache[GetTeamClassIdx(isAlliance, claz)].find(guid) !=
|
if (addclassCache[GetTeamClassIdx(isAlliance, claz)].find(guid) !=
|
||||||
addclassCache[GetTeamClassIdx(isAlliance, claz)].end())
|
addclassCache[GetTeamClassIdx(isAlliance, claz)].end())
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If not in cache, check the account type
|
||||||
|
uint32 accountId = sCharacterCache->GetCharacterAccountIdByGuid(guid);
|
||||||
|
if (accountId && IsAccountType(accountId, 2)) // Type 2 = AddClass
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ public:
|
|||||||
|
|
||||||
bool IsEmpty() { return !lastChangeTime; }
|
bool IsEmpty() { return !lastChangeTime; }
|
||||||
|
|
||||||
public:
|
|
||||||
uint32 value;
|
uint32 value;
|
||||||
uint32 lastChangeTime;
|
uint32 lastChangeTime;
|
||||||
uint32 validIn;
|
uint32 validIn;
|
||||||
@@ -104,10 +103,6 @@ public:
|
|||||||
void LogPlayerLocation();
|
void LogPlayerLocation();
|
||||||
void UpdateAIInternal(uint32 elapsed, bool minimal = false) override;
|
void UpdateAIInternal(uint32 elapsed, bool minimal = false) override;
|
||||||
|
|
||||||
private:
|
|
||||||
//void ScaleBotActivity();
|
|
||||||
|
|
||||||
public:
|
|
||||||
uint32 activeBots = 0;
|
uint32 activeBots = 0;
|
||||||
static bool HandlePlayerbotConsoleCommand(ChatHandler* handler, char const* args);
|
static bool HandlePlayerbotConsoleCommand(ChatHandler* handler, char const* args);
|
||||||
bool IsRandomBot(Player* bot);
|
bool IsRandomBot(Player* bot);
|
||||||
@@ -189,6 +184,11 @@ public:
|
|||||||
};
|
};
|
||||||
std::map<uint32, LevelBracket> zone2LevelBracket;
|
std::map<uint32, LevelBracket> zone2LevelBracket;
|
||||||
std::map<uint8, std::vector<WorldLocation>> bankerLocsPerLevelCache;
|
std::map<uint8, std::vector<WorldLocation>> bankerLocsPerLevelCache;
|
||||||
|
|
||||||
|
// Account type management
|
||||||
|
void AssignAccountTypes();
|
||||||
|
bool IsAccountType(uint32 accountId, uint8 accountType);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnBotLoginInternal(Player* const bot) override;
|
void OnBotLoginInternal(Player* const bot) override;
|
||||||
|
|
||||||
@@ -218,10 +218,8 @@ private:
|
|||||||
void RandomTeleport(Player* bot, std::vector<WorldLocation>& locs, bool hearth = false);
|
void RandomTeleport(Player* bot, std::vector<WorldLocation>& locs, bool hearth = false);
|
||||||
uint32 GetZoneLevel(uint16 mapId, float teleX, float teleY, float teleZ);
|
uint32 GetZoneLevel(uint16 mapId, float teleX, float teleY, float teleZ);
|
||||||
typedef void (RandomPlayerbotMgr::*ConsoleCommandHandler)(Player*);
|
typedef void (RandomPlayerbotMgr::*ConsoleCommandHandler)(Player*);
|
||||||
|
|
||||||
std::vector<Player*> players;
|
std::vector<Player*> players;
|
||||||
uint32 processTicks;
|
uint32 processTicks;
|
||||||
|
|
||||||
|
|
||||||
// std::map<uint32, std::vector<WorldLocation>> rpgLocsCache;
|
// std::map<uint32, std::vector<WorldLocation>> rpgLocsCache;
|
||||||
std::map<uint32, std::map<uint32, std::vector<WorldLocation>>> rpgLocsCacheLevel;
|
std::map<uint32, std::map<uint32, std::vector<WorldLocation>>> rpgLocsCacheLevel;
|
||||||
@@ -230,6 +228,12 @@ private:
|
|||||||
std::list<uint32> currentBots;
|
std::list<uint32> currentBots;
|
||||||
uint32 bgBotsCount;
|
uint32 bgBotsCount;
|
||||||
uint32 playersLevel;
|
uint32 playersLevel;
|
||||||
|
|
||||||
|
// Account lists
|
||||||
|
std::vector<uint32> rndBotTypeAccounts; // Accounts marked as RNDbot (type 1)
|
||||||
|
std::vector<uint32> addClassTypeAccounts; // Accounts marked as AddClass (type 2)
|
||||||
|
|
||||||
|
//void ScaleBotActivity(); // Deprecated function
|
||||||
};
|
};
|
||||||
|
|
||||||
#define sRandomPlayerbotMgr RandomPlayerbotMgr::instance()
|
#define sRandomPlayerbotMgr RandomPlayerbotMgr::instance()
|
||||||
|
|||||||
Reference in New Issue
Block a user