Core/Packets: convert CMSG_ENUM_CHARACTERS and SMSG_ENUM_CHARACTERS_R… (#24)

* Core/Packets: convert CMSG_ENUM_CHARACTERS and SMSG_ENUM_CHARACTERS_RESULT to packet class

* Cleanup some excessive large spaces

* These entire spaces must be purged

* Order members by type size and alphabetical

* Change TaggedPosition into Position
This commit is contained in:
Ghaster
2020-01-19 23:17:26 +01:00
committed by Ovah
parent 135eb3e5a0
commit 2587802100
11 changed files with 416 additions and 287 deletions

View File

@@ -105,51 +105,6 @@
#define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS)
enum CharacterFlags
{
CHARACTER_FLAG_NONE = 0x00000000,
CHARACTER_FLAG_UNK1 = 0x00000001,
CHARACTER_FLAG_UNK2 = 0x00000002,
CHARACTER_LOCKED_FOR_TRANSFER = 0x00000004,
CHARACTER_FLAG_UNK4 = 0x00000008,
CHARACTER_FLAG_UNK5 = 0x00000010,
CHARACTER_FLAG_UNK6 = 0x00000020,
CHARACTER_FLAG_UNK7 = 0x00000040,
CHARACTER_FLAG_UNK8 = 0x00000080,
CHARACTER_FLAG_UNK9 = 0x00000100,
CHARACTER_FLAG_UNK10 = 0x00000200,
CHARACTER_FLAG_HIDE_HELM = 0x00000400,
CHARACTER_FLAG_HIDE_CLOAK = 0x00000800,
CHARACTER_FLAG_UNK13 = 0x00001000,
CHARACTER_FLAG_GHOST = 0x00002000,
CHARACTER_FLAG_RENAME = 0x00004000,
CHARACTER_FLAG_UNK16 = 0x00008000,
CHARACTER_FLAG_UNK17 = 0x00010000,
CHARACTER_FLAG_UNK18 = 0x00020000,
CHARACTER_FLAG_UNK19 = 0x00040000,
CHARACTER_FLAG_UNK20 = 0x00080000,
CHARACTER_FLAG_UNK21 = 0x00100000,
CHARACTER_FLAG_UNK22 = 0x00200000,
CHARACTER_FLAG_UNK23 = 0x00400000,
CHARACTER_FLAG_UNK24 = 0x00800000,
CHARACTER_FLAG_LOCKED_BY_BILLING = 0x01000000,
CHARACTER_FLAG_DECLINED = 0x02000000,
CHARACTER_FLAG_UNK27 = 0x04000000,
CHARACTER_FLAG_UNK28 = 0x08000000,
CHARACTER_FLAG_UNK29 = 0x10000000,
CHARACTER_FLAG_UNK30 = 0x20000000,
CHARACTER_FLAG_UNK31 = 0x40000000,
CHARACTER_FLAG_UNK32 = 0x80000000
};
enum CharacterCustomizeFlags
{
CHAR_CUSTOMIZE_FLAG_NONE = 0x00000000,
CHAR_CUSTOMIZE_FLAG_CUSTOMIZE = 0x00000001, // name, gender, etc...
CHAR_CUSTOMIZE_FLAG_FACTION = 0x00010000, // name, gender, faction, etc...
CHAR_CUSTOMIZE_FLAG_RACE = 0x00100000 // name, gender, race, etc...
};
// corpse reclaim times
#define DEATH_EXPIRE_STEP (5*MINUTE)
#define MAX_DEATH_COUNT 3
@@ -1452,200 +1407,6 @@ void Player::setDeathState(DeathState s)
SetUInt32Value(PLAYER_SELF_RES_SPELL, 0);
}
bool Player::BuildEnumData(PreparedQueryResult result, ByteBuffer* dataBuffer, ByteBuffer* bitBuffer)
{
// 0 1 2 3 4 5 6 7
// SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.skin, characters.face, characters.hairStyle,
// 8 9 10 11 12 13 14 15
// characters.hairColor, characters.facialStyle, characters.level, characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z,
// 16 17 18 19 20 21 22
// guild_member.guildid, characters.playerFlags, characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.data,
// 23 24 25
// character_banned.guid, characters.slot, character_declinedname.genitive
Field* fields = result->Fetch();
ObjectGuid guid(HighGuid::Player, fields[0].GetUInt32());
std::string name = fields[1].GetString();
uint8 plrRace = fields[2].GetUInt8();
uint8 plrClass = fields[3].GetUInt8();
uint8 gender = fields[4].GetUInt8();
uint8 skin = fields[5].GetUInt8();
uint8 face = fields[6].GetUInt8();
uint8 hairStyle = fields[7].GetUInt8();
uint8 hairColor = fields[8].GetUInt8();
uint8 facialStyle = fields[9].GetUInt8();
uint8 level = fields[10].GetUInt8();
uint32 zone = fields[11].GetUInt16();
uint32 mapId = uint32(fields[12].GetUInt16());
float x = fields[13].GetFloat();
float y = fields[14].GetFloat();
float z = fields[15].GetFloat();
uint32 guildId = fields[16].GetUInt32();
ObjectGuid guildGuid;
if (guildId)
guildGuid = ObjectGuid(HighGuid::Guild, guildId);
uint32 playerFlags = fields[17].GetUInt32();
uint32 atLoginFlags = fields[18].GetUInt16();
Tokenizer equipment(fields[22].GetString(), ' ');
uint8 slot = fields[24].GetUInt8();
if (!ValidateAppearance(uint8(plrRace), uint8(plrClass), gender, hairStyle, hairColor, face, facialStyle, skin))
{
TC_LOG_ERROR("entities.player.loading", "Player %s has wrong Appearance values (Hair/Skin/Color), forcing recustomize", guid.ToString().c_str());
// Make sure customization always works properly - send all zeroes instead
skin = 0, face = 0, hairStyle = 0, hairColor = 0, facialStyle = 0;
if (!(atLoginFlags & AT_LOGIN_CUSTOMIZE))
{
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG);
stmt->setUInt16(0, uint16(AT_LOGIN_CUSTOMIZE));
stmt->setUInt32(1, guid);
CharacterDatabase.Execute(stmt);
atLoginFlags |= AT_LOGIN_CUSTOMIZE;
}
}
uint32 charFlags = 0;
if (atLoginFlags & AT_LOGIN_RESURRECT)
playerFlags &= ~PLAYER_FLAGS_GHOST;
if (playerFlags & PLAYER_FLAGS_HIDE_HELM)
charFlags |= CHARACTER_FLAG_HIDE_HELM;
if (playerFlags & PLAYER_FLAGS_HIDE_CLOAK)
charFlags |= CHARACTER_FLAG_HIDE_CLOAK;
if (playerFlags & PLAYER_FLAGS_GHOST)
charFlags |= CHARACTER_FLAG_GHOST;
if (atLoginFlags & AT_LOGIN_RENAME)
charFlags |= CHARACTER_FLAG_RENAME;
if (fields[23].GetUInt32())
charFlags |= CHARACTER_FLAG_LOCKED_BY_BILLING;
if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED) && !fields[22].GetString().empty())
charFlags |= CHARACTER_FLAG_DECLINED;
uint32 customizationFlag = 0;
if (atLoginFlags & AT_LOGIN_CUSTOMIZE)
customizationFlag = CHAR_CUSTOMIZE_FLAG_CUSTOMIZE;
else if (atLoginFlags & AT_LOGIN_CHANGE_FACTION)
customizationFlag = CHAR_CUSTOMIZE_FLAG_FACTION;
else if (atLoginFlags & AT_LOGIN_CHANGE_RACE)
customizationFlag = CHAR_CUSTOMIZE_FLAG_RACE;
uint32 petDisplayId = 0;
uint32 petLevel = 0;
CreatureFamily petFamily = CREATURE_FAMILY_NONE;
// show pet at selection character in character list only for non-ghost character
if (result && !(playerFlags & PLAYER_FLAGS_GHOST) && (plrClass == CLASS_WARLOCK || plrClass == CLASS_HUNTER || plrClass == CLASS_DEATH_KNIGHT))
{
uint32 entry = fields[19].GetUInt32();
CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(entry);
if (creatureInfo)
{
petDisplayId = fields[20].GetUInt32();
petLevel = fields[21].GetUInt16();
petFamily = creatureInfo->family;
}
}
// Packet content flags
bitBuffer->WriteBit(guid[3]);
bitBuffer->WriteBit(guildGuid[1]);
bitBuffer->WriteBit(guildGuid[7]);
bitBuffer->WriteBit(guildGuid[2]);
bitBuffer->WriteBits(uint32(name.length()), 7);
bitBuffer->WriteBit(guid[4]);
bitBuffer->WriteBit(guid[7]);
bitBuffer->WriteBit(guildGuid[3]);
bitBuffer->WriteBit(guid[5]);
bitBuffer->WriteBit(guildGuid[6]);
bitBuffer->WriteBit(guid[1]);
bitBuffer->WriteBit(guildGuid[5]);
bitBuffer->WriteBit(guildGuid[4]);
bitBuffer->WriteBit(atLoginFlags & AT_LOGIN_FIRST);
bitBuffer->WriteBit(guid[0]);
bitBuffer->WriteBit(guid[2]);
bitBuffer->WriteBit(guid[6]);
bitBuffer->WriteBit(guildGuid[0]);
// Character data
*dataBuffer << uint8(plrClass); // Class
for (uint8 slot = 0; slot < INVENTORY_SLOT_BAG_END; ++slot)
{
uint32 visualbase = slot * 2;
uint32 itemId = GetUInt32ValueFromArray(equipment, visualbase);
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
if (!proto)
{
*dataBuffer << uint8(0);
*dataBuffer << uint32(0);
*dataBuffer << uint32(0);
continue;
}
SpellItemEnchantmentEntry const* enchant = nullptr;
uint32 enchants = GetUInt32ValueFromArray(equipment, visualbase + 1);
for (uint8 enchantSlot = PERM_ENCHANTMENT_SLOT; enchantSlot <= TEMP_ENCHANTMENT_SLOT; ++enchantSlot)
{
// values stored in 2 uint16
uint32 enchantId = 0x0000FFFF & (enchants >> enchantSlot * 16);
if (!enchantId)
continue;
enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId);
if (enchant)
break;
}
*dataBuffer << uint8(proto->InventoryType);
*dataBuffer << uint32(proto->DisplayInfoID);
*dataBuffer << uint32(enchant ? enchant->aura_id : 0);
}
*dataBuffer << uint32(petFamily); // Pet family
dataBuffer->WriteByteSeq(guildGuid[2]);
*dataBuffer << uint8(slot); // List order
*dataBuffer << uint8(hairStyle); // Hair style
dataBuffer->WriteByteSeq(guildGuid[3]);
*dataBuffer << uint32(petDisplayId); // Pet DisplayID
*dataBuffer << uint32(charFlags); // Character flags
*dataBuffer << uint8(hairColor); // Hair color
dataBuffer->WriteByteSeq(guid[4]);
*dataBuffer << uint32(mapId); // Map Id
dataBuffer->WriteByteSeq(guildGuid[5]);
*dataBuffer << float(z); // Z
dataBuffer->WriteByteSeq(guildGuid[6]);
*dataBuffer << uint32(petLevel); // Pet level
dataBuffer->WriteByteSeq(guid[3]);
*dataBuffer << float(y); // Y
*dataBuffer << uint32(customizationFlag); // Character customization flags
*dataBuffer << uint8(facialStyle); // Facial hair
dataBuffer->WriteByteSeq(guid[7]);
*dataBuffer << uint8(gender); // Gender
dataBuffer->append(name.c_str(), name.length()); // Name
*dataBuffer << uint8(face); // Face
dataBuffer->WriteByteSeq(guid[0]);
dataBuffer->WriteByteSeq(guid[2]);
dataBuffer->WriteByteSeq(guildGuid[1]);
dataBuffer->WriteByteSeq(guildGuid[7]);
*dataBuffer << float(x); // X
*dataBuffer << uint8(skin); // Skin
*dataBuffer << uint8(plrRace); // Race
*dataBuffer << uint8(level); // Level
dataBuffer->WriteByteSeq(guid[6]);
dataBuffer->WriteByteSeq(guildGuid[4]);
dataBuffer->WriteByteSeq(guildGuid[0]);
dataBuffer->WriteByteSeq(guid[5]);
dataBuffer->WriteByteSeq(guid[1]);
*dataBuffer << uint32(zone); // Zone id
return true;
}
void Player::ToggleAFK()
{
ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK);

