diff options
-rw-r--r-- | src/server/game/Cache/CharacterCache.cpp | 16 | ||||
-rw-r--r-- | src/server/game/Cache/CharacterCache.h | 2 | ||||
-rw-r--r-- | src/server/game/Handlers/CharacterHandler.cpp | 8 | ||||
-rw-r--r-- | src/server/game/Server/Packets/CharacterPackets.h | 1 |
4 files changed, 26 insertions, 1 deletions
diff --git a/src/server/game/Cache/CharacterCache.cpp b/src/server/game/Cache/CharacterCache.cpp index a078c502e40..27b5dab47b6 100644 --- a/src/server/game/Cache/CharacterCache.cpp +++ b/src/server/game/Cache/CharacterCache.cpp @@ -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); diff --git a/src/server/game/Cache/CharacterCache.h b/src/server/game/Cache/CharacterCache.h index a9a872da837..3f8a49dc861 100644 --- a/src/server/game/Cache/CharacterCache.h +++ b/src/server/game/Cache/CharacterCache.h @@ -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; diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 20652bb9fee..9410cc7174b 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -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); diff --git a/src/server/game/Server/Packets/CharacterPackets.h b/src/server/game/Server/Packets/CharacterPackets.h index 1d50331f6c8..60539d8196d 100644 --- a/src/server/game/Server/Packets/CharacterPackets.h +++ b/src/server/game/Server/Packets/CharacterPackets.h @@ -68,6 +68,7 @@ namespace WorldPackets /// Server side data uint8 CharCount = 0; + std::shared_ptr<std::string const> NameToken; }; struct CharacterRenameInfo |