From 63e7b227d830be132817dde7fe481b1b9e6b69ba Mon Sep 17 00:00:00 2001 From: bash Date: Wed, 21 Aug 2024 18:11:19 +0000 Subject: [PATCH 1/2] Loading the botnames from a cache --- src/RandomPlayerbotFactory.cpp | 69 +++++++++++++++++++++++++--------- src/RandomPlayerbotFactory.h | 2 +- 2 files changed, 52 insertions(+), 19 deletions(-) diff --git a/src/RandomPlayerbotFactory.cpp b/src/RandomPlayerbotFactory.cpp index 386efc4da..a0a02f1db 100644 --- a/src/RandomPlayerbotFactory.cpp +++ b/src/RandomPlayerbotFactory.cpp @@ -150,7 +150,7 @@ RandomPlayerbotFactory::RandomPlayerbotFactory(uint32 accountId) : accountId(acc } } -Player* RandomPlayerbotFactory::CreateRandomBot(WorldSession* session, uint8 cls) +Player* RandomPlayerbotFactory::CreateRandomBot(WorldSession* session, uint8 cls, std::unordered_map>& nameCache) { LOG_DEBUG("playerbots", "Creating new random bot for class {}", cls); @@ -168,14 +168,28 @@ Player* RandomPlayerbotFactory::CreateRandomBot(WorldSession* session, uint8 cls const auto raceAndGender = CombineRaceAndGender(gender, race); - std::string name = CreateRandomBotName(raceAndGender); - + std::string name; + if (nameCache.empty()) + { + name = CreateRandomBotName(raceAndGender); + } + else + { + if (nameCache[raceAndGender].empty()) + { + LOG_ERROR("playerbots", "No name found for race and gender: {}", raceAndGender); + return nullptr; + } + uint32 i = urand(0, nameCache[raceAndGender].size() - 1); + name = nameCache[raceAndGender][i]; + swap(nameCache[raceAndGender][i], nameCache[raceAndGender].back()); + nameCache[raceAndGender].pop_back(); + } if (name.empty()) { LOG_ERROR("playerbots", "Unable to get random bot name!"); return nullptr; } - CharacterDatabase.DirectExecute("UPDATE playerbots_names SET in_use=1 WHERE name='{}'", name); std::vector skinColors, facialHairTypes; std::vector> faces, hairs; @@ -242,23 +256,27 @@ Player* RandomPlayerbotFactory::CreateRandomBot(WorldSession* session, uint8 cls std::string const RandomPlayerbotFactory::CreateRandomBotName(NameRaceAndGender raceAndGender) { std::string botName = ""; - int tries = 10; + int tries = 3; while (--tries) { QueryResult result = CharacterDatabase.Query( - "SELECT name FROM playerbots_names " - "WHERE in_use = 0 AND gender = {} ORDER BY RAND() LIMIT 1", + "SELECT n.name " + "FROM playerbots_names n " + "LEFT OUTER JOIN characters c ON c.name = n.name " + "WHERE c.guid IS NULL and n.gender = '{}' " + "ORDER BY RAND() LIMIT 1", static_cast(raceAndGender)); if (!result) { break; } + Field* fields = result->Fetch(); - std::string ret = fields[0].Get(); - if (ObjectMgr::CheckPlayerName(ret) == CHAR_NAME_SUCCESS) // Checks for reservation & profanity, too + botName = fields[0].Get(); + if (ObjectMgr::CheckPlayerName(botName) == CHAR_NAME_SUCCESS) // Checks for reservation & profanity, too { - return ret; - } + return botName; + } } // CONLANG NAME GENERATION @@ -379,7 +397,6 @@ void RandomPlayerbotFactory::CreateRandomBots() } PlayerbotsDatabase.Execute(PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_DEL_RANDOM_BOTS)); - CharacterDatabase.DirectExecute("UPDATE playerbots_names SET in_use = 0 WHERE in_use = 1"); /* 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); @@ -389,12 +406,28 @@ void RandomPlayerbotFactory::CreateRandomBots() return; } - uint32 totalAccCount = sPlayerbotAIConfig->randomBotAccountCount; - LOG_INFO("playerbots", "Creating random bot accounts..."); - + std::unordered_map> nameCache; + uint32 totalAccCount = sPlayerbotAIConfig->randomBotAccountCount; std::vector> account_creations; int account_creation = 0; + + LOG_INFO("playerbots", "Creating cache for names, 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()); + nameCache[raceAndGender].push_back(name); + + } while (result->NextRow()); + for (uint32 accountNumber = 0; accountNumber < sPlayerbotAIConfig->randomBotAccountCount; ++accountNumber) { std::ostringstream out; @@ -435,10 +468,10 @@ void RandomPlayerbotFactory::CreateRandomBots() LOG_INFO("playerbots", "Creating random bot characters..."); uint32 totalRandomBotChars = 0; uint32 totalCharCount = sPlayerbotAIConfig->randomBotAccountCount * 10; - std::vector> playerBots; std::vector sessionBots; int bot_creation = 0; + for (uint32 accountNumber = 0; accountNumber < sPlayerbotAIConfig->randomBotAccountCount; ++accountNumber) { std::ostringstream out; @@ -462,7 +495,7 @@ void RandomPlayerbotFactory::CreateRandomBots() continue; } LOG_INFO("playerbots", "Creating random bot characters for account: [{}/{}]", accountNumber + 1, - sPlayerbotAIConfig->randomBotAccountCount); + sPlayerbotAIConfig->randomBotAccountCount); RandomPlayerbotFactory factory(accountId); WorldSession* session = new WorldSession(accountId, "", nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING, @@ -483,7 +516,7 @@ void RandomPlayerbotFactory::CreateRandomBots() if (cls != 10) { - if (Player* playerBot = factory.CreateRandomBot(session, cls)) + if (Player* playerBot = factory.CreateRandomBot(session, cls, nameCache)) { playerBot->SaveToDB(true, false); sCharacterCache->AddCharacterCacheEntry(playerBot->GetGUID(), accountId, playerBot->GetName(), diff --git a/src/RandomPlayerbotFactory.h b/src/RandomPlayerbotFactory.h index fd541bda9..aa36450a0 100644 --- a/src/RandomPlayerbotFactory.h +++ b/src/RandomPlayerbotFactory.h @@ -49,7 +49,7 @@ class RandomPlayerbotFactory RandomPlayerbotFactory(uint32 accountId); virtual ~RandomPlayerbotFactory() {} - Player* CreateRandomBot(WorldSession* session, uint8 cls); + Player* CreateRandomBot(WorldSession* session, uint8 cls, std::unordered_map>& names); static void CreateRandomBots(); static void CreateRandomGuilds(); static void CreateRandomArenaTeams(ArenaType slot, uint32 count); From aa1ae40e2cc4102255d5183f6a9455b5418d0669 Mon Sep 17 00:00:00 2001 From: bash Date: Wed, 21 Aug 2024 19:34:26 +0000 Subject: [PATCH 2/2] Minor correction in logging text and removed in_use from the playerbots_names table and added an additional index for the fallback --- sql/characters/playerbots_names.sql | 3 +-- src/RandomPlayerbotFactory.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/sql/characters/playerbots_names.sql b/sql/characters/playerbots_names.sql index cadcac9da..ba42fe950 100644 --- a/sql/characters/playerbots_names.sql +++ b/sql/characters/playerbots_names.sql @@ -100010,5 +100010,4 @@ INSERT INTO `playerbots_names` VALUES DELETE FROM `playerbots_names` WHERE LENGTH(`name`) > 12; ALTER TABLE `playerbots_names` MODIFY `name` varchar(12); - -ALTER TABLE `playerbots_names` ADD in_use BIT default 0; \ No newline at end of file +ALTER TABLE `playerbots_names` ADD UNIQUE INDEX name(name, gender); diff --git a/src/RandomPlayerbotFactory.cpp b/src/RandomPlayerbotFactory.cpp index a0a02f1db..1171fc9e5 100644 --- a/src/RandomPlayerbotFactory.cpp +++ b/src/RandomPlayerbotFactory.cpp @@ -412,7 +412,7 @@ void RandomPlayerbotFactory::CreateRandomBots() std::vector> account_creations; int account_creation = 0; - LOG_INFO("playerbots", "Creating cache for names, gender and race."); + LOG_INFO("playerbots", "Creating cache for names per gender and race."); QueryResult result = CharacterDatabase.Query("SELECT name, gender FROM playerbots_names"); if (!result) {