Core/Packets: converted CMSG_WHO and SMSG_WHO to packet class

This commit is contained in:
Ovahlord
2020-04-18 18:22:31 +02:00
parent ee9f0b9bf0
commit 631236fa8a
7 changed files with 301 additions and 122 deletions

View File

@@ -48,10 +48,12 @@
#include "Opcodes.h"
#include "OutdoorPvP.h"
#include "Player.h"
#include "QueryPackets.h"
#include "ScriptMgr.h"
#include "Spell.h"
#include "SpellInfo.h"
#include "WhoListStorage.h"
#include "WhoPackets.h"
#include "World.h"
#include "WorldPacket.h"
#include <zlib.h>
@@ -178,89 +180,62 @@ void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket& recvData)
}
}
void WorldSession::HandleWhoOpcode(WorldPacket& recvData)
void WorldSession::HandleWhoOpcode(WorldPackets::Who::WhoRequestPkt& whoRequest)
{
TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_WHO Message");
WorldPackets::Who::WhoRequest& request = whoRequest.Request;
uint32 matchCount = 0;
uint32 levelMin, levelMax, racemask, classmask, zonesCount, strCount;
uint32 zoneids[10]; // 10 is client limit
std::string packetPlayerName, packetGuildName;
recvData >> levelMin; // maximal player level, default 0
recvData >> levelMax; // minimal player level, default 100 (MAX_LEVEL)
recvData >> packetPlayerName; // player name, case sensitive...
recvData >> packetGuildName; // guild name, case sensitive...
recvData >> racemask; // race mask
recvData >> classmask; // class mask
recvData >> zonesCount; // zones count, client limit = 10 (2.0.10)
if (zonesCount > 10)
return; // can't be received from real client or broken packet
for (uint32 i = 0; i < zonesCount; ++i)
{
uint32 temp;
recvData >> temp; // zone id, 0 if zone is unknown...
zoneids[i] = temp;
TC_LOG_DEBUG("network", "Zone %u: %u", i, zoneids[i]);
}
recvData >> strCount; // user entered strings count, client limit=4 (checked on 2.0.10)
if (strCount > 4)
return; // can't be received from real client or broken packet
TC_LOG_DEBUG("network", "Minlvl %u, maxlvl %u, name %s, guild %s, racemask %u, classmask %u, zones %u, strings %u", levelMin, levelMax, packetPlayerName.c_str(), packetGuildName.c_str(), racemask, classmask, zonesCount, strCount);
std::wstring str[4]; // 4 is client limit
for (uint32 i = 0; i < strCount; ++i)
{
std::string temp;
recvData >> temp; // user entered string, it used as universal search pattern(guild+player name)?
if (!Utf8toWStr(temp, str[i]))
continue;
wstrToLower(str[i]);
TC_LOG_DEBUG("network", "String %u: %s", i, temp.c_str());
}
std::wstring wpacketPlayerName;
std::wstring wpacketGuildName;
if (!(Utf8toWStr(packetPlayerName, wpacketPlayerName) && Utf8toWStr(packetGuildName, wpacketGuildName)))
// zones count, client limit = 10 (2.0.10)
// can't be received from real client or broken packet
if (whoRequest.Request.Areas.size() > 10)
return;
wstrToLower(wpacketPlayerName);
wstrToLower(wpacketGuildName);
// user entered strings count, client limit=4 (checked on 2.0.10)
// can't be received from real client or broken packet
if (request.Words.size() > 4)
return;
std::vector<std::wstring> wWords;
wWords.resize(request.Words.size());
for (size_t i = 0; i < request.Words.size(); ++i)
{
TC_LOG_DEBUG("network", "WorldSession::HandleWhoOpcode: Word: %s", request.Words[i].Word.c_str());
// user entered string, it used as universal search pattern(guild+player name)?
if (!Utf8toWStr(request.Words[i].Word, wWords[i]))
continue;
wstrToLower(wWords[i]);
}
std::wstring wPlayerName;
std::wstring wGuildName;
if (!(Utf8toWStr(request.Name, wPlayerName) && Utf8toWStr(request.Guild, wGuildName)))
return;
wstrToLower(wPlayerName);
wstrToLower(wGuildName);
// client send in case not set max level value 100 but Trinity supports 255 max level,
// update it to show GMs with characters after 100 level
if (levelMax >= MAX_LEVEL)
levelMax = STRONG_MAX_LEVEL;
if (whoRequest.Request.MaxLevel >= MAX_LEVEL)
whoRequest.Request.MaxLevel = STRONG_MAX_LEVEL;
uint32 team = _player->GetTeam();
uint32 gmLevelInWhoList = sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST);
uint32 displayCount = 0;
uint32 gmLevelInWhoList = sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST);
WorldPacket data(SMSG_WHO, 500); // guess size
data << uint32(matchCount); // placeholder, count of players matching criteria
data << uint32(displayCount); // placeholder, count of players displayed
WorldPackets::Who::WhoResponsePkt response;
WhoListInfoVector const& whoList = sWhoListStorageMgr->GetWhoList();
for (WhoListPlayerInfo const& target : whoList)
{
// player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST
// 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))
continue;
// player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST
if (!HasPermission(rbac::RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS) && target.GetSecurity() > AccountTypes(gmLevelInWhoList))
// player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if has RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS
if (target.GetSecurity() > AccountTypes(gmLevelInWhoList) && !HasPermission(rbac::RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS))
continue;
// check if target is globally visible for player
@@ -270,87 +245,75 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData)
// check if target's level is in level range
uint8 lvl = target.GetLevel();
if (lvl < levelMin || lvl > levelMax)
if (lvl < request.MinLevel || lvl > request.MaxLevel)
continue;
// check if class matches classmask
uint8 class_ = target.GetClass();
if (!(classmask & (1 << class_)))
if (request.ClassFilter >= 0 && !(request.ClassFilter & (1 << target.GetClass())))
continue;
// check if race matches racemask
uint32 race = target.GetRace();
if (!(racemask & (1 << race)))
if (request.RaceFilter >= 0 && (request.RaceFilter & (1 << target.GetRace())))
continue;
uint32 playerZoneId = target.GetZoneId();
uint8 gender = target.GetGender();
bool showZones = true;
for (uint32 i = 0; i < zonesCount; ++i)
if (!whoRequest.Request.Areas.empty())
{
if (zoneids[i] == playerZoneId)
{
showZones = true;
break;
}
showZones = false;
if (std::find(whoRequest.Request.Areas.begin(), whoRequest.Request.Areas.end(), target.GetZoneId()) == whoRequest.Request.Areas.end())
continue;
}
if (!showZones)
std::wstring const& wTargetName = target.GetWidePlayerName();
if (!(wPlayerName.empty() || wTargetName.find(wPlayerName) != std::wstring::npos))
continue;
std::wstring const& wideplayername = target.GetWidePlayerName();
if (!(wpacketPlayerName.empty() || wideplayername.find(wpacketPlayerName) != std::wstring::npos))
std::wstring const& wTargetGuildName = target.GetWideGuildName();
if (!wGuildName.empty() && wTargetGuildName.find(wGuildName) == std::wstring::npos)
continue;
std::wstring const& wideguildname = target.GetWideGuildName();
if (!(wpacketGuildName.empty() || wideguildname.find(wpacketGuildName) != std::wstring::npos))
continue;
std::string aname;
if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(playerZoneId))
aname = areaEntry->AreaName[GetSessionDbcLocale()];
bool s_show = true;
for (uint32 i = 0; i < strCount; ++i)
if (!wWords.empty())
{
if (!str[i].empty())
std::string aName;
if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(target.GetZoneId()))
aName = areaEntry->AreaName[GetSessionDbcLocale()];
bool show = false;
for (size_t i = 0; i < wWords.size(); ++i)
{
if (wideguildname.find(str[i]) != std::wstring::npos ||
wideplayername.find(str[i]) != std::wstring::npos ||
Utf8FitTo(aname, str[i]))
if (!wWords[i].empty())
{
s_show = true;
break;
if (wTargetName.find(wWords[i]) != std::wstring::npos ||
wTargetGuildName.find(wWords[i]) != std::wstring::npos ||
Utf8FitTo(aName, wWords[i]))
{
show = true;
break;
}
}
s_show = false;
}
if (!show)
continue;
}
if (!s_show)
WorldPackets::Who::WhoEntry whoEntry;
if (!whoEntry.PlayerData.Initialize(target.GetGuid(), nullptr))
continue;
// 49 is maximum player count sent to client - can be overridden
if (!target.GetGuildName().empty())
whoEntry.GuildName = target.GetGuildName();
whoEntry.AreaID = target.GetZoneId();
response.Response.Entries.push_back(whoEntry);
// 50 is maximum player count sent to client - can be overridden
// through config, but is unstable
if ((matchCount++) >= sWorld->getIntConfig(CONFIG_MAX_WHO))
continue;
data << target.GetPlayerName(); // player name
data << target.GetGuildName(); // guild name
data << uint32(lvl); // player level
data << uint32(class_); // player class
data << uint32(race); // player race
data << uint8(gender); // player gender
data << uint32(playerZoneId); // player zone id
++displayCount;
if (response.Response.Entries.size() >= sWorld->getIntConfig(CONFIG_MAX_WHO))
break;
}
data.put(0, displayCount); // insert right count, count displayed
data.put(4, matchCount); // insert right count, count of matches
SendPacket(&data);
TC_LOG_DEBUG("network", "WORLD: Send SMSG_WHO Message");
SendPacket(response.Write());
}
void WorldSession::HandleLogoutRequestOpcode(WorldPacket& /*recvData*/)

