diff options
author | xinef1 <w.szyszko2@gmail.com> | 2017-01-29 04:59:17 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2019-07-21 21:06:54 +0200 |
commit | 07d02d744f9ac82b0543559a15ace7b3035fdb99 (patch) | |
tree | 650fb029a8e4424c726747b2b02b3f432ee2d62e | |
parent | b742c872223950dfae14468b0e7a304a3e660e76 (diff) |
Remade who list processing (#18636)
* Remade who list processing, requests are now processed in maps. Player entries are now copied every 5 seconds to dedicated storage (avoids usage of hashmapholder mutex)
(cherrypicked from 88f746935ff6a9055c5712997254aff63b406352)
-rw-r--r-- | src/server/game/Handlers/MiscHandler.cpp | 61 | ||||
-rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Storages/WhoListStorage.cpp | 68 | ||||
-rw-r--r-- | src/server/game/Storages/WhoListStorage.h | 86 | ||||
-rw-r--r-- | src/server/game/World/World.cpp | 10 | ||||
-rw-r--r-- | src/server/game/World/World.h | 1 |
6 files changed, 188 insertions, 40 deletions
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index bdd7482c03b..65da0e6ff3f 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -49,6 +49,7 @@ #include "ScriptMgr.h" #include "Spell.h" #include "SpellPackets.h" +#include "WhoListStorage.h" #include "WhoPackets.h" #include "World.h" #include "WorldPacket.h" @@ -140,64 +141,46 @@ void WorldSession::HandleWhoOpcode(WorldPackets::Who::WhoRequestPkt& whoRequest) WorldPackets::Who::WhoResponsePkt response; - boost::shared_lock<boost::shared_mutex> lock(*HashMapHolder<Player>::GetLock()); - - HashMapHolder<Player>::MapType const& m = ObjectAccessor::GetPlayers(); - for (HashMapHolder<Player>::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr) + WhoListInfoVector const& whoList = sWhoListStorageMgr->GetWhoList(); + for (WhoListPlayerInfo const& target : whoList) { - Player* target = itr->second; // player can see member of other team only if has RBAC_PERM_TWO_SIDE_WHO_LIST - if (target->GetTeam() != team && !HasPermission(rbac::RBAC_PERM_TWO_SIDE_WHO_LIST)) + if (target.GetTeam() != team && !HasPermission(rbac::RBAC_PERM_TWO_SIDE_WHO_LIST)) continue; // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if has RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS - if (target->GetSession()->GetSecurity() > AccountTypes(gmLevelInWhoList) && !HasPermission(rbac::RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS)) - continue; - - // do not process players which are not in world - if (!target->IsInWorld()) + if (target.GetSecurity() > AccountTypes(gmLevelInWhoList) && !HasPermission(rbac::RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS)) continue; // check if target is globally visible for player - if (!target->IsVisibleGloballyFor(_player)) - continue; + if (_player->GetGUID() != target.GetGuid() && !target.IsVisible()) + if (AccountMgr::IsPlayerAccount(_player->GetSession()->GetSecurity()) || target.GetSecurity() > _player->GetSession()->GetSecurity()) + continue; // check if target's level is in level range - uint8 lvl = target->getLevel(); + uint8 lvl = target.GetLevel(); if (lvl < request.MinLevel || lvl > request.MaxLevel) continue; // check if class matches classmask - if (request.ClassFilter >= 0 && !(request.ClassFilter & (1 << target->getClass()))) + if (request.ClassFilter >= 0 && !(request.ClassFilter & (1 << target.GetClass()))) continue; // check if race matches racemask - if (request.RaceFilter >= 0 && !(request.RaceFilter & (SI64LIT(1) << target->getRace()))) + if (request.RaceFilter >= 0 && !(request.RaceFilter & (SI64LIT(1) << target.GetRace()))) continue; if (!whoRequest.Areas.empty()) { - if (std::find(whoRequest.Areas.begin(), whoRequest.Areas.end(), target->GetZoneId()) == whoRequest.Areas.end()) + if (std::find(whoRequest.Areas.begin(), whoRequest.Areas.end(), target.GetZoneId()) == whoRequest.Areas.end()) continue; } - std::wstring wTargetName; - - if (!Utf8toWStr(target->GetName(), wTargetName)) - continue; - - wstrToLower(wTargetName); - - if (!wPlayerName.empty() && wTargetName.find(wPlayerName) == std::wstring::npos) - continue; - - Guild* targetGuild = target->GetGuild(); - std::wstring wTargetGuildName; - - if (!Utf8toWStr(targetGuild ? targetGuild->GetName() : "", wTargetGuildName)) + std::wstring const& wTargetName = target.GetWidePlayerName(); + if (!(wPlayerName.empty() || wTargetName.find(wPlayerName) != std::wstring::npos)) continue; - wstrToLower(wTargetGuildName); + std::wstring const& wTargetGuildName = target.GetWideGuildName(); if (!wGuildName.empty() && wTargetGuildName.find(wGuildName) == std::wstring::npos) continue; @@ -205,7 +188,7 @@ void WorldSession::HandleWhoOpcode(WorldPackets::Who::WhoRequestPkt& whoRequest) if (!wWords.empty()) { std::string aName; - if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(target->GetZoneId())) + if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(target.GetZoneId())) aName = areaEntry->AreaName->Str[GetSessionDbcLocale()]; bool show = false; @@ -228,18 +211,18 @@ void WorldSession::HandleWhoOpcode(WorldPackets::Who::WhoRequestPkt& whoRequest) } WorldPackets::Who::WhoEntry whoEntry; - if (!whoEntry.PlayerData.Initialize(target->GetGUID(), target)) + if (!whoEntry.PlayerData.Initialize(target.GetGuid(), nullptr)) continue; - if (targetGuild) + if (!target.GetGuildGuid().IsEmpty()) { - whoEntry.GuildGUID = targetGuild->GetGUID(); + whoEntry.GuildGUID = target.GetGuildGuid(); whoEntry.GuildVirtualRealmAddress = GetVirtualRealmAddress(); - whoEntry.GuildName = targetGuild->GetName(); + whoEntry.GuildName = target.GetGuildName(); } - whoEntry.AreaID = target->GetZoneId(); - whoEntry.IsGM = target->IsGameMaster(); + whoEntry.AreaID = target.GetZoneId(); + whoEntry.IsGM = target.IsGameMaster(); response.Response.Entries.push_back(whoEntry); diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index d5b2be6428b..13306152bcd 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -870,7 +870,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_VOICE_CHAT_LOGIN, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_VOID_STORAGE_TRANSFER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleVoidStorageTransfer); DEFINE_HANDLER(CMSG_WARDEN_DATA, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleWardenData); - DEFINE_HANDLER(CMSG_WHO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleWhoOpcode); + DEFINE_HANDLER(CMSG_WHO, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleWhoOpcode); DEFINE_HANDLER(CMSG_WHO_IS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleWhoIsOpcode); DEFINE_HANDLER(CMSG_WORLD_PORT_RESPONSE, STATUS_TRANSFER, PROCESS_THREADUNSAFE, &WorldSession::HandleMoveWorldportAckOpcode); DEFINE_HANDLER(CMSG_WRAP_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleWrapItem); diff --git a/src/server/game/Storages/WhoListStorage.cpp b/src/server/game/Storages/WhoListStorage.cpp new file mode 100644 index 00000000000..ea02853dc0d --- /dev/null +++ b/src/server/game/Storages/WhoListStorage.cpp @@ -0,0 +1,68 @@ +/* +* Copyright (C) 2008-2019 TrinityCore <http://www.trinitycore.org/> +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at your +* option) any later version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along +* with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "WhoListStorage.h" +#include "World.h" +#include "ObjectAccessor.h" +#include "Player.h" +#include "GuildMgr.h" +#include "WorldSession.h" +#include "Guild.h" + +WhoListStorageMgr* WhoListStorageMgr::instance() +{ + static WhoListStorageMgr instance; + return &instance; +} + +void WhoListStorageMgr::Update() +{ + // clear current list + _whoListStorage.clear(); + _whoListStorage.reserve(sWorld->GetPlayerCount()+1); + + HashMapHolder<Player>::MapType const& m = ObjectAccessor::GetPlayers(); + for (HashMapHolder<Player>::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr) + { + if (!itr->second->FindMap() || itr->second->GetSession()->PlayerLoading()) + continue; + + std::string playerName = itr->second->GetName(); + std::wstring widePlayerName; + if (!Utf8toWStr(playerName, widePlayerName)) + continue; + + wstrToLower(widePlayerName); + + std::string guildName = sGuildMgr->GetGuildNameById(itr->second->GetGuildId()); + std::wstring wideGuildName; + if (!Utf8toWStr(guildName, wideGuildName)) + continue; + + wstrToLower(wideGuildName); + + Guild* guild = itr->second->GetGuild(); + ObjectGuid guildGuid; + + if (guild) + guildGuid = guild->GetGUID(); + + _whoListStorage.emplace_back(itr->second->GetGUID(), itr->second->GetTeam(), itr->second->GetSession()->GetSecurity(), itr->second->getLevel(), + itr->second->getClass(), itr->second->getRace(), itr->second->GetZoneId(), itr->second->m_playerData->NativeSex, itr->second->IsVisible(), + itr->second->IsGameMaster(), widePlayerName, wideGuildName, playerName, guildName, guildGuid); + } +} diff --git a/src/server/game/Storages/WhoListStorage.h b/src/server/game/Storages/WhoListStorage.h new file mode 100644 index 00000000000..d42e20cdc4c --- /dev/null +++ b/src/server/game/Storages/WhoListStorage.h @@ -0,0 +1,86 @@ +/* +* Copyright (C) 2008-2019 TrinityCore <http://www.trinitycore.org/> +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at your +* option) any later version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along +* with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _WHOLISTSTORAGE_H +#define _WHOLISTSTORAGE_H + +#include "Common.h" +#include "ObjectGuid.h" + +class WhoListPlayerInfo +{ +public: + WhoListPlayerInfo(ObjectGuid guid, uint32 team, AccountTypes security, uint8 level, uint8 clss, uint8 race, uint32 zoneid, uint8 gender, bool visible, bool gamemaster, std::wstring const& widePlayerName, + std::wstring const& wideGuildName, std::string const& playerName, std::string const& guildName, ObjectGuid guildguid) : + _guid(guid), _team(team), _security(security), _level(level), _class(clss), _race(race), _zoneid(zoneid), _gender(gender), _visible(visible), + _gamemaster(gamemaster), _widePlayerName(widePlayerName), _wideGuildName(wideGuildName), _playerName(playerName), _guildName(guildName), _guildguid(guildguid) {} + + ObjectGuid GetGuid() const { return _guid; } + uint32 GetTeam() const { return _team; } + AccountTypes GetSecurity() const { return _security; } + uint8 GetLevel() const { return _level; } + uint8 GetClass() const { return _class; } + uint8 GetRace() const { return _race; } + uint32 GetZoneId() const { return _zoneid; } + uint8 GetGender() const { return _gender; } + bool IsVisible() const { return _visible; } + bool IsGameMaster() const { return _gamemaster; } + std::wstring const& GetWidePlayerName() const { return _widePlayerName; } + std::wstring const& GetWideGuildName() const { return _wideGuildName; } + std::string const& GetPlayerName() const { return _playerName; } + std::string const& GetGuildName() const { return _guildName; } + ObjectGuid GetGuildGuid() const { return _guildguid; } + +private: + ObjectGuid _guid; + uint32 _team; + AccountTypes _security; + uint8 _level; + uint8 _class; + uint8 _race; + uint32 _zoneid; + uint8 _gender; + bool _visible; + bool _gamemaster; + std::wstring _widePlayerName; + std::wstring _wideGuildName; + std::string _playerName; + std::string _guildName; + ObjectGuid _guildguid; +}; + +typedef std::vector<WhoListPlayerInfo> WhoListInfoVector; + +class TC_GAME_API WhoListStorageMgr +{ +private: + WhoListStorageMgr() { }; + ~WhoListStorageMgr() { }; + +public: + static WhoListStorageMgr* instance(); + + void Update(); + WhoListInfoVector const& GetWhoList() const { return _whoListStorage; } + +protected: + WhoListInfoVector _whoListStorage; +}; + +#define sWhoListStorageMgr WhoListStorageMgr::instance() + +#endif // _WHOLISTSTORAGE_H diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 7abaf15a857..bb0c517dbf4 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -91,6 +91,7 @@ #include "WaypointManager.h" #include "WaypointMovementGenerator.h" #include "WeatherMgr.h" +#include "WhoListStorage.h" #include "WorldSession.h" #include "WorldSocket.h" @@ -2102,6 +2103,8 @@ void World::SetInitialWorldSettings() m_timers[WUPDATE_CHECK_FILECHANGES].SetInterval(500); + m_timers[WUPDATE_WHO_LIST].SetInterval(5 * IN_MILLISECONDS); // update who list cache every 5 seconds + //to set mailtimer to return mails every day between 4 and 5 am //mailtimer is increased when updating auctions //one second is 1000 -(tested on win system) @@ -2305,6 +2308,13 @@ void World::Update(uint32 diff) m_timers[i].SetCurrent(0); } + ///- Update Who List Storage + if (m_timers[WUPDATE_WHO_LIST].Passed()) + { + m_timers[WUPDATE_WHO_LIST].Reset(); + sWhoListStorageMgr->Update(); + } + ///- Update the game time and check for shutdown time _UpdateGameTime(); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 18c0770fece..9715cff322f 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -93,6 +93,7 @@ enum WorldTimers WUPDATE_GUILDSAVE, WUPDATE_BLACKMARKET, WUPDATE_CHECK_FILECHANGES, + WUPDATE_WHO_LIST, WUPDATE_COUNT }; |