Core/NetworkIO: update SMSG_CHAR_ENUM and CMSG_PLAYER_LOGIN

This commit is contained in:
joschiwald
2014-10-31 14:47:56 +01:00
parent e9e1f5b018
commit 310c33d96f
10 changed files with 393 additions and 254 deletions
-192
View File
@@ -85,51 +85,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
@@ -1953,153 +1908,6 @@ void Player::InnEnter(time_t time, uint32 mapid, float x, float y, float z)
time_inn_enter = time;
}
bool Player::BuildEnumData(PreparedQueryResult result, ByteBuffer* dataBuffer)
{
// 0 1 2 3 4 5 6 7
// "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, "
// 8 9 10 11 12 13 14
// "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, "
// 15 16 17 18 19 20 21 22
// "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.data, character_banned.guid, characters.slot, character_declinedname.genitive"
Field* fields = result->Fetch();
ObjectGuid guid = ObjectGuid::Create<HighGuid::Player>(fields[0].GetUInt64());
std::string name = fields[1].GetString();
uint8 playerRace = fields[2].GetUInt8();
uint8 playerClass = fields[3].GetUInt8();
uint8 gender = fields[4].GetUInt8();
uint8 skin = uint8(fields[5].GetUInt32() & 0xFF);
uint8 face = uint8((fields[5].GetUInt32() >> 8) & 0xFF);
uint8 hairStyle = uint8((fields[5].GetUInt32() >> 16) & 0xFF);
uint8 hairColor = uint8((fields[5].GetUInt32() >> 24) & 0xFF);
uint8 facialHair = uint8(fields[6].GetUInt32() & 0xFF);
uint8 level = fields[7].GetUInt8();
uint32 zone = fields[8].GetUInt16();
uint32 mapId = uint32(fields[9].GetUInt16());
float x = fields[10].GetFloat();
float y = fields[11].GetFloat();
float z = fields[12].GetFloat();
uint64 guildId = fields[13].GetUInt64();
ObjectGuid guildGuid;
if (guildId)
guildGuid = ObjectGuid::Create<HighGuid::Guild>(guildId);
uint32 playerFlags = fields[14].GetUInt32();
uint32 atLoginFlags = fields[15].GetUInt16();
Tokenizer equipment(fields[19].GetString(), ' ');
uint8 slot = fields[21].GetUInt8();
uint32 charFlags = 0;
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[20].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;
uint32 petFamily = 0;
// show pet at selection character in character list only for non-ghost character
if (result && !(playerFlags & PLAYER_FLAGS_GHOST) && (playerClass == CLASS_WARLOCK || playerClass == CLASS_HUNTER || playerClass == CLASS_DEATH_KNIGHT))
{
uint32 entry = fields[16].GetUInt32();
CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(entry);
if (creatureInfo)
{
petDisplayId = fields[17].GetUInt32();
petLevel = fields[18].GetUInt16();
petFamily = creatureInfo->family;
}
}
// Packet content flags
*dataBuffer << guid;
*dataBuffer << uint8(slot); // List order
*dataBuffer << uint8(playerRace); // Race
*dataBuffer << uint8(playerClass); // Class
*dataBuffer << uint8(gender); // Gender
*dataBuffer << uint8(skin); // Skin
*dataBuffer << uint8(face); // Face
*dataBuffer << uint8(hairStyle); // Hair style
*dataBuffer << uint8(hairColor); // Hair color
*dataBuffer << uint8(facialHair); // Facial hair
*dataBuffer << uint8(level); // Level
*dataBuffer << uint32(zone); // Zone ids
*dataBuffer << uint32(mapId); // Map Id
*dataBuffer << float(y); // Y
*dataBuffer << float(x); // X
*dataBuffer << float(z); // Z
*dataBuffer << guildGuid;
*dataBuffer << uint32(charFlags); // Character flag
*dataBuffer << uint32(customizationFlag); // Character customization flags
*dataBuffer << uint32(0); // Character flags 3
*dataBuffer << uint32(petDisplayId); // Pet DisplayID
*dataBuffer << uint32(petLevel); // Pet level
*dataBuffer << uint32(petFamily); // Pet family
for (int i = 0; i < 2; i++) // ProfessionIDs
*dataBuffer << uint32(0);
// Character data
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 << uint32(0);
*dataBuffer << uint32(0);
*dataBuffer << uint8(0);
continue;
}
SpellItemEnchantmentEntry const* enchant = NULL;
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 << uint32(proto->DisplayInfoID);
*dataBuffer << uint32(enchant ? enchant->aura_id : 0);
*dataBuffer << uint8(proto->InventoryType);
}
dataBuffer->WriteBits(uint32(name.length()), 6);
dataBuffer->WriteBit(atLoginFlags & AT_LOGIN_FIRST);
dataBuffer->WriteBit(0); // BoostInProgress
dataBuffer->WriteString(name); // Name
return true;
}
void Player::ToggleAFK()
{
ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK);
-2
View File
@@ -1293,8 +1293,6 @@ class Player : public Unit, public GridObject<Player>
void Update(uint32 time) override;
static bool BuildEnumData(PreparedQueryResult result, ByteBuffer* dataBuffer);
void SetInWater(bool apply);
bool IsInWater() const override { return m_isInWater; }
+26 -51
View File
@@ -21,6 +21,7 @@
#include "ArenaTeamMgr.h"
#include "Battleground.h"
#include "CalendarMgr.h"
#include "CharacterPackets.h"
#include "Chat.h"
#include "Common.h"
#include "DatabaseEnv.h"
@@ -222,45 +223,35 @@ bool LoginQueryHolder::Initialize()
void WorldSession::HandleCharEnum(PreparedQueryResult result)
{
uint32 charCount = 0;
WorldPacket data(SMSG_CHAR_ENUM);
data.WriteBit(1); // Success
data.WriteBit(0); // IsDeleted (used for character undelete list)
WorldPackets::Character::CharEnumResult charEnum;
charEnum.Success = true;
charEnum.IsDeletedCharacters = false;
if (result)
{
_legitCharacters.clear();
charCount = uint32(result->GetRowCount());
data << uint32(charCount);
data << uint32(0); // FactionChangeRestrictions
data.reserve(charCount * 450); // Guessed
do
{
ObjectGuid guid = ObjectGuid::Create<HighGuid::Player>((*result)[0].GetUInt64());
Field* fields = result->Fetch();
WorldPackets::Character::CharEnumResult::CharacterInfo charInfo(fields);
TC_LOG_INFO("network", "Loading char guid %s from account %u.", guid.ToString().c_str(), GetAccountId());
TC_LOG_INFO("network", "Loading char guid %s from account %u.", charInfo.Guid.ToString().c_str(), GetAccountId());
Player::BuildEnumData(result, &data);
// Do not allow locked characters to login
if (!(charInfo.Flags & (CHARACTER_FLAG_LOCKED_FOR_TRANSFER | CHARACTER_FLAG_LOCKED_BY_BILLING)))
_legitCharacters.insert(charInfo.Guid);
// Do not allow banned characters to log in
if (!(*result)[20].GetUInt64())
_legitCharacters.insert(guid);
if (!sWorld->HasCharacterNameData(charInfo.Guid)) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet.
sWorld->AddCharacterNameData(charInfo.Guid, charInfo.Name, charInfo.Sex, charInfo.Race, charInfo.Class, charInfo.Level);
if (!sWorld->HasCharacterNameData(guid)) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet.
sWorld->AddCharacterNameData(guid, (*result)[1].GetString(), (*result)[4].GetUInt8(), (*result)[2].GetUInt8(), (*result)[3].GetUInt8(), (*result)[7].GetUInt8());
} while (result->NextRow());
}
else
{
data << uint32(0); // CharCount
data << uint32(0); // FactionChangeRestrictions
charEnum.Characters.emplace_back(charInfo);
}
while (result->NextRow());
}
SendPacket(&data);
charEnum.Write();
SendPacket(&charEnum.GetWorldPacket());
}
void WorldSession::HandleCharEnumOpcode(WorldPacket& /*recvData*/)
@@ -763,38 +754,23 @@ void WorldSession::HandlePlayerLoginOpcode(WorldPacket& recvData)
return;
}
m_playerLoading = true;
ObjectGuid playerGuid;
TC_LOG_DEBUG("network", "WORLD: Recvd Player Logon Message");
playerGuid[2] = recvData.ReadBit();
playerGuid[3] = recvData.ReadBit();
playerGuid[0] = recvData.ReadBit();
playerGuid[6] = recvData.ReadBit();
playerGuid[4] = recvData.ReadBit();
playerGuid[5] = recvData.ReadBit();
playerGuid[1] = recvData.ReadBit();
playerGuid[7] = recvData.ReadBit();
recvData.ReadByteSeq(playerGuid[2]);
recvData.ReadByteSeq(playerGuid[7]);
recvData.ReadByteSeq(playerGuid[0]);
recvData.ReadByteSeq(playerGuid[3]);
recvData.ReadByteSeq(playerGuid[5]);
recvData.ReadByteSeq(playerGuid[6]);
recvData.ReadByteSeq(playerGuid[1]);
recvData.ReadByteSeq(playerGuid[4]);
m_playerLoading = true;
TC_LOG_DEBUG("network", "Character %s logging in", playerGuid.ToString().c_str());
WorldPackets::Character::PlayerLogin playerLogin(std::move(recvData));
playerLogin.Read();
if (!IsLegitCharacterForAccount(playerGuid))
TC_LOG_DEBUG("network", "Character %s logging in", playerLogin.Guid.ToString().c_str());
if (!IsLegitCharacterForAccount(playerLogin.Guid))
{
TC_LOG_ERROR("network", "Account (%u) can't login with that character (%s).", GetAccountId(), playerGuid.ToString().c_str());
TC_LOG_ERROR("network", "Account (%u) can't login with that character (%s).", GetAccountId(), playerLogin.Guid.ToString().c_str());
KickPlayer();
return;
}
LoginQueryHolder *holder = new LoginQueryHolder(GetAccountId(), playerGuid);
LoginQueryHolder* holder = new LoginQueryHolder(GetAccountId(), playerLogin.Guid);
if (!holder->Initialize())
{
delete holder; // delete all unprocessed queries
@@ -1083,9 +1059,8 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
if (pCurrChar->IsGameMaster())
SendNotification(LANG_GM_ON);
std::string IP_str = GetRemoteAddress();
TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Login Character: [%s] (%s) Level: %d",
GetAccountId(), IP_str.c_str(), pCurrChar->GetName().c_str(), pCurrChar->GetGUID().ToString().c_str(), pCurrChar->getLevel());
GetAccountId(), GetRemoteAddress().c_str(), pCurrChar->GetName().c_str(), pCurrChar->GetGUID().ToString().c_str(), pCurrChar->getLevel());
if (!pCurrChar->IsStandState() && !pCurrChar->HasUnitState(UNIT_STATE_STUNNED))
pCurrChar->SetStandState(UNIT_STAND_STATE_STAND);
+47 -2
View File
@@ -292,7 +292,7 @@ enum ItemQualities
ITEM_QUALITY_EPIC = 4, // PURPLE
ITEM_QUALITY_LEGENDARY = 5, // ORANGE
ITEM_QUALITY_ARTIFACT = 6, // LIGHT YELLOW
ITEM_QUALITY_HEIRLOOM = 7
ITEM_QUALITY_HEIRLOOM = 7
};
#define MAX_ITEM_QUALITY 8
@@ -853,6 +853,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,
@@ -3669,7 +3714,7 @@ inline uint8 ClassByQuestSort(int32 QuestSort)
enum SkillType
{
SKILL_NONE = 0,
SKILL_FROST = 6,
SKILL_FIRE = 8,
SKILL_ARMS = 26,
+1 -1
View File
@@ -17,6 +17,6 @@
#include "Packet.h"
WorldPackets::ServerPacket::ServerPacket(OpcodeServer opcode, size_t initialSize = 200) : Packet(WorldPacket(opcode, initialSize))
WorldPackets::ServerPacket::ServerPacket(OpcodeServer opcode, size_t initialSize /*= 200*/) : Packet(WorldPacket(opcode, initialSize))
{
}
+3 -3
View File
@@ -33,6 +33,7 @@ namespace WorldPackets
virtual void Read() = 0;
WorldPacket& GetWorldPacket() { return _worldPacket; }
size_t GetSize() const { return _worldPacket.size(); }
protected:
WorldPacket _worldPacket;
@@ -41,11 +42,10 @@ namespace WorldPackets
class ServerPacket : public Packet
{
public:
ServerPacket(OpcodeServer opcode, size_t initialSize);
ServerPacket(OpcodeServer opcode, size_t initialSize = 200);
void Read() override final { ASSERT(!"Read not implemented for server packets."); }
size_t GetSize() const { return _worldPacket.size(); }
void Reset() { _worldPacket.clear(); }
};
@@ -58,4 +58,4 @@ namespace WorldPackets
};
}
#endif
#endif // PacketBaseWorld_h__
@@ -49,7 +49,7 @@ void WorldPackets::Auth::AuthSession::Read()
}
WorldPackets::Auth::AuthResponse::AuthResponse()
: ServerPacket(SMSG_AUTH_RESPONSE, 132)
: ServerPacket(SMSG_AUTH_RESPONSE, 132)
{
WaitInfo.HasValue = false;
SuccessInfo.HasValue = false;
@@ -15,7 +15,8 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef AuthenticationPackets_h__
#ifndef AuthenticationPacketsWorld_h__
#define AuthenticationPacketsWorld_h__
#include "Packet.h"
#include "Util.h"
@@ -134,4 +135,4 @@ namespace WorldPackets
}
}
#endif
#endif // AuthenticationPacketsWorld_h__
@@ -0,0 +1,196 @@
/*
* Copyright (C) 2008-2014 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 "CharacterPackets.h"
WorldPackets::Character::CharEnumResult::CharacterInfo::CharacterInfo(Field* fields)
{
// 0 1 2 3 4 5 6 7
// "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, "
// 8 9 10 11 12 13 14
// "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, "
// 15 16 17 18 19 20 21 22
// "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.data, character_banned.guid, characters.slot, character_declinedname.genitive"
Guid = ObjectGuid::Create<HighGuid::Player>(fields[0].GetUInt64());
Name = fields[1].GetString();
Race = fields[2].GetUInt8();
Class = fields[3].GetUInt8();
Sex = fields[4].GetUInt8();
Skin = uint8(fields[5].GetUInt32() & 0xFF);
Face = uint8((fields[5].GetUInt32() >> 8) & 0xFF);
HairStyle = uint8((fields[5].GetUInt32() >> 16) & 0xFF);
HairColor = uint8((fields[5].GetUInt32() >> 24) & 0xFF);
FacialHair = uint8(fields[6].GetUInt32() & 0xFF);
Level = fields[7].GetUInt8();
ZoneId = fields[8].GetUInt16();
MapId = fields[9].GetUInt16();
PreLoadPosition.x = fields[10].GetFloat();
PreLoadPosition.y = fields[11].GetFloat();
PreLoadPosition.z = fields[12].GetFloat();
if (uint32 guildId = fields[13].GetUInt32())
GuildGuid = ObjectGuid::Create<HighGuid::Guild>(guildId);
uint32 playerFlags = fields[14].GetUInt32();
uint32 atLoginFlags = fields[15].GetUInt16();
if (playerFlags & PLAYER_FLAGS_HIDE_HELM)
Flags |= CHARACTER_FLAG_HIDE_HELM;
if (playerFlags & PLAYER_FLAGS_HIDE_CLOAK)
Flags |= CHARACTER_FLAG_HIDE_CLOAK;
if (playerFlags & PLAYER_FLAGS_GHOST)
Flags |= CHARACTER_FLAG_GHOST;
if (atLoginFlags & AT_LOGIN_RENAME)
Flags |= CHARACTER_FLAG_RENAME;
if (fields[20].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)
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;
Flags3 = 0;
FirstLogin = (atLoginFlags & AT_LOGIN_FIRST) != 0;
// show pet at selection character in character list only for non-ghost character
if (!(playerFlags & PLAYER_FLAGS_GHOST) && (Class == CLASS_WARLOCK || Class == CLASS_HUNTER || Class == CLASS_DEATH_KNIGHT))
{
if (CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(fields[16].GetUInt32()))
{
Pet.CreatureDisplayId = fields[17].GetUInt32();
Pet.Level = fields[18].GetUInt16();
Pet.CreatureFamily = creatureInfo->family;
}
}
BoostInProgress = false;
ProfessionIds[0] = 0;
ProfessionIds[1] = 0;
Tokenizer equipment(fields[19].GetString(), ' ');
ListPosition = fields[21].GetUInt8();
for (uint8 slot = 0; slot < INVENTORY_SLOT_BAG_END; ++slot)
{
uint32 visualBase = slot * 2;
uint32 itemId = Player::GetUInt32ValueFromArray(equipment, visualBase);
if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId))
{
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;
if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId))
{
VisualItems[slot].DisplayEnchantId = enchant->aura_id;
break;
}
}
VisualItems[slot].DisplayId = proto->DisplayInfoID;
VisualItems[slot].InventoryType = uint8(proto->InventoryType);
}
}
}
WorldPackets::Character::CharEnumResult::CharEnumResult()
: ServerPacket(SMSG_CHAR_ENUM) { }
void WorldPackets::Character::CharEnumResult::Write()
{
_worldPacket.reserve(9 + Characters.size() * sizeof(CharacterInfo) + FactionChangeRestrictions.size() * sizeof(RestrictedFactionChangeRuleInfo));
_worldPacket.WriteBit(Success);
_worldPacket.WriteBit(IsDeletedCharacters);
_worldPacket << uint32(Characters.size());
_worldPacket << uint32(FactionChangeRestrictions.size());
for (CharacterInfo const& charInfo : Characters)
{
_worldPacket << charInfo.Guid;
_worldPacket << uint8(charInfo.ListPosition);
_worldPacket << uint8(charInfo.Race);
_worldPacket << uint8(charInfo.Class);
_worldPacket << uint8(charInfo.Sex);
_worldPacket << uint8(charInfo.Skin);
_worldPacket << uint8(charInfo.Face);
_worldPacket << uint8(charInfo.HairStyle);
_worldPacket << uint8(charInfo.HairColor);
_worldPacket << uint8(charInfo.FacialHair);
_worldPacket << uint8(charInfo.Level);
_worldPacket << uint32(charInfo.ZoneId);
_worldPacket << uint32(charInfo.MapId);
_worldPacket << float(charInfo.PreLoadPosition.x);
_worldPacket << float(charInfo.PreLoadPosition.y);
_worldPacket << float(charInfo.PreLoadPosition.z);
_worldPacket << charInfo.GuildGuid;
_worldPacket << uint32(charInfo.Flags);
_worldPacket << uint32(charInfo.CustomizationFlag);
_worldPacket << uint32(charInfo.Flags3);
_worldPacket << uint32(charInfo.Pet.CreatureDisplayId);
_worldPacket << uint32(charInfo.Pet.Level);
_worldPacket << uint32(charInfo.Pet.CreatureFamily);
_worldPacket << uint32(charInfo.ProfessionIds[0]);
_worldPacket << uint32(charInfo.ProfessionIds[1]);
for (uint8 slot = 0; slot < INVENTORY_SLOT_BAG_END; ++slot)
{
_worldPacket << uint32(charInfo.VisualItems[slot].DisplayId);
_worldPacket << uint32(charInfo.VisualItems[slot].DisplayEnchantId);
_worldPacket << uint8(charInfo.VisualItems[slot].InventoryType);
}
_worldPacket.WriteBits(charInfo.Name.length(), 6);
_worldPacket.WriteBit(charInfo.FirstLogin);
_worldPacket.WriteBit(charInfo.BoostInProgress);
_worldPacket.WriteString(charInfo.Name);
}
for (RestrictedFactionChangeRuleInfo const& rule : FactionChangeRestrictions)
{
_worldPacket << uint32(rule.Mask);
_worldPacket << uint8(rule.Race);
}
}
WorldPackets::Character::PlayerLogin::PlayerLogin(WorldPacket&& packet)
: ClientPacket(std::move(packet))
{
ASSERT(_worldPacket.GetOpcode() == CMSG_PLAYER_LOGIN);
}
void WorldPackets::Character::PlayerLogin::Read()
{
_worldPacket >> Guid;
_worldPacket >> FarClip;
}
@@ -0,0 +1,116 @@
/*
* Copyright (C) 2008-2014 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 CharacterPackets_h__
#define CharacterPackets_h__
#include "Packet.h"
#include "Player.h"
namespace WorldPackets
{
namespace Character
{
class CharEnumResult final : public ServerPacket
{
public:
struct CharacterInfo
{
/**
* @fn void WorldPackets::Character::CharEnumResult::CharacterInfo::CharacterInfo(Field* fields);
*
* @brief Initialize the struct with values from QueryResult
*
* @param fields Field set of CharacterDatabaseStatements::CHAR_SEL_ENUM
*/
CharacterInfo(Field* fields);
ObjectGuid Guid;
std::string Name;
uint8 ListPosition = 0; ///< Order of the characters in list
uint8 Race = 0;
uint8 Class = 0;
uint8 Sex = 0;
uint8 Skin = 0;
uint8 Face = 0;
uint8 HairStyle = 0;
uint8 HairColor = 0;
uint8 FacialHair = 0;
uint8 Level = 0;
uint32 ZoneId = 0;
uint32 MapId = 0;
G3D::Vector3 PreLoadPosition;
ObjectGuid GuildGuid;
uint32 Flags = 0; ///< Character flag @see enum CharacterFlags
uint32 CustomizationFlag = 0; ///< Character customization flags @see enum CharacterCustomizeFlags
uint32 Flags3 = 0; ///< Character flags 3 @todo research
bool FirstLogin = false;
struct PetInfo
{
uint32 CreatureDisplayId = 0; ///< PetCreatureDisplayID
uint32 Level = 0; ///< PetExperienceLevel
uint32 CreatureFamily = 0; ///< PetCreatureFamilyID
} Pet;
bool BoostInProgress = false; ///< @todo
uint32 ProfessionIds[2]; ///< @todo
struct VisualItemInfo
{
uint32 DisplayId = 0;
uint32 DisplayEnchantId = 0;
uint8 InventoryType = 0;
};
VisualItemInfo VisualItems[INVENTORY_SLOT_BAG_END];
};
struct RestrictedFactionChangeRuleInfo
{
RestrictedFactionChangeRuleInfo(uint32 mask, uint8 race)
: Mask(mask), Race(race) { }
uint32 Mask = 0;
uint8 Race = 0;
};
CharEnumResult();
void Write() override;
bool Success = false; ///<
bool IsDeletedCharacters = false; ///< used for character undelete list
std::list<CharacterInfo> Characters; ///< all characters on the list
std::list<RestrictedFactionChangeRuleInfo> FactionChangeRestrictions; ///< @todo: research
};
class PlayerLogin final : public ClientPacket
{
public:
PlayerLogin(WorldPacket&& packet);
void Read() override;
ObjectGuid Guid; ///< Guid of the player that is logging in
float FarClip = 0.0f; ///< Visibility distance (for terrain)
};
}
}
#endif // CharacterPackets_h__