View File

@@ -1047,8 +1047,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void Update(uint32 time) override;
static bool BuildEnumData(PreparedQueryResult result, ByteBuffer* dataBuffer, ByteBuffer* bitBuffer);
bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit* caster) const override;
void SetInWater(bool apply);

View File

@@ -23,6 +23,7 @@
#include "BattlenetServerManager.h"
#include "CalendarMgr.h"
#include "CharacterCache.h"
#include "CharacterPackets.h"
#include "Chat.h"
#include "DatabaseEnv.h"
#include "DBCStores.h"
@@ -242,53 +243,56 @@ bool LoginQueryHolder::Initialize()
void WorldSession::HandleCharEnum(PreparedQueryResult result)
{
uint32 charCount = 0;
ByteBuffer bitBuffer;
ByteBuffer dataBuffer;
WorldPackets::Character::EnumCharactersResult charEnum;
charEnum.Success = true;
_legitCharacters.clear();
bitBuffer.WriteBits(0, 23);
bitBuffer.WriteBit(1);
if (result)
{
_legitCharacters.clear();
charCount = uint32(result->GetRowCount());
bitBuffer.reserve(24 * charCount / 8);
dataBuffer.reserve(charCount * 381);
bitBuffer.WriteBits(charCount, 17);
do
{
ObjectGuid guid(HighGuid::Player, (*result)[0].GetUInt32());
charEnum.Characters.emplace_back(result->Fetch());
TC_LOG_INFO("network", "Loading char guid %s from account %u.", guid.ToString().c_str(), GetAccountId());
WorldPackets::Character::EnumCharactersResult::CharacterInfo& charInfo = charEnum.Characters.back();
Player::BuildEnumData(result, &dataBuffer, &bitBuffer);
TC_LOG_INFO("network", "Loading char guid %s from account %u.", charInfo.Guid.ToString().c_str(), GetAccountId());
// Do not allow banned characters to log in
if (!(*result)[23].GetUInt32())
_legitCharacters.insert(guid);
if (!Player::ValidateAppearance(charInfo.RaceID, charInfo.ClassID, charInfo.SexID, charInfo.HairStyle, charInfo.HairColor, charInfo.FaceID, charInfo.FacialHair, charInfo.SkinID))
{
TC_LOG_ERROR("entities.player.loading", "Player %s has wrong Appearance values (Hair/Skin/Color), forcing recustomize", charInfo.Guid.ToString().c_str());
if (!sCharacterCache->HasCharacterCacheEntry(guid)) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet.
sCharacterCache->AddCharacterCacheEntry(guid, GetAccountId(), (*result)[1].GetString(), (*result)[4].GetUInt8(), (*result)[2].GetUInt8(), (*result)[3].GetUInt8(), (*result)[10].GetUInt8());
// Make sure customization always works properly - send all zeroes instead
charInfo.SkinID = 0;
charInfo.FaceID = 0;
charInfo.HairStyle = 0;
charInfo.HairColor = 0;
charInfo.FacialHair = 0;
} while (result->NextRow());
if (!(charInfo.Flags2 == CHAR_CUSTOMIZE_FLAG_CUSTOMIZE))
{
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG);
stmt->setUInt16(0, uint16(AT_LOGIN_CUSTOMIZE));
stmt->setUInt32(1, charInfo.Guid.GetCounter());
CharacterDatabase.Execute(stmt);
charInfo.Flags2 = CHAR_CUSTOMIZE_FLAG_CUSTOMIZE;
}
}
// Do not allow locked characters to login
if (!(charInfo.Flags & (CHARACTER_FLAG_LOCKED_FOR_TRANSFER | CHARACTER_FLAG_LOCKED_BY_BILLING)))
_legitCharacters.insert(charInfo.Guid);
if (!sCharacterCache->HasCharacterCacheEntry(charInfo.Guid)) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet.
sCharacterCache->AddCharacterCacheEntry(charInfo.Guid, GetAccountId(), charInfo.Name, charInfo.SexID, charInfo.RaceID, charInfo.ClassID, charInfo.ExperienceLevel);
}
while (result->NextRow());
}
else
bitBuffer.WriteBits(0, 17);
bitBuffer.FlushBits();
WorldPacket data(SMSG_CHAR_ENUM, 7 + bitBuffer.size() + dataBuffer.size());
data.append(bitBuffer);
if (charCount)
data.append(dataBuffer);
SendPacket(&data);
SendPacket(charEnum.Write());
}
void WorldSession::HandleCharEnumOpcode(WorldPacket& /*recvData*/)
void WorldSession::HandleCharEnumOpcode(WorldPackets::Character::EnumCharacters& /*enumCharacters*/)
{
// remove expired bans
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_EXPIRED_BANS);

