aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Handlers/CharacterHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Handlers/CharacterHandler.cpp')
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp364
1 files changed, 208 insertions, 156 deletions
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index 49283ac0c26..9b4b8f41f97 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -31,6 +31,7 @@
#include "Chat.h"
#include "ClientConfigPackets.h"
#include "Common.h"
+#include "Containers.h"
#include "DatabaseEnv.h"
#include "DB2Stores.h"
#include "EquipmentSetPackets.h"
@@ -88,6 +89,10 @@ bool LoginQueryHolder::Initialize()
stmt->setUInt64(0, lowGuid);
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_FROM, stmt);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_CUSTOMIZATIONS);
+ stmt->setUInt64(0, lowGuid);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CUSTOMIZATIONS, stmt);
+
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GROUP_MEMBER);
stmt->setUInt64(0, lowGuid);
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GROUP, stmt);
@@ -307,16 +312,78 @@ bool LoginQueryHolder::Initialize()
return res;
}
-void WorldSession::HandleCharEnum(PreparedQueryResult result)
+class EnumCharactersQueryHolder : public CharacterDatabaseQueryHolder
+{
+public:
+ enum
+ {
+ CHARACTERS,
+ CUSTOMIZATIONS,
+
+ MAX
+ };
+
+ EnumCharactersQueryHolder()
+ {
+ SetSize(MAX);
+ }
+
+ bool Initialize(uint32 accountId, bool withDeclinedNames, bool isDeletedCharacters)
+ {
+ _isDeletedCharacters = isDeletedCharacters;
+
+ constexpr CharacterDatabaseStatements statements[2][3] =
+ {
+ { CHAR_SEL_ENUM, CHAR_SEL_ENUM_DECLINED_NAME, CHAR_SEL_ENUM_CUSTOMIZATIONS },
+ { CHAR_SEL_UNDELETE_ENUM, CHAR_SEL_UNDELETE_ENUM_DECLINED_NAME, CHAR_SEL_UNDELETE_ENUM_CUSTOMIZATIONS }
+ };
+
+ bool result = true;
+ CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(statements[isDeletedCharacters ? 1 : 0][withDeclinedNames ? 1 : 0]);
+ stmt->setUInt8(0, PET_SAVE_AS_CURRENT);
+ stmt->setUInt32(1, accountId);
+ result &= SetPreparedQuery(CHARACTERS, stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(statements[isDeletedCharacters ? 1 : 0][2]);
+ stmt->setUInt32(0, accountId);
+ result &= SetPreparedQuery(CUSTOMIZATIONS, stmt);
+
+ return result;
+ }
+
+ bool IsDeletedCharacters() const { return _isDeletedCharacters; }
+
+private:
+ bool _isDeletedCharacters = false;
+};
+
+void WorldSession::HandleCharEnum(CharacterDatabaseQueryHolder* holder)
{
WorldPackets::Character::EnumCharactersResult charEnum;
charEnum.Success = true;
- charEnum.IsDeletedCharacters = false;
+ charEnum.IsDeletedCharacters = static_cast<EnumCharactersQueryHolder*>(holder)->IsDeletedCharacters();
charEnum.DisabledClassesMask = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK);
- _legitCharacters.clear();
+ if (!charEnum.IsDeletedCharacters)
+ _legitCharacters.clear();
- if (result)
+ std::unordered_map<ObjectGuid::LowType, std::vector<UF::ChrCustomizationChoice>> customizations;
+ if (PreparedQueryResult customizationsResult = holder->GetPreparedResult(EnumCharactersQueryHolder::CUSTOMIZATIONS))
+ {
+ do
+ {
+ Field* fields = customizationsResult->Fetch();
+ std::vector<UF::ChrCustomizationChoice>& customizationsForCharacter = customizations[fields[0].GetUInt64()];
+
+ customizationsForCharacter.emplace_back();
+ UF::ChrCustomizationChoice& choice = customizationsForCharacter.back();
+ choice.ChrCustomizationOptionID = fields[1].GetUInt32();
+ choice.ChrCustomizationChoiceID = fields[2].GetUInt32();
+
+ } while (customizationsResult->NextRow());
+ }
+
+ if (PreparedQueryResult result = holder->GetPreparedResult(EnumCharactersQueryHolder::CHARACTERS))
{
do
{
@@ -324,32 +391,33 @@ void WorldSession::HandleCharEnum(PreparedQueryResult result)
WorldPackets::Character::EnumCharactersResult::CharacterInfo& charInfo = charEnum.Characters.back();
+ if (std::vector<UF::ChrCustomizationChoice>* customizationsForChar = Trinity::Containers::MapGetValuePtr(customizations, charInfo.Guid.GetCounter()))
+ charInfo.Customizations = std::move(*customizationsForChar);
+
TC_LOG_INFO("network", "Loading char guid %s from account %u.", charInfo.Guid.ToString().c_str(), GetAccountId());
- if (!Player::ValidateAppearance(charInfo.RaceID, charInfo.ClassID, charInfo.SexID, charInfo.HairStyle, charInfo.HairColor, charInfo.FaceID, charInfo.FacialHair, charInfo.SkinID, charInfo.CustomDisplay))
+ if (!charEnum.IsDeletedCharacters)
{
- TC_LOG_ERROR("entities.player.loading", "Player %s has wrong Appearance values (Hair/Skin/Color), forcing recustomize", charInfo.Guid.ToString().c_str());
+ if (!ValidateAppearance(Races(charInfo.RaceID), Classes(charInfo.ClassID), Gender(charInfo.SexID), MakeChrCustomizationChoiceRange(charInfo.Customizations)))
+ {
+ TC_LOG_ERROR("entities.player.loading", "Player %s has wrong Appearance values (Hair/Skin/Color), forcing recustomize", charInfo.Guid.ToString().c_str());
- // 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;
+ charInfo.Customizations.clear();
- if (!(charInfo.Flags2 == CHAR_CUSTOMIZE_FLAG_CUSTOMIZE))
- {
- CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG);
- stmt->setUInt16(0, uint16(AT_LOGIN_CUSTOMIZE));
- stmt->setUInt64(1, charInfo.Guid.GetCounter());
- CharacterDatabase.Execute(stmt);
- charInfo.Flags2 = CHAR_CUSTOMIZE_FLAG_CUSTOMIZE;
+ if (!(charInfo.Flags2 == CHAR_CUSTOMIZE_FLAG_CUSTOMIZE))
+ {
+ CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG);
+ stmt->setUInt16(0, uint16(AT_LOGIN_CUSTOMIZE));
+ stmt->setUInt64(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);
+ // 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, false);
@@ -370,6 +438,8 @@ void WorldSession::HandleCharEnum(PreparedQueryResult result)
}
SendPacket(charEnum.Write());
+
+ delete holder;
}
void WorldSession::HandleCharEnumOpcode(WorldPackets::Character::EnumCharacters& /*enumCharacters*/)
@@ -379,58 +449,123 @@ void WorldSession::HandleCharEnumOpcode(WorldPackets::Character::EnumCharacters&
CharacterDatabase.Execute(stmt);
/// get all the data necessary for loading all characters (along with their pets) on the account
+ EnumCharactersQueryHolder* holder = new EnumCharactersQueryHolder();
+ if (!holder->Initialize(GetAccountId(), sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED), false))
+ {
+ HandleCharEnum(holder);
+ return;
+ }
- if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED))
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ENUM_DECLINED_NAME);
- else
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ENUM);
+ _charEnumCallback = CharacterDatabase.DelayQueryHolder(holder);
+}
- stmt->setUInt8(0, PET_SAVE_AS_CURRENT);
- stmt->setUInt32(1, GetAccountId());
+void WorldSession::HandleCharUndeleteEnumOpcode(WorldPackets::Character::EnumCharacters& /*enumCharacters*/)
+{
+ /// get all the data necessary for loading all undeleted characters (along with their pets) on the account
+ EnumCharactersQueryHolder* holder = new EnumCharactersQueryHolder();
+ if (!holder->Initialize(GetAccountId(), sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED), true))
+ {
+ HandleCharEnum(holder);
+ return;
+ }
- _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleCharEnum, this, std::placeholders::_1)));
+ _charEnumCallback = CharacterDatabase.DelayQueryHolder(holder);
}
-void WorldSession::HandleCharUndeleteEnum(PreparedQueryResult result)
+bool WorldSession::MeetsChrCustomizationReq(ChrCustomizationReqEntry const* req, Classes playerClass,
+ bool checkRequiredDependentChoices, Trinity::IteratorPair<UF::ChrCustomizationChoice const*> selectedChoices) const
{
- WorldPackets::Character::EnumCharactersResult charEnum;
- charEnum.Success = true;
- charEnum.IsDeletedCharacters = true;
- charEnum.DisabledClassesMask = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK);
+ if (!req->GetFlags().HasFlag(ChrCustomizationReqFlag::HasRequirements))
+ return true;
- if (result)
+ if (req->ClassMask && !(req->ClassMask & (1 << (playerClass - 1))))
+ return false;
+
+ if (req->AchievementID /*&& !HasAchieved(req->AchievementID)*/)
+ return false;
+
+ if (req->ItemModifiedAppearanceID && !GetCollectionMgr()->HasItemAppearance(req->ItemModifiedAppearanceID).first)
+ return false;
+
+ if (checkRequiredDependentChoices)
{
- do
+ if (std::unordered_map<uint32, std::vector<uint32>> const* requiredChoices = sDB2Manager.GetRequiredCustomizationChoices(req->ID))
{
- Field* fields = result->Fetch();
- WorldPackets::Character::EnumCharactersResult::CharacterInfo charInfo(fields);
-
- TC_LOG_INFO("network", "Loading undeleted char guid %s from account %u.", charInfo.Guid.ToString().c_str(), GetAccountId());
+ for (std::pair<uint32 const /*chrCustomizationOptionId*/, std::vector<uint32>> const& requiredChoicesForOption : *requiredChoices)
+ {
+ bool hasRequiredChoiceForOption = false;
+ for (uint32 requiredChoice : requiredChoicesForOption.second)
+ {
+ auto choiceItr = std::find_if(selectedChoices.begin(), selectedChoices.end(), [requiredChoice](UF::ChrCustomizationChoice const& choice)
+ {
+ return choice.ChrCustomizationChoiceID == requiredChoice;
+ });
- 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, true);
+ if (choiceItr != selectedChoices.end())
+ {
+ hasRequiredChoiceForOption = true;
+ break;
+ }
+ }
- charEnum.Characters.emplace_back(charInfo);
+ if (!hasRequiredChoiceForOption)
+ return false;
+ }
}
- while (result->NextRow());
}
- SendPacket(charEnum.Write());
+ return true;
}
-void WorldSession::HandleCharUndeleteEnumOpcode(WorldPackets::Character::EnumCharacters& /*enumCharacters*/)
+bool WorldSession::ValidateAppearance(Races race, Classes playerClass, Gender gender, Trinity::IteratorPair<UF::ChrCustomizationChoice const*> customizations)
{
- /// get all the data necessary for loading all undeleted characters (along with their pets) on the account
- CharacterDatabasePreparedStatement* stmt = nullptr;
- if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED))
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_UNDELETE_ENUM_DECLINED_NAME);
- else
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_UNDELETE_ENUM);
+ std::vector<ChrCustomizationOptionEntry const*> const* options = sDB2Manager.GetCustomiztionOptions(race, gender);
+ if (!options)
+ return false;
+
+ uint32 previousOption = 0;
+
+ for (UF::ChrCustomizationChoice playerChoice : customizations)
+ {
+ // check uniqueness of options
+ if (playerChoice.ChrCustomizationOptionID == previousOption)
+ return false;
+
+ previousOption = playerChoice.ChrCustomizationOptionID;
+
+ // check if we can use this option
+ auto customizationOptionDataItr = std::find_if(options->begin(), options->end(), [&](ChrCustomizationOptionEntry const* option)
+ {
+ return option->ID == playerChoice.ChrCustomizationOptionID;
+ });
- stmt->setUInt8(0, PET_SAVE_AS_CURRENT);
- stmt->setUInt32(1, GetAccountId());
+ // option not found for race/gender combination
+ if (customizationOptionDataItr == options->end())
+ return false;
- _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleCharUndeleteEnum, this, std::placeholders::_1)));
+ if (ChrCustomizationReqEntry const* req = sChrCustomizationReqStore.LookupEntry((*customizationOptionDataItr)->ChrCustomizationReqID))
+ if (!MeetsChrCustomizationReq(req, playerClass, false, customizations))
+ return false;
+
+ std::vector<ChrCustomizationChoiceEntry const*> const* choicesForOption = sDB2Manager.GetCustomiztionChoices(playerChoice.ChrCustomizationOptionID);
+ if (!choicesForOption)
+ return false;
+
+ auto customizationChoiceDataItr = std::find_if(choicesForOption->begin(), choicesForOption->end(), [&](ChrCustomizationChoiceEntry const* choice)
+ {
+ return choice->ID == playerChoice.ChrCustomizationChoiceID;
+ });
+
+ // choice not found for option
+ if (customizationChoiceDataItr == choicesForOption->end())
+ return false;
+
+ if (ChrCustomizationReqEntry const* req = sChrCustomizationReqStore.LookupEntry((*customizationChoiceDataItr)->ChrCustomizationReqID))
+ if (!MeetsChrCustomizationReq(req, playerClass, true, customizations))
+ return false;
+ }
+
+ return true;
}
void WorldSession::HandleCharCreateOpcode(WorldPackets::Character::CreateCharacter& charCreate)
@@ -673,19 +808,6 @@ void WorldSession::HandleCharCreateOpcode(WorldPackets::Character::CreateCharact
if (checkDemonHunterReqs)
{
- uint8 accClass = field[2].GetUInt8();
- if (accClass == CLASS_DEMON_HUNTER)
- {
- if (freeDemonHunterSlots > 0)
- --freeDemonHunterSlots;
-
- if (freeDemonHunterSlots == 0)
- {
- SendCharCreate(CHAR_CREATE_FAILED);
- return;
- }
- }
-
if (!hasDemonHunterReqLevel)
{
uint8 accLevel = field[0].GetUInt8();
@@ -746,7 +868,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPackets::Character::CreateCharact
{
TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Create Character: %s %s", GetAccountId(), GetRemoteAddress().c_str(), newChar->GetName().c_str(), newChar->GetGUID().ToString().c_str());
sScriptMgr->OnPlayerCreate(newChar.get());
- sCharacterCache->AddCharacterCacheEntry(newChar->GetGUID(), GetAccountId(), newChar->GetName(), newChar->m_playerData->NativeSex, newChar->getRace(), newChar->getClass(), newChar->getLevel(), false);
+ sCharacterCache->AddCharacterCacheEntry(newChar->GetGUID(), GetAccountId(), newChar->GetName(), newChar->GetNativeSex(), newChar->getRace(), newChar->getClass(), newChar->getLevel(), false);
SendCharCreate(CHAR_CREATE_SUCCESS, newChar->GetGUID());
}
@@ -763,7 +885,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPackets::Character::CreateCharact
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_CREATE_INFO);
stmt->setUInt32(0, GetAccountId());
- stmt->setUInt32(1, (skipCinematics == 1 || createInfo->Class == CLASS_DEMON_HUNTER) ? 12 : 1);
+ stmt->setUInt32(1, (skipCinematics == 1 || createInfo->Class == CLASS_DEMON_HUNTER) ? 1200 : 1); // 200 (max chars per realm) + 1000 (max deleted chars per realm)
queryCallback.WithPreparedCallback(std::move(finalizeCharacterCreation)).SetNextQuery(CharacterDatabase.AsyncQuery(stmt));
}));
}
@@ -1532,41 +1654,7 @@ void WorldSession::HandleSetPlayerDeclinedNames(WorldPackets::Character::SetPlay
void WorldSession::HandleAlterAppearance(WorldPackets::Character::AlterApperance& packet)
{
- BarberShopStyleEntry const* bs_hair = sBarberShopStyleStore.LookupEntry(packet.NewHairStyle);
- if (!bs_hair || bs_hair->Type != 0 || bs_hair->Race != _player->getRace() || bs_hair->Sex != _player->m_playerData->NativeSex)
- return;
-
- BarberShopStyleEntry const* bs_facialHair = sBarberShopStyleStore.LookupEntry(packet.NewFacialHair);
- if (!bs_facialHair || bs_facialHair->Type != 2 || bs_facialHair->Race != _player->getRace() || bs_facialHair->Sex != _player->m_playerData->NativeSex)
- return;
-
- BarberShopStyleEntry const* bs_skinColor = sBarberShopStyleStore.LookupEntry(packet.NewSkinColor);
- if (bs_skinColor && (bs_skinColor->Type != 3 || bs_skinColor->Race != _player->getRace() || bs_skinColor->Sex != _player->m_playerData->NativeSex))
- return;
-
- BarberShopStyleEntry const* bs_face = sBarberShopStyleStore.LookupEntry(packet.NewFace);
- if (bs_face && (bs_face->Type != 4 || bs_face->Race != _player->getRace() || bs_face->Sex != _player->m_playerData->NativeSex))
- return;
-
- std::array<BarberShopStyleEntry const*, PLAYER_CUSTOM_DISPLAY_SIZE> customDisplayEntries;
- std::array<uint8, PLAYER_CUSTOM_DISPLAY_SIZE> customDisplay;
- for (std::size_t i = 0; i < PLAYER_CUSTOM_DISPLAY_SIZE; ++i)
- {
- BarberShopStyleEntry const* bs_customDisplay = sBarberShopStyleStore.LookupEntry(packet.NewCustomDisplay[i]);
- if (bs_customDisplay && (bs_customDisplay->Type != 5 + i || bs_customDisplay->Race != _player->getRace() || bs_customDisplay->Sex != _player->m_playerData->NativeSex))
- return;
-
- customDisplayEntries[i] = bs_customDisplay;
- customDisplay[i] = bs_customDisplay ? bs_customDisplay->Data : 0;
- }
-
- if (!Player::ValidateAppearance(_player->getRace(), _player->getClass(), _player->m_playerData->NativeSex,
- bs_hair->Data,
- packet.NewHairColor,
- bs_face ? bs_face->Data : _player->m_playerData->FaceID,
- bs_facialHair->Data,
- bs_skinColor ? bs_skinColor->Data : _player->m_playerData->SkinID,
- customDisplay))
+ if (!ValidateAppearance(Races(_player->getRace()), Classes(_player->getClass()), Gender(packet.NewSex), MakeChrCustomizationChoiceRange(packet.Customizations)))
return;
GameObject* go = _player->FindNearestGameObjectOfType(GAMEOBJECT_TYPE_BARBER_CHAIR, 5.0f);
@@ -1582,12 +1670,12 @@ void WorldSession::HandleAlterAppearance(WorldPackets::Character::AlterApperance
return;
}
- uint32 cost = _player->GetBarberShopCost(bs_hair, packet.NewHairColor, bs_facialHair, bs_skinColor, bs_face, customDisplayEntries);
+ int64 cost = _player->GetBarberShopCost(MakeChrCustomizationChoiceRange(packet.Customizations));
// 0 - ok
// 1, 3 - not enough money
// 2 - you have to sit on barber chair
- if (!_player->HasEnoughMoney((uint64)cost))
+ if (!_player->HasEnoughMoney(cost))
{
SendPacket(WorldPackets::Character::BarberShopResult(WorldPackets::Character::BarberShopResult::ResultEnum::NoMoney).Write());
return;
@@ -1595,23 +1683,17 @@ void WorldSession::HandleAlterAppearance(WorldPackets::Character::AlterApperance
SendPacket(WorldPackets::Character::BarberShopResult(WorldPackets::Character::BarberShopResult::ResultEnum::Success).Write());
- _player->ModifyMoney(-int64(cost)); // it isn't free
+ _player->ModifyMoney(-cost); // it isn't free
_player->UpdateCriteria(CRITERIA_TYPE_GOLD_SPENT_AT_BARBER, cost);
- _player->SetHairStyleId(bs_hair->Data);
- _player->SetHairColorId(packet.NewHairColor);
- _player->SetFacialHairStyleId(bs_facialHair->Data);
- if (bs_skinColor)
- _player->SetSkinId(bs_skinColor->Data);
- if (bs_face)
- _player->SetFaceId(bs_face->Data);
-
- for (uint32 i = 0; i < PLAYER_CUSTOM_DISPLAY_SIZE; ++i)
- _player->SetCustomDisplayOption(i, customDisplay[i]);
+ _player->SetNativeSex(packet.NewSex);
+ _player->SetCustomizations(Trinity::Containers::MakeIteratorPair(packet.Customizations.begin(), packet.Customizations.end()));
_player->UpdateCriteria(CRITERIA_TYPE_VISIT_BARBER_SHOP, 1);
_player->SetStandState(UNIT_STAND_STATE_STAND);
+
+ sCharacterCache->UpdateCharacterGender(_player->GetGUID(), packet.NewSex);
}
void WorldSession::HandleCharCustomizeOpcode(WorldPackets::Character::CharCustomize& packet)
@@ -1642,13 +1724,12 @@ void WorldSession::HandleCharCustomizeCallback(std::shared_ptr<WorldPackets::Cha
Field* fields = result->Fetch();
std::string oldName = fields[0].GetString();
- uint8 plrRace = fields[1].GetUInt8();
- uint8 plrClass = fields[2].GetUInt8();
- uint8 plrGender = fields[3].GetUInt8();
+ Races plrRace = Races(fields[1].GetUInt8());
+ Classes plrClass = Classes(fields[2].GetUInt8());
+ Gender plrGender = Gender(fields[3].GetUInt8());
uint16 atLoginFlags = fields[4].GetUInt16();
- if (!Player::ValidateAppearance(plrRace, plrClass, plrGender, customizeInfo->HairStyleID, customizeInfo->HairColorID, customizeInfo->FaceID,
- customizeInfo->FacialHairStyleID, customizeInfo->SkinID, customizeInfo->CustomDisplay))
+ if (!ValidateAppearance(plrRace, plrClass, plrGender, MakeChrCustomizationChoiceRange(customizeInfo->Customizations)))
{
SendCharCustomize(CHAR_CREATE_ERROR, customizeInfo.get());
return;
@@ -1708,22 +1789,7 @@ void WorldSession::HandleCharCustomizeCallback(std::shared_ptr<WorldPackets::Cha
ObjectGuid::LowType lowGuid = customizeInfo->CharGUID.GetCounter();
/// Customize
- {
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GENDER_AND_APPEARANCE);
-
- stmt->setUInt8(0, customizeInfo->SexID);
- stmt->setUInt8(1, customizeInfo->SkinID);
- stmt->setUInt8(2, customizeInfo->FaceID);
- stmt->setUInt8(3, customizeInfo->HairStyleID);
- stmt->setUInt8(4, customizeInfo->HairColorID);
- stmt->setUInt8(5, customizeInfo->FacialHairStyleID);
- stmt->setUInt8(6, customizeInfo->CustomDisplay[0]);
- stmt->setUInt8(7, customizeInfo->CustomDisplay[1]);
- stmt->setUInt8(8, customizeInfo->CustomDisplay[2]);
- stmt->setUInt64(9, lowGuid);
-
- trans->Append(stmt);
- }
+ Player::SaveCustomizations(trans, lowGuid, MakeChrCustomizationChoiceRange(customizeInfo->Customizations));
/// Name Change and update atLogin flags
{
@@ -1823,7 +1889,7 @@ void WorldSession::HandleEquipmentSetSave(WorldPackets::EquipmentSet::SaveEquipm
if (!illusion->ItemVisual || !(illusion->Flags & ENCHANTMENT_COLLECTABLE))
return false;
- if (PlayerConditionEntry const* condition = sPlayerConditionStore.LookupEntry(illusion->TransmogPlayerConditionID))
+ if (PlayerConditionEntry const* condition = sPlayerConditionStore.LookupEntry(illusion->TransmogUseConditionID))
if (!sConditionMgr->IsPlayerMeetingCondition(_player, condition))
return false;
@@ -2055,21 +2121,7 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(std::shared_ptr<WorldPa
}
// Customize
- {
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GENDER_AND_APPEARANCE);
- stmt->setUInt8(0, factionChangeInfo->SexID);
- stmt->setUInt8(1, factionChangeInfo->SkinID);
- stmt->setUInt8(2, factionChangeInfo->FaceID);
- stmt->setUInt8(3, factionChangeInfo->HairStyleID);
- stmt->setUInt8(4, factionChangeInfo->HairColorID);
- stmt->setUInt8(5, factionChangeInfo->FacialHairStyleID);
- stmt->setUInt8(6, factionChangeInfo->CustomDisplay[0]);
- stmt->setUInt8(7, factionChangeInfo->CustomDisplay[1]);
- stmt->setUInt8(8, factionChangeInfo->CustomDisplay[2]);
- stmt->setUInt64(9, lowGuid);
-
- trans->Append(stmt);
- }
+ Player::SaveCustomizations(trans, lowGuid, MakeChrCustomizationChoiceRange(factionChangeInfo->Customizations));
// Race Change
{