diff --git a/src/RandomPlayerbotFactory.cpp b/src/RandomPlayerbotFactory.cpp index fdd4ae0f..e83a8c1c 100644 --- a/src/RandomPlayerbotFactory.cpp +++ b/src/RandomPlayerbotFactory.cpp @@ -14,6 +14,7 @@ #include "ScriptMgr.h" #include "SharedDefines.h" #include "SocialMgr.h" +#include "Timer.h" std::map> RandomPlayerbotFactory::availableRaces; @@ -282,6 +283,12 @@ std::string const RandomPlayerbotFactory::CreateRandomBotName(NameRaceAndGender botName = fields[0].Get(); if (ObjectMgr::CheckPlayerName(botName) == CHAR_NAME_SUCCESS) // Checks for reservation & profanity, too { + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); + stmt->SetData(0, botName); + + if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) + continue; + return botName; } } @@ -346,6 +353,14 @@ std::string const RandomPlayerbotFactory::CreateRandomBotName(NameRaceAndGender botName.clear(); continue; } + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); + stmt->SetData(0, botName); + + if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) + { + botName.clear(); + continue; + } return std::move(botName); } @@ -363,6 +378,14 @@ std::string const RandomPlayerbotFactory::CreateRandomBotName(NameRaceAndGender botName.clear(); continue; } + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); + stmt->SetData(0, botName); + + if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) + { + botName.clear(); + continue; + } return std::move(botName); } LOG_ERROR("playerbots", "Random name generation failed."); @@ -404,10 +427,12 @@ void RandomPlayerbotFactory::CreateRandomBots() } PlayerbotsDatabase.Execute(PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_DEL_RANDOM_BOTS)); - /* TODO(yunfan): we need to sleep here to wait for async account deleted, or the newly account won't be created - correctly the better way is turning the async db operation to sync db operation */ - std::this_thread::sleep_for(10ms * sPlayerbotAIConfig->randomBotAccountCount); - LOG_INFO("playerbots", "Random bot characters deleted."); + uint32 timer = getMSTime(); + while (LoginDatabase.QueueSize()) + { + std::this_thread::sleep_for(1s); + } + LOG_INFO("playerbots", ">> Random bot accounts deleted in {} ms", GetMSTimeDiffToNow(timer)); LOG_INFO("playerbots", "Please reset the AiPlayerbot.DeleteRandomBotAccounts to 0 and restart the server..."); World::StopNow(SHUTDOWN_EXIT_CODE); return; @@ -419,23 +444,6 @@ void RandomPlayerbotFactory::CreateRandomBots() std::vector> account_creations; int account_creation = 0; - LOG_INFO("playerbots", "Creating cache for names per gender and race."); - QueryResult result = CharacterDatabase.Query("SELECT name, gender FROM playerbots_names"); - if (!result) - { - LOG_ERROR("playerbots", "No more unused names left"); - return; - } - do - { - Field* fields = result->Fetch(); - std::string name = fields[0].Get(); - NameRaceAndGender raceAndGender = static_cast(fields[1].Get()); - if (sObjectMgr->CheckPlayerName(name) == CHAR_NAME_SUCCESS) - nameCache[raceAndGender].push_back(name); - - } while (result->NextRow()); - for (uint32 accountNumber = 0; accountNumber < sPlayerbotAIConfig->randomBotAccountCount; ++accountNumber) { std::ostringstream out; @@ -468,9 +476,14 @@ void RandomPlayerbotFactory::CreateRandomBots() if (account_creation) { - /* wait for async accounts create to make character create correctly, same as account delete */ - LOG_INFO("playerbots", "Waiting for {} accounts loading into database...", account_creation); - std::this_thread::sleep_for(10ms * sPlayerbotAIConfig->randomBotAccountCount); + LOG_INFO("playerbots", "Waiting for {} accounts loading into database ({} queries)...", account_creation, LoginDatabase.QueueSize()); + /* wait for async accounts create to make character create correctly */ + uint32 timer = getMSTime(); + while (LoginDatabase.QueueSize()) + { + std::this_thread::sleep_for(1s); + } + LOG_INFO("playerbots", ">> {} Accounts loaded into database in {} ms", account_creation, GetMSTimeDiffToNow(timer)); } LOG_INFO("playerbots", "Creating random bot characters..."); @@ -480,6 +493,7 @@ void RandomPlayerbotFactory::CreateRandomBots() std::vector sessionBots; int bot_creation = 0; + bool nameCached = false; for (uint32 accountNumber = 0; accountNumber < sPlayerbotAIConfig->randomBotAccountCount; ++accountNumber) { std::ostringstream out; @@ -502,7 +516,37 @@ void RandomPlayerbotFactory::CreateRandomBots() { continue; } - LOG_INFO("playerbots", "Creating random bot characters for account: [{}/{}]", accountNumber + 1, + + if (!nameCached) + { + nameCached = true; + LOG_INFO("playerbots", "Creating cache for names per gender and race..."); + QueryResult result = CharacterDatabase.Query("SELECT name, gender FROM playerbots_names"); + if (!result) + { + LOG_ERROR("playerbots", "No more unused names left"); + return; + } + do + { + Field* fields = result->Fetch(); + std::string name = fields[0].Get(); + NameRaceAndGender raceAndGender = static_cast(fields[1].Get()); + if (sObjectMgr->CheckPlayerName(name) == CHAR_NAME_SUCCESS) + { + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); + stmt->SetData(0, name); + + if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) + continue; + + nameCache[raceAndGender].push_back(name); + } + + } while (result->NextRow()); + } + + LOG_DEBUG("playerbots", "Creating random bot characters for account: [{}/{}]", accountNumber + 1, sPlayerbotAIConfig->randomBotAccountCount); RandomPlayerbotFactory factory(accountId); @@ -544,9 +588,14 @@ void RandomPlayerbotFactory::CreateRandomBots() if (bot_creation) { - LOG_INFO("playerbots", "Waiting for {} characters loading into database...", bot_creation); + LOG_INFO("playerbots", "Waiting for {} characters loading into database ({} queries)...", bot_creation, CharacterDatabase.QueueSize()); /* wait for characters load into database, or characters will fail to loggin */ - std::this_thread::sleep_for(5s + bot_creation * 5ms); + uint32 timer = getMSTime(); + while (CharacterDatabase.QueueSize()) + { + std::this_thread::sleep_for(1s); + } + LOG_INFO("playerbots", ">> {} Characters loaded into database in {} ms", bot_creation, GetMSTimeDiffToNow(timer)); } for (WorldSession* session : sessionBots) diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index 81b5ce20..3c90c5cf 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -567,9 +567,7 @@ void RandomPlayerbotMgr::LoadBattleMastersCache() { BattleMastersCache.clear(); - LOG_INFO("playerbots", "---------------------------------------"); - LOG_INFO("playerbots", " Loading BattleMasters Cache "); - LOG_INFO("playerbots", "---------------------------------------"); + LOG_INFO("playerbots", "Loading BattleMasters Cache..."); QueryResult result = WorldDatabase.Query("SELECT `entry`,`bg_template` FROM `battlemaster_entry`"); @@ -1534,9 +1532,9 @@ void RandomPlayerbotMgr::PrepareTeleportCache() } LOG_INFO("playerbots", ">> {} locations for level collected.", collected_locs); - LOG_INFO("playerbots", "Preparing innkeepers locations for level..."); if (sPlayerbotAIConfig->enableNewRpgStrategy) { + LOG_INFO("playerbots", "Preparing innkeepers locations for level..."); results = WorldDatabase.Query( "SELECT " "map, "