View File

@@ -780,6 +780,51 @@ enum SheathTypes
#define MAX_SHEATHETYPE 8
enum CharacterFlags
{
CHARACTER_FLAG_NONE = 0x00000000,
CHARACTER_FLAG_UNK1 = 0x00000001,
CHARACTER_FLAG_UNK2 = 0x00000002,
CHARACTER_FLAG_LOCKED_FOR_TRANSFER = 0x00000004,
CHARACTER_FLAG_UNK4 = 0x00000008,
CHARACTER_FLAG_UNK5 = 0x00000010,
CHARACTER_FLAG_UNK6 = 0x00000020,
CHARACTER_FLAG_UNK7 = 0x00000040,
CHARACTER_FLAG_UNK8 = 0x00000080,
CHARACTER_FLAG_UNK9 = 0x00000100,
CHARACTER_FLAG_UNK10 = 0x00000200,
CHARACTER_FLAG_HIDE_HELM = 0x00000400,
CHARACTER_FLAG_HIDE_CLOAK = 0x00000800,
CHARACTER_FLAG_UNK13 = 0x00001000,
CHARACTER_FLAG_GHOST = 0x00002000,
CHARACTER_FLAG_RENAME = 0x00004000,
CHARACTER_FLAG_UNK16 = 0x00008000,
CHARACTER_FLAG_UNK17 = 0x00010000,
CHARACTER_FLAG_UNK18 = 0x00020000,
CHARACTER_FLAG_UNK19 = 0x00040000,
CHARACTER_FLAG_UNK20 = 0x00080000,
CHARACTER_FLAG_UNK21 = 0x00100000,
CHARACTER_FLAG_UNK22 = 0x00200000,
CHARACTER_FLAG_UNK23 = 0x00400000,
CHARACTER_FLAG_UNK24 = 0x00800000,
CHARACTER_FLAG_LOCKED_BY_BILLING = 0x01000000,
CHARACTER_FLAG_DECLINED = 0x02000000,
CHARACTER_FLAG_UNK27 = 0x04000000,
CHARACTER_FLAG_UNK28 = 0x08000000,
CHARACTER_FLAG_UNK29 = 0x10000000,
CHARACTER_FLAG_UNK30 = 0x20000000,
CHARACTER_FLAG_UNK31 = 0x40000000,
CHARACTER_FLAG_UNK32 = 0x80000000
};
enum CharacterCustomizeFlags
{
CHAR_CUSTOMIZE_FLAG_NONE = 0x00000000,
CHAR_CUSTOMIZE_FLAG_CUSTOMIZE = 0x00000001, // name, gender, etc...
CHAR_CUSTOMIZE_FLAG_FACTION = 0x00010000, // name, gender, faction, etc...
CHAR_CUSTOMIZE_FLAG_RACE = 0x00100000 // name, gender, race, etc...
};
enum CharacterSlot
{
SLOT_HEAD = 0,

View File

@@ -19,6 +19,7 @@
#define AllPackets_h__
#include "AuthenticationPackets.h"
#include "CharacterPackets.h"
#include "GuildPackets.h"
#include "LFGPackets.h"
#include "NPCPackets.h"

View File

@@ -0,0 +1,211 @@
/*
* 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 "CharacterPackets.h"
#include "DBCStores.h"
#include "Field.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "World.h"
WorldPackets::Character::EnumCharactersResult::CharacterInfo::CharacterInfo(Field* fields)
{
// 0 1 2 3 4 5 6 7
// SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.skin, characters.face, characters.hairStyle,
// 8 9 10 11 12 13 14 15
// characters.hairColor, characters.facialStyle, characters.level, characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z,
// 16 17 18 19 20 21 22
// guild_member.guildid, characters.playerFlags, characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.data,
// 23 24 25
// character_banned.guid, characters.slot, character_declinedname.genitive
Guid = ObjectGuid::Create<HighGuid::Player>(fields[0].GetUInt32());
Name = fields[1].GetString();
RaceID = fields[2].GetUInt8();
ClassID = fields[3].GetUInt8();
SexID = fields[4].GetUInt8();
SkinID = fields[5].GetUInt8();
FaceID = fields[6].GetUInt8();
HairStyle = fields[7].GetUInt8();
HairColor = fields[8].GetUInt8();
FacialHair = fields[9].GetUInt8();
ExperienceLevel = fields[10].GetUInt8();
ZoneID = int32(fields[11].GetUInt16());
MapID = int32(fields[12].GetUInt16());
PreloadPos = Position(fields[13].GetFloat(), fields[14].GetFloat(), fields[15].GetFloat());
if (ObjectGuid::LowType guildId = fields[16].GetUInt32())
GuildGUID = ObjectGuid::Create<HighGuid::Guild>(guildId);
uint32 playerFlags = fields[17].GetUInt32();
uint32 atLoginFlags = fields[18].GetUInt16();
if (atLoginFlags & AT_LOGIN_RESURRECT)
playerFlags &= ~PLAYER_FLAGS_GHOST;
if (playerFlags & PLAYER_FLAGS_GHOST)
Flags |= CHARACTER_FLAG_GHOST;
if (atLoginFlags & AT_LOGIN_RENAME)
Flags |= CHARACTER_FLAG_RENAME;
if (fields[23].GetUInt32())
Flags |= CHARACTER_FLAG_LOCKED_BY_BILLING;
if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED) && !fields[22].GetString().empty())
Flags |= CHARACTER_FLAG_DECLINED;
if (atLoginFlags & AT_LOGIN_CUSTOMIZE)
Flags2 = CHAR_CUSTOMIZE_FLAG_CUSTOMIZE;
else if (atLoginFlags & AT_LOGIN_CHANGE_FACTION)
Flags2 = CHAR_CUSTOMIZE_FLAG_FACTION;
else if (atLoginFlags & AT_LOGIN_CHANGE_RACE)
Flags2 = CHAR_CUSTOMIZE_FLAG_RACE;
FirstLogin = (atLoginFlags & AT_LOGIN_FIRST) != 0;
// show pet at selection character in character list only for non-ghost character
if (!(playerFlags & PLAYER_FLAGS_GHOST) && (ClassID == CLASS_WARLOCK || ClassID == CLASS_HUNTER || ClassID == CLASS_DEATH_KNIGHT))
{
if (CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(fields[19].GetUInt32()))
{
PetCreatureDisplayID = fields[20].GetUInt32();
PetExperienceLevel = fields[21].GetUInt16();
PetCreatureFamilyID = creatureInfo->family;
}
}
Tokenizer equipment(fields[22].GetString(), ' ');
ListPosition = fields[24].GetUInt8();
for (uint8 slot = 0; slot < INVENTORY_SLOT_BAG_END; ++slot)
{
uint32 visualBase = slot * 2;
uint32 itemId = Player::GetUInt32ValueFromArray(equipment, visualBase);
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
if (!proto)
continue;
SpellItemEnchantmentEntry const* enchant = nullptr;
uint32 enchants = Player::GetUInt32ValueFromArray(equipment, visualBase + 1);
for (uint8 enchantSlot = PERM_ENCHANTMENT_SLOT; enchantSlot <= TEMP_ENCHANTMENT_SLOT; ++enchantSlot)
{
// values stored in 2 uint16
uint32 enchantId = 0x0000FFFF & (enchants >> enchantSlot * 16);
if (!enchantId)
continue;
enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId);
if (enchant)
break;
}
VisualItems[slot].InvType = proto->InventoryType;
VisualItems[slot].DisplayID = proto->DisplayInfoID;
VisualItems[slot].DisplayEnchantID = enchant ? enchant->aura_id : 0;
}
}
WorldPacket const* WorldPackets::Character::EnumCharactersResult::Write()
{
_worldPacket.reserve(6 + Characters.size() * sizeof(CharacterInfo) + FactionChangeRestrictions.size() * sizeof(RestrictedFactionChangeRuleInfo));
_worldPacket.WriteBits(FactionChangeRestrictions.size(), 23);
_worldPacket.WriteBit(Success);
_worldPacket.WriteBits(Characters.size(), 17);
for (CharacterInfo const& charInfo : Characters)
{
_worldPacket.WriteBit(charInfo.Guid[3]);
_worldPacket.WriteBit(charInfo.GuildGUID[1]);
_worldPacket.WriteBit(charInfo.GuildGUID[7]);
_worldPacket.WriteBit(charInfo.GuildGUID[2]);
_worldPacket.WriteBits(charInfo.Name.length(), 7);
_worldPacket.WriteBit(charInfo.Guid[4]);
_worldPacket.WriteBit(charInfo.Guid[7]);
_worldPacket.WriteBit(charInfo.GuildGUID[3]);
_worldPacket.WriteBit(charInfo.Guid[5]);
_worldPacket.WriteBit(charInfo.GuildGUID[6]);
_worldPacket.WriteBit(charInfo.Guid[1]);
_worldPacket.WriteBit(charInfo.GuildGUID[5]);
_worldPacket.WriteBit(charInfo.GuildGUID[4]);
_worldPacket.WriteBit(charInfo.FirstLogin);
_worldPacket.WriteBit(charInfo.Guid[0]);
_worldPacket.WriteBit(charInfo.Guid[2]);
_worldPacket.WriteBit(charInfo.Guid[6]);
_worldPacket.WriteBit(charInfo.GuildGUID[0]);
}
_worldPacket.FlushBits();
for (CharacterInfo const& charInfo : Characters)
{
_worldPacket << uint8(charInfo.ClassID);
for (WorldPackets::Character::EnumCharactersResult::CharacterInfo::VisualItemInfo const& visualItem : charInfo.VisualItems)
{
_worldPacket << uint8(visualItem.InvType);
_worldPacket << uint32(visualItem.DisplayID);
_worldPacket << uint32(visualItem.DisplayEnchantID);
}
_worldPacket << uint32(charInfo.PetCreatureFamilyID);
_worldPacket.WriteByteSeq(charInfo.GuildGUID[2]);
_worldPacket << uint8(charInfo.ListPosition);
_worldPacket << uint8(charInfo.HairStyle);
_worldPacket.WriteByteSeq(charInfo.GuildGUID[3]);
_worldPacket << uint32(charInfo.PetCreatureDisplayID);
_worldPacket << uint32(charInfo.Flags);
_worldPacket << uint8(charInfo.HairColor);
_worldPacket.WriteByteSeq(charInfo.Guid[4]);
_worldPacket << int32(charInfo.MapID);
_worldPacket.WriteByteSeq(charInfo.GuildGUID[5]);
_worldPacket << float(charInfo.PreloadPos.GetPositionZ());
_worldPacket.WriteByteSeq(charInfo.GuildGUID[6]);
_worldPacket << uint32(charInfo.PetExperienceLevel);
_worldPacket.WriteByteSeq(charInfo.Guid[3]);
_worldPacket << float(charInfo.PreloadPos.GetPositionY());
_worldPacket << uint32(charInfo.Flags2);
_worldPacket << uint8(charInfo.FacialHair);
_worldPacket.WriteByteSeq(charInfo.Guid[7]);
_worldPacket << uint8(charInfo.SexID);
_worldPacket.WriteString(charInfo.Name);
_worldPacket << uint8(charInfo.FaceID);
_worldPacket.WriteByteSeq(charInfo.Guid[0]);
_worldPacket.WriteByteSeq(charInfo.Guid[2]);
_worldPacket.WriteByteSeq(charInfo.GuildGUID[1]);
_worldPacket.WriteByteSeq(charInfo.GuildGUID[7]);
_worldPacket << float(charInfo.PreloadPos.GetPositionX());
_worldPacket << uint8(charInfo.SkinID);
_worldPacket << uint8(charInfo.RaceID);
_worldPacket << uint8(charInfo.ExperienceLevel);
_worldPacket.WriteByteSeq(charInfo.Guid[6]);
_worldPacket.WriteByteSeq(charInfo.GuildGUID[4]);
_worldPacket.WriteByteSeq(charInfo.GuildGUID[0]);
_worldPacket.WriteByteSeq(charInfo.Guid[5]);
_worldPacket.WriteByteSeq(charInfo.Guid[1]);
_worldPacket << int32(charInfo.ZoneID);
}
for (RestrictedFactionChangeRuleInfo const& rule : FactionChangeRestrictions)
{
_worldPacket << int32(rule.Mask);
_worldPacket << uint8(rule.Race);
}
return &_worldPacket;
}

View File

@@ -0,0 +1,107 @@
/*
* 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 MiscPackets_h__
#define MiscPackets_h__
#include "Packet.h"
#include "ObjectGuid.h"
#include "Position.h"
#include <array>
class Field;
namespace WorldPackets
{
namespace Character
{
class EnumCharacters final : public ClientPacket
{
public:
EnumCharacters(WorldPacket&& packet) : ClientPacket(CMSG_ENUM_CHARACTERS, std::move(packet)) { }
void Read() override { }
};
class EnumCharactersResult final : public ServerPacket
{
public:
struct CharacterInfo
{
/**
* @fn void WorldPackets::Character::EnumCharactersResult::CharacterInfo::CharacterInfo(Field* fields);
*
* @brief Initialize the struct with values from QueryResult
*
* @param fields Field set of CharacterDatabaseStatements::CHAR_SEL_ENUM
*/
CharacterInfo(Field* fields);
struct VisualItemInfo
{
uint32 DisplayID = 0;
uint32 DisplayEnchantID = 0;
uint8 InvType = 0;
};
Position PreloadPos;
ObjectGuid Guid;
ObjectGuid GuildGUID;
uint32 Flags = 0; ///< Character flag @see enum CharacterFlags
uint32 Flags2 = 0; ///< Character customization flags @see enum CharacterCustomizeFlags
int32 MapID = 0;
uint32 PetCreatureDisplayID = 0;
uint32 PetCreatureFamilyID = 0;
uint32 PetExperienceLevel = 0;
int32 ZoneID = 0;
uint8 ClassID = 0;
uint8 ExperienceLevel = 0;
uint8 FaceID = 0;
uint8 FacialHair = 0;
uint8 HairColor = 0;
uint8 HairStyle = 0;
uint8 ListPosition = 0; ///< Order of the characters in list
uint8 RaceID = 0;
uint8 SexID = 0;
uint8 SkinID = 0;
bool FirstLogin = false;
std::string Name;
std::array<VisualItemInfo, 23> VisualItems = { };
};
struct RestrictedFactionChangeRuleInfo
{
RestrictedFactionChangeRuleInfo(int32 mask, uint8 race)
: Mask(mask), Race(race) { }
int32 Mask = 0;
uint8 Race = 0;
};
EnumCharactersResult() : ServerPacket(SMSG_ENUM_CHARACTERS_RESULT) { }
WorldPacket const* Write() override;
bool Success = false; ///<
std::vector<CharacterInfo> Characters; ///< all characters on the list
std::vector<RestrictedFactionChangeRuleInfo> FactionChangeRestrictions; ///< @todo: research
};
}
}
#endif // CharacterPackets_h__

