Core/Players: Prevent creating characters with duplicate name by reserving name early in the process

Closes #21656
Closes #21809

(cherry picked from commit fdb2b90685ebc3852740c424170101a196c29ebb)
This commit is contained in:
Shauren
2021-09-25 15:34:20 +02:00
parent 9775b4353e
commit 47630708f0
4 changed files with 26 additions and 1 deletions
+16
View File
@@ -30,6 +30,7 @@ namespace
{
std::unordered_map<ObjectGuid, CharacterCacheEntry> _characterCacheStore;
std::unordered_map<std::string, CharacterCacheEntry*> _characterCacheByNameStore;
std::unordered_set<std::string> _characterCreationNameStore;
}
CharacterCache::CharacterCache()
@@ -225,6 +226,21 @@ CharacterCacheEntry const* CharacterCache::GetCharacterCacheByName(std::string c
return nullptr;
}
std::shared_ptr<std::string const> CharacterCache::TryCreateCharacterWithName(std::string const& name) const
{
auto itr = _characterCacheByNameStore.find(name);
if (itr != _characterCacheByNameStore.end())
return nullptr;
auto insertResult = _characterCreationNameStore.insert(name);
if (!insertResult.second)
return nullptr;
// shared_ptr with custom deleter that erases its held value from _characterCreationNameStore instead of deleting it (points to value inside the container)
return std::shared_ptr<std::string const>(&(*insertResult.first),
[this](std::string const* storedName) { _characterCreationNameStore.erase(*storedName); });
}
ObjectGuid CharacterCache::GetCharacterGuidByName(std::string const& name) const
{
auto itr = _characterCacheByNameStore.find(name);
+1 -1
View File
@@ -58,7 +58,7 @@ class TC_GAME_API CharacterCache
bool HasCharacterCacheEntry(ObjectGuid const& guid) const;
CharacterCacheEntry const* GetCharacterCacheByGuid(ObjectGuid const& guid) const;
CharacterCacheEntry const* GetCharacterCacheByName(std::string const& name) const;
std::shared_ptr<std::string const> TryCreateCharacterWithName(std::string const& name) const;
ObjectGuid GetCharacterGuidByName(std::string const& name) const;
bool GetCharacterNameByGuid(ObjectGuid guid, std::string& name) const;
uint32 GetCharacterTeamByGuid(ObjectGuid guid) const;
@@ -704,6 +704,14 @@ void WorldSession::HandleCharCreateOpcode(WorldPackets::Character::CreateCharact
}
std::shared_ptr<WorldPackets::Character::CharacterCreateInfo> createInfo = charCreate.CreateInfo;
// Reserve the name for the duration of callback chain
createInfo->NameToken = sCharacterCache->TryCreateCharacterWithName(createInfo->Name);
if (!createInfo->NameToken)
{
SendCharCreate(CHAR_CREATE_NAME_IN_USE);
return;
}
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME);
stmt->setString(0, charCreate.CreateInfo->Name);
@@ -68,6 +68,7 @@ namespace WorldPackets
/// Server side data
uint8 CharCount = 0;
std::shared_ptr<std::string const> NameToken;
};
struct CharacterRenameInfo