View File

@@ -28,6 +28,7 @@
#include "QuestPackets.h"
#include "QueryPackets.h"
#include "SystemPackets.h"
#include "WhoPackets.h"
#include "WorldStatePackets.h"
#endif // AllPackets_h__

View File

@@ -15,6 +15,8 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CharacterCache.h"
#include "Player.h"
#include "QueryPackets.h"
void WorldPackets::Query::DBQueryBulk::Read()
@@ -75,3 +77,31 @@ WorldPacket const* WorldPackets::Query::HotfixNotifyBlob::Write()
return &_worldPacket;
}
bool WorldPackets::Query::PlayerGuidLookupData::Initialize(ObjectGuid const& guid, Player const* player /*= nullptr*/)
{
CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(guid);
if (!characterInfo)
return false;
if (player)
{
ASSERT(player->GetGUID() == guid);
Name = player->GetName();
Race = player->getRace();
Sex = player->getGender();
ClassID = player->getClass();
Level = player->getLevel();
}
else
{
Name = characterInfo->Name;
Race = characterInfo->Race;
Sex = characterInfo->Sex;
ClassID = characterInfo->Class;
Level = characterInfo->Level;
}
return true;
}

View File

@@ -21,6 +21,9 @@
#include "Packet.h"
#include "DB2Stores.h"
#include "ObjectGuid.h"
#include "SharedDefines.h"
class Player;
namespace WorldPackets
{
@@ -65,6 +68,17 @@ namespace WorldPackets
HotfixData const* Hotfixes = nullptr;
};
struct PlayerGuidLookupData
{
bool Initialize(ObjectGuid const& guid, Player const* player = nullptr);
std::string Name;
uint8 Race = RACE_NONE;
uint8 Sex = GENDER_NONE;
uint8 ClassID = CLASS_NONE;
uint8 Level = 0;
};
}
}