View File

@@ -256,7 +256,6 @@ void OpcodeTable::Initialize()
DEFINE_HANDLER(CMSG_CHAR_CREATE, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharCreateOpcode );
DEFINE_HANDLER(CMSG_CHAR_CUSTOMIZE, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharCustomize );
DEFINE_HANDLER(CMSG_CHAR_DELETE, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharDeleteOpcode );
DEFINE_HANDLER(CMSG_CHAR_ENUM, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharEnumOpcode );
DEFINE_HANDLER(CMSG_CHAR_FACTION_CHANGE, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharFactionOrRaceChange );
DEFINE_HANDLER(CMSG_CHAR_RACE_CHANGE, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharFactionOrRaceChange );
DEFINE_HANDLER(CMSG_CHAR_RENAME, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharRenameOpcode );
@@ -294,6 +293,7 @@ void OpcodeTable::Initialize()
DEFINE_HANDLER(CMSG_EMOTE, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleEmoteOpcode );
DEFINE_HANDLER(CMSG_ENABLETAXI, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleTaxiQueryAvailableNodes );
DEFINE_HANDLER(CMSG_ENABLE_NAGLE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_EarlyProccess );
DEFINE_HANDLER(CMSG_ENUM_CHARACTERS, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleCharEnumOpcode );
DEFINE_HANDLER(CMSG_EQUIPMENT_SET_DELETE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleEquipmentSetDelete );
DEFINE_HANDLER(CMSG_EQUIPMENT_SET_SAVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleEquipmentSetSave );
DEFINE_HANDLER(CMSG_EQUIPMENT_SET_USE, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleEquipmentSetUse );
@@ -757,7 +757,6 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CREATE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CUSTOMIZE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_DELETE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_ENUM, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_FACTION_CHANGE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_RENAME, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_IGNORED_ACCOUNT_MUTED, STATUS_NEVER, CONNECTION_TYPE_REALM);
@@ -829,6 +828,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_EMOTE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENABLE_BARBER_SHOP, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENCHANTMENTLOG, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENUM_CHARACTERS_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENVIRONMENTALDAMAGELOG, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_EQUIPMENT_SET_LIST, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_EQUIPMENT_SET_SAVED, STATUS_NEVER, CONNECTION_TYPE_REALM);

