Skip to content

Commit

Permalink
Merge pull request liyunfan1223#489 from hermensbas/feature/performan…
Browse files Browse the repository at this point in the history
…ce_botnames_loading_with_cache

Performance loading the botnames from a cache
  • Loading branch information
liyunfan1223 authored Aug 22, 2024
2 parents 1aa9145 + aa1ae40 commit 1a8fcc6
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 21 deletions.
3 changes: 1 addition & 2 deletions sql/characters/playerbots_names.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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;
ALTER TABLE `playerbots_names` ADD UNIQUE INDEX name(name, gender);
69 changes: 51 additions & 18 deletions src/RandomPlayerbotFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<NameRaceAndGender, std::vector<std::string>>& nameCache)
{
LOG_DEBUG("playerbots", "Creating new random bot for class {}", cls);

Expand All @@ -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<uint8> skinColors, facialHairTypes;
std::vector<std::pair<uint8, uint8>> faces, hairs;
Expand Down Expand Up @@ -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<uint8>(raceAndGender));
if (!result)
{
break;
}

Field* fields = result->Fetch();
std::string ret = fields[0].Get<std::string>();
if (ObjectMgr::CheckPlayerName(ret) == CHAR_NAME_SUCCESS) // Checks for reservation & profanity, too
botName = fields[0].Get<std::string>();
if (ObjectMgr::CheckPlayerName(botName) == CHAR_NAME_SUCCESS) // Checks for reservation & profanity, too
{
return ret;
}
return botName;
}
}

// CONLANG NAME GENERATION
Expand Down Expand Up @@ -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);
Expand All @@ -389,12 +406,28 @@ void RandomPlayerbotFactory::CreateRandomBots()
return;
}

uint32 totalAccCount = sPlayerbotAIConfig->randomBotAccountCount;

LOG_INFO("playerbots", "Creating random bot accounts...");

std::unordered_map<NameRaceAndGender, std::vector<std::string>> nameCache;
uint32 totalAccCount = sPlayerbotAIConfig->randomBotAccountCount;
std::vector<std::future<void>> 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<std::string>();
NameRaceAndGender raceAndGender = static_cast<NameRaceAndGender>(fields[1].Get<uint8>());
nameCache[raceAndGender].push_back(name);

} while (result->NextRow());

for (uint32 accountNumber = 0; accountNumber < sPlayerbotAIConfig->randomBotAccountCount; ++accountNumber)
{
std::ostringstream out;
Expand Down Expand Up @@ -435,10 +468,10 @@ void RandomPlayerbotFactory::CreateRandomBots()
LOG_INFO("playerbots", "Creating random bot characters...");
uint32 totalRandomBotChars = 0;
uint32 totalCharCount = sPlayerbotAIConfig->randomBotAccountCount * 10;

std::vector<std::pair<Player*, uint32>> playerBots;
std::vector<WorldSession*> sessionBots;
int bot_creation = 0;

for (uint32 accountNumber = 0; accountNumber < sPlayerbotAIConfig->randomBotAccountCount; ++accountNumber)
{
std::ostringstream out;
Expand All @@ -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,
Expand All @@ -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(),
Expand Down
2 changes: 1 addition & 1 deletion src/RandomPlayerbotFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<NameRaceAndGender, std::vector<std::string>>& names);
static void CreateRandomBots();
static void CreateRandomGuilds();
static void CreateRandomArenaTeams(ArenaType slot, uint32 count);
Expand Down

0 comments on commit 1a8fcc6

Please sign in to comment.