View File

@@ -0,0 +1,87 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* 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 "WhoPackets.h"
ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Who::WhoWord& word)
{
data >> word.Word;
return data;
}
ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Who::WhoRequest& request)
{
data >> request.MinLevel;
data >> request.MaxLevel;
data >> request.Guild;
data >> request.Name;
data >> request.RaceFilter;
data >> request.ClassFilter;
uint32 areas = 0;
data >> areas;
request.Areas.resize(areas);
for (size_t i = 0; i < request.Areas.size(); ++i)
data >> request.Areas[i];
uint32 words = 0;
data >> words;
request.Words.resize(words);
for (size_t i = 0; i < request.Words.size(); ++i)
data >> request.Words[i];
return data;
}
void WorldPackets::Who::WhoRequestPkt::Read()
{
_worldPacket >> Request;
}
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Who::WhoEntry const& entry)
{
data << entry.PlayerData.Name;
data << entry.GuildName;
data << uint32(entry.PlayerData.Level);
data << uint32(entry.PlayerData.ClassID);
data << uint32(entry.PlayerData.Race);
data << uint8(entry.PlayerData.Sex);
data << uint32(entry.AreaID);
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Who::WhoResponse const& response)
{
data << uint32(response.Entries.size()); // Number of displayed characters
data << uint32(response.Entries.size()); // Number of matching characters (when using filters) TODO
for (WorldPackets::Who::WhoEntry const& whoEntry : response.Entries)
data << whoEntry;
return data;
}
WorldPacket const* WorldPackets::Who::WhoResponsePkt::Write()
{
_worldPacket << Response;
return &_worldPacket;
}

View File

@@ -0,0 +1,79 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* 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 WhoPackets_h__
#define WhoPackets_h__
#include "Packet.h"
#include "QueryPackets.h"
namespace WorldPackets
{
namespace Who
{
struct WhoWord
{
std::string Word;
};
struct WhoRequest
{
int32 MinLevel = 0;
int32 MaxLevel = 0;
std::string Name;
std::string Guild;
int32 RaceFilter = -1;
int32 ClassFilter = -1;
std::vector<WhoWord> Words;
std::vector<int32> Areas;
};
class WhoRequestPkt final : public ClientPacket
{
public:
WhoRequestPkt(WorldPacket&& packet) : ClientPacket(CMSG_WHO, std::move(packet)) { }
void Read() override;
WhoRequest Request;
};
struct WhoEntry
{
Query::PlayerGuidLookupData PlayerData;
std::string GuildName;
int32 AreaID = 0;
};
struct WhoResponse
{
std::vector<WhoEntry> Entries;
};
class WhoResponsePkt final : public ServerPacket
{
public:
WhoResponsePkt() : ServerPacket(SMSG_WHO, 1) { }
WorldPacket const* Write() override;
WhoResponse Response;
};
}
}
#endif // WhoPackets_h__

View File

@@ -171,6 +171,11 @@ namespace WorldPackets
{
class DBQueryBulk;
}
namespace Who
{
class WhoRequestPkt;
}
}
enum AccountDataType
@@ -656,7 +661,7 @@ class TC_GAME_API WorldSession
void HandleLootOpcode(WorldPacket& recvPacket);
void HandleLootReleaseOpcode(WorldPacket& recvPacket);
void HandleLootMasterGiveOpcode(WorldPacket& recvPacket);
void HandleWhoOpcode(WorldPacket& recvPacket);
void HandleWhoOpcode(WorldPackets::Who::WhoRequestPkt& whoRequest);
void HandleLogoutRequestOpcode(WorldPacket& recvPacket);
void HandlePlayerLogoutOpcode(WorldPacket& recvPacket);
void HandleLogoutCancelOpcode(WorldPacket& recvPacket);