View File

@@ -149,7 +149,6 @@ enum OpcodeClient : uint16
CMSG_CHAR_CREATE = 0x4A36,
CMSG_CHAR_CUSTOMIZE = 0x2C34,
CMSG_CHAR_DELETE = 0x6425,
CMSG_CHAR_ENUM = 0x0502,
CMSG_CHAR_FACTION_CHANGE = 0x2735,
CMSG_CHAR_RACE_CHANGE = 0x0D24,
CMSG_CHAR_RENAME = 0x2327,
@@ -188,6 +187,7 @@ enum OpcodeClient : uint16
CMSG_EMOTE = 0x4C26,
CMSG_ENABLETAXI = 0x0C16,
CMSG_ENABLE_NAGLE = 0x4449,
CMSG_ENUM_CHARACTERS = 0x0502,
CMSG_EQUIPMENT_SET_DELETE = 0x4D07,
CMSG_EQUIPMENT_SET_SAVE = 0x4F27,
CMSG_EQUIPMENT_SET_USE = 0x0417,
@@ -691,7 +691,6 @@ enum OpcodeServer
SMSG_CHAR_CREATE = 0x2D05,
SMSG_CHAR_CUSTOMIZE = 0x4F16,
SMSG_CHAR_DELETE = 0x0304,
SMSG_CHAR_ENUM = 0x10B0,
SMSG_CHAR_FACTION_CHANGE = 0x4C06,
SMSG_CHAR_RENAME = 0x2024,
SMSG_CHAT_IGNORED_ACCOUNT_MUTED = 0x15A4,
@@ -768,6 +767,7 @@ enum OpcodeServer
SMSG_EMOTE = 0x0A34,
SMSG_ENABLE_BARBER_SHOP = 0x2D16,
SMSG_ENCHANTMENTLOG = 0x6035,
SMSG_ENUM_CHARACTERS_RESULT = 0x10B0,
SMSG_ENVIRONMENTALDAMAGELOG = 0x6C05,
SMSG_EQUIPMENT_SET_LIST = 0x2E04,
SMSG_EQUIPMENT_SET_SAVED = 0x2216,
@@ -1431,9 +1431,6 @@ enum OpcodeMisc : uint16
COMPRESSED_OPCODE_MASK = 0x8000
};
typedef OpcodeClient OpcodeClient;
typedef OpcodeServer OpcodeServer;
/// Player state
enum SessionStatus
{
@@ -1452,7 +1449,7 @@ enum PacketProcessing
PROCESS_THREADSAFE //packet is thread-safe - process it in Map::Update()
};
class WorldSession;
class WorldPacket;
class WorldSession;
class OpcodeHandler

View File

@@ -411,8 +411,8 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
}
// some auth opcodes can be recieved before STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes
// however when we recieve CMSG_CHAR_ENUM we are surely no longer during the logout process.
if (packet->GetOpcode() == CMSG_CHAR_ENUM)
// however when we recieve CMSG_ENUM_CHARACTERS we are surely no longer during the logout process.
if (packet->GetOpcode() == CMSG_ENUM_CHARACTERS)
m_playerRecentlyLogout = false;
if (AntiDOS.EvaluateOpcode(*packet, currentTime))
@@ -1521,7 +1521,7 @@ uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) co
}
case CMSG_CHAR_CREATE: // 7 5 3 async db queries
case CMSG_CHAR_ENUM: // 22 3 2 async db queries
case CMSG_ENUM_CHARACTERS: // 22 3 2 async db queries
case CMSG_GMTICKET_CREATE: // 1 25 1 async db query
case CMSG_GMTICKET_UPDATETEXT: // 0 15 1 async db query
case CMSG_GMTICKET_DELETETICKET: // 1 25 1 async db query

View File

@@ -80,6 +80,11 @@ namespace WorldPackets
enum class ConnectToSerial : uint32;
}
namespace Character
{
class EnumCharacters;
}
namespace LFG
{
class LFGJoin;
@@ -550,13 +555,13 @@ class TC_GAME_API WorldSession
void Handle_ServerSide(WorldPacket& recvPacket); // sever side only, can't be accepted from client
void Handle_Deprecated(WorldPacket& recvPacket); // never used anymore by client
void HandleCharEnumOpcode(WorldPacket& recvPacket);
void HandleCharEnum(PreparedQueryResult result);
void HandleCharEnumOpcode(WorldPackets::Character::EnumCharacters& /*enumCharacters*/);
void HandleCharDeleteOpcode(WorldPacket& recvPacket);
void HandleCharCreateOpcode(WorldPacket& recvPacket);
void HandlePlayerLoginOpcode(WorldPacket& recvPacket);
void HandleContinuePlayerLogin();
void HandleLoadScreenOpcode(WorldPacket& recvPacket);
void HandleCharEnum(PreparedQueryResult result);
void HandlePlayerLogin(LoginQueryHolder* holder);
void HandleCharFactionOrRaceChange(WorldPacket& recvData);
void HandleCharFactionOrRaceChangeCallback(std::shared_ptr<CharacterFactionChangeInfo> factionChangeInfo, PreparedQueryResult result);