TrinityCore
CharacterHandler.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "WorldSession.h"
19#include "AccountMgr.h"
20#include "ArenaTeam.h"
21#include "ArenaTeamMgr.h"
22#include "ArtifactPackets.h"
23#include "AuctionHousePackets.h"
25#include "Battleground.h"
26#include "BattlegroundPackets.h"
27#include "BattlePetMgr.h"
28#include "CalendarMgr.h"
29#include "CharacterCache.h"
30#include "CharacterPackets.h"
31#include "Chat.h"
32#include "Common.h"
33#include "Containers.h"
34#include "DatabaseEnv.h"
35#include "DB2Stores.h"
36#include "EquipmentSetPackets.h"
37#include "GameObject.h"
38#include "GameTime.h"
39#include "GitRevision.h"
40#include "Group.h"
41#include "GroupMgr.h"
42#include "Guild.h"
43#include "GuildMgr.h"
44#include "Item.h"
45#include "Language.h"
46#include "Log.h"
47#include "Map.h"
48#include "Metric.h"
49#include "MiscPackets.h"
50#include "MotionMaster.h"
51#include "ObjectAccessor.h"
52#include "ObjectMgr.h"
53#include "Pet.h"
54#include "Player.h"
55#include "PlayerDump.h"
56#include "QueryHolder.h"
57#include "QueryPackets.h"
58#include "Realm.h"
59#include "ReputationMgr.h"
60#include "ScriptMgr.h"
61#include "SocialMgr.h"
62#include "StringConvert.h"
63#include "SystemPackets.h"
64#include "Util.h"
65#include "World.h"
66#include <sstream>
67
69{
70 private:
73 public:
75 : m_accountId(accountId), m_guid(guid) { }
76 ObjectGuid GetGuid() const { return m_guid; }
77 uint32 GetAccountId() const { return m_accountId; }
78 bool Initialize();
79};
80
82{
84
85 bool res = true;
87
89 stmt->setUInt64(0, lowGuid);
91
92 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_CUSTOMIZATIONS);
93 stmt->setUInt64(0, lowGuid);
95
96 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GROUP_MEMBER);
97 stmt->setUInt64(0, lowGuid);
99
100 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_AURAS);
101 stmt->setUInt64(0, lowGuid);
103
104 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_AURA_EFFECTS);
105 stmt->setUInt64(0, lowGuid);
107
109 stmt->setUInt64(0, lowGuid);
111
112 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SPELL);
113 stmt->setUInt64(0, lowGuid);
115
116 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SPELL_FAVORITES);
117 stmt->setUInt64(0, lowGuid);
119
120 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUS);
121 stmt->setUInt64(0, lowGuid);
123
125 stmt->setUInt64(0, lowGuid);
127
129 stmt->setUInt64(0, lowGuid);
131
133 stmt->setUInt64(0, lowGuid);
135
136 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_DAILY);
137 stmt->setUInt64(0, lowGuid);
139
140 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_WEEKLY);
141 stmt->setUInt64(0, lowGuid);
143
145 stmt->setUInt64(0, lowGuid);
147
149 stmt->setUInt64(0, lowGuid);
151
152 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_REPUTATION);
153 stmt->setUInt64(0, lowGuid);
155
156 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_INVENTORY);
157 stmt->setUInt64(0, lowGuid);
159
160 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEM_INSTANCE_ARTIFACT);
161 stmt->setUInt64(0, lowGuid);
163
164 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEM_INSTANCE_AZERITE);
165 stmt->setUInt64(0, lowGuid);
167
169 stmt->setUInt64(0, lowGuid);
171
173 stmt->setUInt64(0, lowGuid);
175
177 stmt->setUInt64(0, lowGuid);
179
180 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_VOID_STORAGE);
181 stmt->setUInt64(0, lowGuid);
183
184 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL);
185 stmt->setUInt64(0, lowGuid);
187
188 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS);
189 stmt->setUInt64(0, lowGuid);
191
192 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS_ARTIFACT);
193 stmt->setUInt64(0, lowGuid);
195
196 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS_AZERITE);
197 stmt->setUInt64(0, lowGuid);
199
201 stmt->setUInt64(0, lowGuid);
203
205 stmt->setUInt64(0, lowGuid);
207
208 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS_AZERITE_EMPOWERED);
209 stmt->setUInt64(0, lowGuid);
211
212 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SOCIALLIST);
213 stmt->setUInt64(0, lowGuid);
215
216 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_HOMEBIND);
217 stmt->setUInt64(0, lowGuid);
219
220 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS);
221 stmt->setUInt64(0, lowGuid);
223
224 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SPELL_CHARGES);
225 stmt->setUInt64(0, lowGuid);
227
228 if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED))
229 {
230 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_DECLINEDNAMES);
231 stmt->setUInt64(0, lowGuid);
233 }
234
235 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER);
236 stmt->setUInt64(0, lowGuid);
238
239 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ARENAINFO);
240 stmt->setUInt64(0, lowGuid);
242
243 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACHIEVEMENTS);
244 stmt->setUInt64(0, lowGuid);
246
247 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_CRITERIAPROGRESS);
248 stmt->setUInt64(0, lowGuid);
250
251 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_EQUIPMENTSETS);
252 stmt->setUInt64(0, lowGuid);
254
255 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_TRANSMOG_OUTFITS);
256 stmt->setUInt64(0, lowGuid);
258
259 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_CUF_PROFILES);
260 stmt->setUInt64(0, lowGuid);
262
263 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_BGDATA);
264 stmt->setUInt64(0, lowGuid);
266
267 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GLYPHS);
268 stmt->setUInt64(0, lowGuid);
270
271 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_TALENTS);
272 stmt->setUInt64(0, lowGuid);
274
275 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_PVP_TALENTS);
276 stmt->setUInt64(0, lowGuid);
278
279 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PLAYER_ACCOUNT_DATA);
280 stmt->setUInt64(0, lowGuid);
282
283 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SKILLS);
284 stmt->setUInt64(0, lowGuid);
286
287 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_RANDOMBG);
288 stmt->setUInt64(0, lowGuid);
290
291 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_BANNED);
292 stmt->setUInt64(0, lowGuid);
294
295 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUSREW);
296 stmt->setUInt64(0, lowGuid);
298
299 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES);
300 stmt->setUInt32(0, m_accountId);
302
303 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PLAYER_CURRENCY);
304 stmt->setUInt64(0, lowGuid);
306
307 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CORPSE_LOCATION);
308 stmt->setUInt64(0, lowGuid);
310
311 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_PETS);
312 stmt->setUInt64(0, lowGuid);
314
315 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON);
316 stmt->setUInt64(0, lowGuid);
318
320 stmt->setUInt64(0, lowGuid);
322
323 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON_BUILDINGS);
324 stmt->setUInt64(0, lowGuid);
326
327 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWERS);
328 stmt->setUInt64(0, lowGuid);
330
332 stmt->setUInt64(0, lowGuid);
334
335 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_TRAIT_ENTRIES);
336 stmt->setUInt64(0, lowGuid);
338
339 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_TRAIT_CONFIGS);
340 stmt->setUInt64(0, lowGuid);
342
343 return res;
344}
345
347{
348public:
349 enum
350 {
353
354 MAX
355 };
356
358 {
359 SetSize(MAX);
360 }
361
362 bool Initialize(uint32 accountId, bool withDeclinedNames, bool isDeletedCharacters)
363 {
364 _isDeletedCharacters = isDeletedCharacters;
365
366 constexpr CharacterDatabaseStatements statements[2][3] =
367 {
370 };
371
372 bool result = true;
373 CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(statements[isDeletedCharacters ? 1 : 0][withDeclinedNames ? 1 : 0]);
374 stmt->setUInt32(0, accountId);
375 result &= SetPreparedQuery(CHARACTERS, stmt);
376
377 stmt = CharacterDatabase.GetPreparedStatement(statements[isDeletedCharacters ? 1 : 0][2]);
378 stmt->setUInt32(0, accountId);
379 result &= SetPreparedQuery(CUSTOMIZATIONS, stmt);
380
381 return result;
382 }
383
385
386private:
388};
389
391{
393 charEnum.Success = true;
394 charEnum.IsDeletedCharacters = static_cast<EnumCharactersQueryHolder const&>(holder).IsDeletedCharacters();
396
397 if (!charEnum.IsDeletedCharacters)
398 _legitCharacters.clear();
399
400 std::unordered_map<ObjectGuid::LowType, std::vector<UF::ChrCustomizationChoice>> customizations;
402 {
403 do
404 {
405 Field* fields = customizationsResult->Fetch();
406 UF::ChrCustomizationChoice& choice = customizations[fields[0].GetUInt64()].emplace_back();
407 choice.ChrCustomizationOptionID = fields[1].GetUInt32();
408 choice.ChrCustomizationChoiceID = fields[2].GetUInt32();
409
410 } while (customizationsResult->NextRow());
411 }
412
414 {
415 do
416 {
417 charEnum.Characters.emplace_back(result->Fetch());
418
420
421 if (std::vector<UF::ChrCustomizationChoice>* customizationsForChar = Trinity::Containers::MapGetValuePtr(customizations, charInfo.Guid.GetCounter()))
422 charInfo.Customizations = std::move(*customizationsForChar);
423
424 TC_LOG_INFO("network", "Loading char guid {} from account {}.", charInfo.Guid.ToString(), GetAccountId());
425
426 if (!charEnum.IsDeletedCharacters)
427 {
429 {
430 TC_LOG_ERROR("entities.player.loading", "Player {} has wrong Appearance values (Hair/Skin/Color), forcing recustomize", charInfo.Guid.ToString());
431
432 charInfo.Customizations.clear();
433
435 {
438 stmt->setUInt64(1, charInfo.Guid.GetCounter());
439 CharacterDatabase.Execute(stmt);
441 }
442 }
443
444 // Do not allow locked characters to login
446 _legitCharacters.insert(charInfo.Guid);
447 }
448
449 if (!sCharacterCache->HasCharacterCacheEntry(charInfo.Guid)) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet.
450 sCharacterCache->AddCharacterCacheEntry(charInfo.Guid, GetAccountId(), charInfo.Name, charInfo.SexID, charInfo.RaceID, charInfo.ClassID, charInfo.ExperienceLevel, false);
451
452 charEnum.MaxCharacterLevel = std::max<int32>(charEnum.MaxCharacterLevel, charInfo.ExperienceLevel);
453 }
454 while (result->NextRow() && charEnum.Characters.size() < MAX_CHARACTERS_PER_REALM);
455 }
456
457 for (std::pair<uint8 const, RaceUnlockRequirement> const& requirement : sObjectMgr->GetRaceUnlockRequirements())
458 {
460 raceUnlock.RaceID = requirement.first;
461 raceUnlock.HasExpansion = GetAccountExpansion() >= requirement.second.Expansion;
462 raceUnlock.HasAchievement = requirement.second.AchievementId != 0
464 /* || HasAccountAchievement(requirement.second.AchievementId)*/);
465 charEnum.RaceUnlockData.push_back(raceUnlock);
466 }
467
468 SendPacket(charEnum.Write());
469}
470
472{
473 // remove expired bans
475 CharacterDatabase.Execute(stmt);
476
478 std::shared_ptr<EnumCharactersQueryHolder> holder = std::make_shared<EnumCharactersQueryHolder>();
479 if (!holder->Initialize(GetAccountId(), sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED), false))
480 {
481 HandleCharEnum(*holder);
482 return;
483 }
484
485 AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder)).AfterComplete([this](SQLQueryHolderBase const& result)
486 {
487 HandleCharEnum(static_cast<EnumCharactersQueryHolder const&>(result));
488 });
489}
490
492{
494 std::shared_ptr<EnumCharactersQueryHolder> holder = std::make_shared<EnumCharactersQueryHolder>();
495 if (!holder->Initialize(GetAccountId(), sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED), true))
496 {
497 HandleCharEnum(*holder);
498 return;
499 }
500
501 AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder)).AfterComplete([this](SQLQueryHolderBase const& result)
502 {
503 HandleCharEnum(static_cast<EnumCharactersQueryHolder const&>(result));
504 });
505}
506
508 bool checkRequiredDependentChoices, Trinity::IteratorPair<UF::ChrCustomizationChoice const*> selectedChoices) const
509{
511 return true;
512
513 if (req->ClassMask && !(req->ClassMask & (1 << (playerClass - 1))))
514 return false;
515
516 if (race != RACE_NONE && !req->RaceMask.IsEmpty() && req->RaceMask.RawValue != -1 && !req->RaceMask.HasRace(race))
517 return false;
518
519 if (req->AchievementID /*&& !HasAchieved(req->AchievementID)*/)
520 return false;
521
522 if (req->ItemModifiedAppearanceID && !GetCollectionMgr()->HasItemAppearance(req->ItemModifiedAppearanceID).first)
523 return false;
524
525 if (req->QuestID)
526 {
527 if (!_player)
528 return false;
529
530 if (!_player->IsQuestRewarded(req->QuestID))
531 return false;
532 }
533
534 if (checkRequiredDependentChoices)
535 {
536 if (std::vector<std::pair<uint32, std::vector<uint32>>> const* requiredChoices = sDB2Manager.GetRequiredCustomizationChoices(req->ID))
537 {
538 for (auto const& [chrCustomizationOptionId, requiredChoicesForOption] : *requiredChoices)
539 {
540 bool hasRequiredChoiceForOption = false;
541 for (uint32 requiredChoice : requiredChoicesForOption)
542 {
543 auto choiceItr = std::find_if(selectedChoices.begin(), selectedChoices.end(), [requiredChoice](UF::ChrCustomizationChoice const& choice)
544 {
545 return choice.ChrCustomizationChoiceID == requiredChoice;
546 });
547
548 if (choiceItr != selectedChoices.end())
549 {
550 hasRequiredChoiceForOption = true;
551 break;
552 }
553 }
554
555 if (!hasRequiredChoiceForOption)
556 return false;
557 }
558 }
559 }
560
561 return true;
562}
563
565{
566 std::vector<ChrCustomizationOptionEntry const*> const* options = sDB2Manager.GetCustomiztionOptions(race, gender);
567 if (!options)
568 return false;
569
570 uint32 previousOption = 0;
571
572 for (UF::ChrCustomizationChoice playerChoice : customizations)
573 {
574 // check uniqueness of options
575 if (playerChoice.ChrCustomizationOptionID == previousOption)
576 return false;
577
578 previousOption = playerChoice.ChrCustomizationOptionID;
579
580 // check if we can use this option
581 auto customizationOptionDataItr = std::find_if(options->begin(), options->end(), [&](ChrCustomizationOptionEntry const* option)
582 {
583 return option->ID == playerChoice.ChrCustomizationOptionID;
584 });
585
586 // option not found for race/gender combination
587 if (customizationOptionDataItr == options->end())
588 return false;
589
590 if (ChrCustomizationReqEntry const* req = sChrCustomizationReqStore.LookupEntry((*customizationOptionDataItr)->ChrCustomizationReqID))
591 if (!MeetsChrCustomizationReq(req, race, playerClass, false, customizations))
592 return false;
593
594 std::vector<ChrCustomizationChoiceEntry const*> const* choicesForOption = sDB2Manager.GetCustomiztionChoices(playerChoice.ChrCustomizationOptionID);
595 if (!choicesForOption)
596 return false;
597
598 auto customizationChoiceDataItr = std::find_if(choicesForOption->begin(), choicesForOption->end(), [&](ChrCustomizationChoiceEntry const* choice)
599 {
600 return choice->ID == playerChoice.ChrCustomizationChoiceID;
601 });
602
603 // choice not found for option
604 if (customizationChoiceDataItr == choicesForOption->end())
605 return false;
606
607 if (ChrCustomizationReqEntry const* req = sChrCustomizationReqStore.LookupEntry((*customizationChoiceDataItr)->ChrCustomizationReqID))
608 if (!MeetsChrCustomizationReq(req, race, playerClass, true, customizations))
609 return false;
610 }
611
612 return true;
613}
614
616{
618 {
619 if (uint32 mask = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED))
620 {
621 bool disabled = false;
622
623 switch (Player::TeamIdForRace(charCreate.CreateInfo->Race))
624 {
625 case TEAM_ALLIANCE:
626 disabled = (mask & (1 << 0)) != 0;
627 break;
628 case TEAM_HORDE:
629 disabled = (mask & (1 << 1)) != 0;
630 break;
631 case TEAM_NEUTRAL:
632 disabled = (mask & (1 << 2)) != 0;
633 break;
634 }
635
636 if (disabled)
637 {
639 return;
640 }
641 }
642 }
643
644 ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(charCreate.CreateInfo->Class);
645 if (!classEntry)
646 {
647 TC_LOG_ERROR("network", "Class ({}) not found in DBC while creating new char for account (ID: {}): wrong DBC files or cheater?", charCreate.CreateInfo->Class, GetAccountId());
649 return;
650 }
651
652 ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(charCreate.CreateInfo->Race);
653 if (!raceEntry)
654 {
655 TC_LOG_ERROR("network", "Race ({}) not found in DBC while creating new char for account (ID: {}): wrong DBC files or cheater?", charCreate.CreateInfo->Race, GetAccountId());
657 return;
658 }
659
660 // prevent character creating Expansion race without Expansion account
661 RaceUnlockRequirement const* raceExpansionRequirement = sObjectMgr->GetRaceUnlockRequirement(charCreate.CreateInfo->Race);
662 if (!raceExpansionRequirement)
663 {
664 TC_LOG_ERROR("entities.player.cheat", "Account {} tried to create character with unavailable race {}", GetAccountId(), charCreate.CreateInfo->Race);
666 return;
667 }
668
669 if (raceExpansionRequirement->Expansion > GetAccountExpansion())
670 {
671 TC_LOG_ERROR("entities.player.cheat", "Expansion {} account:[{}] tried to Create character with expansion {} race ({})",
672 GetAccountExpansion(), GetAccountId(), raceExpansionRequirement->Expansion, charCreate.CreateInfo->Race);
674 return;
675 }
676
677 //if (raceExpansionRequirement->AchievementId && !)
678 //{
679 // TC_LOG_ERROR("entities.player.cheat", "Expansion {} account:[{}] tried to Create character without achievement {} race ({})",
680 // GetAccountExpansion(), GetAccountId(), raceExpansionRequirement->AchievementId, charCreate.CreateInfo->Race);
681 // SendCharCreate(CHAR_CREATE_ALLIED_RACE_ACHIEVEMENT);
682 // return;
683 //}
684
685 // prevent character creating Expansion class without Expansion account
686 if (ClassAvailability const* raceClassExpansionRequirement = sObjectMgr->GetClassExpansionRequirement(charCreate.CreateInfo->Race, charCreate.CreateInfo->Class))
687 {
688 if (raceClassExpansionRequirement->ActiveExpansionLevel > GetExpansion() || raceClassExpansionRequirement->AccountExpansionLevel > GetAccountExpansion())
689 {
690 TC_LOG_ERROR("entities.player.cheat", "Account:[{}] tried to create character with race/class {}/{} without required expansion (had {}/{}, required {}/{})",
691 GetAccountId(), uint32(charCreate.CreateInfo->Race), uint32(charCreate.CreateInfo->Class), GetExpansion(), GetAccountExpansion(),
692 raceClassExpansionRequirement->ActiveExpansionLevel, raceClassExpansionRequirement->AccountExpansionLevel);
694 return;
695 }
696 }
697 else if (ClassAvailability const* classExpansionRequirement = sObjectMgr->GetClassExpansionRequirementFallback(charCreate.CreateInfo->Class))
698 {
699 if (classExpansionRequirement->MinActiveExpansionLevel > GetExpansion() || classExpansionRequirement->AccountExpansionLevel > GetAccountExpansion())
700 {
701 TC_LOG_ERROR("entities.player.cheat", "Account:[{}] tried to create character with race/class {}/{} without required expansion (had {}/{}, required {}/{})",
702 GetAccountId(), uint32(charCreate.CreateInfo->Race), uint32(charCreate.CreateInfo->Class), GetExpansion(), GetAccountExpansion(),
703 classExpansionRequirement->ActiveExpansionLevel, classExpansionRequirement->AccountExpansionLevel);
705 return;
706 }
707 }
708 else
709 {
710 TC_LOG_ERROR("entities.player.cheat", "Expansion {} account:[{}] tried to Create character for race/class combination that is missing requirements in db ({}/{})",
711 GetAccountExpansion(), GetAccountId(), uint32(charCreate.CreateInfo->Race), uint32(charCreate.CreateInfo->Class));
713 return;
714 }
715
717 {
718 if (raceEntry->GetFlags().HasFlag(ChrRacesFlag::NPCOnly))
719 {
720 TC_LOG_ERROR("network", "Race ({}) was not playable but requested while creating new char for account (ID: {}): wrong DBC files or cheater?", charCreate.CreateInfo->Race, GetAccountId());
722 return;
723 }
724
726 if (raceMaskDisabled.HasRace(charCreate.CreateInfo->Race))
727 {
729 return;
730 }
731 }
732
734 {
735 uint32 classMaskDisabled = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK);
736 if ((1 << (charCreate.CreateInfo->Class - 1)) & classMaskDisabled)
737 {
739 return;
740 }
741 }
742
743 // prevent character creating with invalid name
744 if (!normalizePlayerName(charCreate.CreateInfo->Name))
745 {
746 TC_LOG_ERROR("entities.player.cheat", "Account:[{}] but tried to Create character with empty [name] ", GetAccountId());
748 return;
749 }
750
751 // check name limitations
753 if (res != CHAR_NAME_SUCCESS)
754 {
755 SendCharCreate(res);
756 return;
757 }
758
760 {
762 return;
763 }
764
765 std::shared_ptr<WorldPackets::Character::CharacterCreateInfo> createInfo = charCreate.CreateInfo;
767 stmt->setString(0, charCreate.CreateInfo->Name);
768
770 .WithChainingPreparedCallback([this](QueryCallback& queryCallback, PreparedQueryResult result)
771 {
772 if (result)
773 {
774 SendCharCreate(CHAR_CREATE_NAME_IN_USE);
775 return;
776 }
777
779 stmt->setUInt32(0, GetAccountId());
780 queryCallback.SetNextQuery(LoginDatabase.AsyncQuery(stmt));
781 })
782 .WithChainingPreparedCallback([this](QueryCallback& queryCallback, PreparedQueryResult result)
783 {
784 uint64 acctCharCount = 0;
785 if (result)
786 {
787 Field* fields = result->Fetch();
788 acctCharCount = uint64(fields[0].GetDouble());
789 }
790
791 if (acctCharCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_ACCOUNT))
792 {
793 SendCharCreate(CHAR_CREATE_ACCOUNT_LIMIT);
794 return;
795 }
796
798 stmt->setUInt32(0, GetAccountId());
799 queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt));
800 })
801 .WithChainingPreparedCallback([this, createInfo](QueryCallback& queryCallback, PreparedQueryResult result)
802 {
803 if (result)
804 {
805 Field* fields = result->Fetch();
806 createInfo->CharCount = uint8(fields[0].GetUInt64()); // SQL's COUNT() returns uint64 but it will always be less than uint8.Max
807
808 if (createInfo->CharCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM))
809 {
810 SendCharCreate(CHAR_CREATE_SERVER_LIMIT);
811 return;
812 }
813 }
814
815 bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || HasPermission(rbac::RBAC_PERM_TWO_SIDE_CHARACTER_CREATION);
816 uint32 skipCinematics = sWorld->getIntConfig(CONFIG_SKIP_CINEMATICS);
817
818 std::function<void(PreparedQueryResult)> finalizeCharacterCreation = [this, createInfo](PreparedQueryResult result)
819 {
820 bool haveSameRace = false;
821 uint32 demonHunterReqLevel = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_DEMON_HUNTER);
822 bool hasDemonHunterReqLevel = (demonHunterReqLevel == 0);
823 uint32 evokerReqLevel = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_EVOKER);
824 bool hasEvokerReqLevel = (evokerReqLevel == 0);
825 bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || HasPermission(rbac::RBAC_PERM_TWO_SIDE_CHARACTER_CREATION);
826 uint32 skipCinematics = sWorld->getIntConfig(CONFIG_SKIP_CINEMATICS);
827 bool checkClassLevelReqs = (createInfo->Class == CLASS_DEMON_HUNTER || createInfo->Class == CLASS_EVOKER)
829 int32 evokerLimit = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_EVOKERS_PER_REALM);
830 bool hasEvokerLimit = evokerLimit != 0;
831
832 if (result)
833 {
834 uint32 team = Player::TeamForRace(createInfo->Race);
835
836 Field* field = result->Fetch();
837 uint8 accRace = field[1].GetUInt8();
838 uint8 accClass = field[2].GetUInt8();
839
840 if (checkClassLevelReqs)
841 {
842 if (!hasDemonHunterReqLevel)
843 {
844 uint8 accLevel = field[0].GetUInt8();
845 if (accLevel >= demonHunterReqLevel)
846 hasDemonHunterReqLevel = true;
847 }
848 if (!hasEvokerReqLevel)
849 {
850 uint8 accLevel = field[0].GetUInt8();
851 if (accLevel >= evokerReqLevel)
852 hasEvokerReqLevel = true;
853 }
854 }
855
856 if (accClass == CLASS_EVOKER)
857 --evokerLimit;
858
859 // need to check team only for first character
861 if (!allowTwoSideAccounts)
862 {
863 uint32 accTeam = 0;
864 if (accRace > 0)
865 accTeam = Player::TeamForRace(accRace);
866
867 if (accTeam != team)
868 {
869 SendCharCreate(CHAR_CREATE_PVP_TEAMS_VIOLATION);
870 return;
871 }
872 }
873
874 // search same race for cinematic or same class if need
876 while ((skipCinematics == 1 && !haveSameRace) || createInfo->Class == CLASS_DEMON_HUNTER || createInfo->Class == CLASS_EVOKER)
877 {
878 if (!result->NextRow())
879 break;
880
881 field = result->Fetch();
882 accRace = field[1].GetUInt8();
883 accClass = field[2].GetUInt8();
884
885 if (!haveSameRace)
886 haveSameRace = createInfo->Race == accRace;
887
888 if (checkClassLevelReqs)
889 {
890 if (!hasDemonHunterReqLevel)
891 {
892 uint8 accLevel = field[0].GetUInt8();
893 if (accLevel >= demonHunterReqLevel)
894 hasDemonHunterReqLevel = true;
895 }
896 if (!hasEvokerReqLevel)
897 {
898 uint8 accLevel = field[0].GetUInt8();
899 if (accLevel >= evokerReqLevel)
900 hasEvokerReqLevel = true;
901 }
902 }
903
904 if (accClass == CLASS_EVOKER)
905 --evokerLimit;
906 }
907 }
908
909 if (checkClassLevelReqs)
910 {
911 if (!hasDemonHunterReqLevel)
912 {
913 SendCharCreate(CHAR_CREATE_NEW_PLAYER);
914 return;
915 }
916 if (!hasEvokerReqLevel)
917 {
919 return;
920 }
921 }
922
923 if (createInfo->Class == CLASS_EVOKER && hasEvokerLimit && evokerLimit < 1)
924 {
925 SendCharCreate(CHAR_CREATE_DRACTHYR_DUPLICATE);
926 return;
927 }
928
929 // Check name uniqueness in the same step as saving to database
930 if (sCharacterCache->GetCharacterCacheByName(createInfo->Name))
931 {
932 SendCharCreate(CHAR_CREATE_NAME_IN_USE);
933 return;
934 }
935
936 std::shared_ptr<Player> newChar(new Player(this), [](Player* ptr)
937 {
939 delete ptr;
940 });
941 newChar->GetMotionMaster()->Initialize();
942 if (!newChar->Create(sObjectMgr->GetGenerator<HighGuid::Player>().Generate(), createInfo.get()))
943 {
944 // Player not create (race/class/etc problem?)
945 SendCharCreate(CHAR_CREATE_ERROR);
946 return;
947 }
948
949 if ((haveSameRace && skipCinematics == 1) || skipCinematics == 2)
950 newChar->setCinematic(1); // not show intro
951
952 newChar->SetAtLoginFlag(AT_LOGIN_FIRST); // First login
953
954 CharacterDatabaseTransaction characterTransaction = CharacterDatabase.BeginTransaction();
955 LoginDatabaseTransaction trans = LoginDatabase.BeginTransaction();
956
957 // Player created, save it now
958 newChar->SaveToDB(trans, characterTransaction, true);
959 createInfo->CharCount += 1;
960
962 stmt->setUInt32(0, createInfo->CharCount);
963 stmt->setUInt32(1, GetAccountId());
964 stmt->setUInt32(2, realm.Id.Realm);
965 trans->Append(stmt);
966
967 LoginDatabase.CommitTransaction(trans);
968
969 AddTransactionCallback(CharacterDatabase.AsyncCommitTransaction(characterTransaction)).AfterComplete([this, newChar = std::move(newChar)](bool success)
970 {
971 if (success)
972 {
973 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Create Character: {} {}", GetAccountId(), GetRemoteAddress(), newChar->GetName(), newChar->GetGUID().ToString());
974 sScriptMgr->OnPlayerCreate(newChar.get());
975 sCharacterCache->AddCharacterCacheEntry(newChar->GetGUID(), GetAccountId(), newChar->GetName(), newChar->GetNativeGender(), newChar->GetRace(), newChar->GetClass(), newChar->GetLevel(), false);
976
977 SendCharCreate(CHAR_CREATE_SUCCESS, newChar->GetGUID());
978 }
979 else
980 SendCharCreate(CHAR_CREATE_ERROR);
981 });
982 };
983
984 if (allowTwoSideAccounts && !skipCinematics && createInfo->Class != CLASS_DEMON_HUNTER)
985 {
986 finalizeCharacterCreation(PreparedQueryResult(nullptr));
987 return;
988 }
989
991 stmt->setUInt32(0, GetAccountId());
992 stmt->setUInt32(1, (skipCinematics == 1 || createInfo->Class == CLASS_DEMON_HUNTER || createInfo->Class == CLASS_EVOKER) ? 1200 : 1); // 200 (max chars per realm) + 1000 (max deleted chars per realm)
993 queryCallback.WithPreparedCallback(std::move(finalizeCharacterCreation)).SetNextQuery(CharacterDatabase.AsyncQuery(stmt));
994 }));
995}
996
998{
999 // Initiating
1000 uint32 initAccountId = GetAccountId();
1001
1002 // can't delete loaded character
1003 if (ObjectAccessor::FindPlayer(charDelete.Guid))
1004 {
1005 sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
1006 return;
1007 }
1008
1009 // is guild leader
1010 if (sGuildMgr->GetGuildByLeader(charDelete.Guid))
1011 {
1012 sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
1014 return;
1015 }
1016
1017 // is arena team captain
1018 if (sArenaTeamMgr->GetArenaTeamByCaptain(charDelete.Guid))
1019 {
1020 sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
1022 return;
1023 }
1024
1025 CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(charDelete.Guid);
1026 if (!characterInfo)
1027 {
1028 sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
1029 return;
1030 }
1031
1032 uint32 accountId = characterInfo->AccountId;
1033 std::string name = characterInfo->Name;
1034 uint8 level = characterInfo->Level;
1035
1036 // prevent deleting other players' characters using cheating tools
1037 if (accountId != initAccountId)
1038 {
1039 sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
1040 return;
1041 }
1042
1043 TC_LOG_INFO("entities.player.character", "Account: {}, IP: {} deleted character: {}, {}, Level: {}", accountId, GetRemoteAddress(), name, charDelete.Guid.ToString(), level);
1044
1045 // To prevent hook failure, place hook before removing reference from DB
1046 sScriptMgr->OnPlayerDelete(charDelete.Guid, initAccountId); // To prevent race conditioning, but as it also makes sense, we hand the accountId over for successful delete.
1047 // Shouldn't interfere with character deletion though
1048
1049 if (sLog->ShouldLog("entities.player.dump", LOG_LEVEL_INFO)) // optimize GetPlayerDump call
1050 {
1051 std::string dump;
1052 if (PlayerDumpWriter().GetDump(charDelete.Guid.GetCounter(), dump))
1053 sLog->OutCharDump(dump.c_str(), accountId, charDelete.Guid.GetCounter(), name.c_str());
1054 }
1055
1056 sCalendarMgr->RemoveAllPlayerEventsAndInvites(charDelete.Guid);
1057 Player::DeleteFromDB(charDelete.Guid, accountId);
1058
1060}
1061
1063{
1064 if (PlayerLoading() || GetPlayer() != nullptr)
1065 {
1066 TC_LOG_ERROR("network", "Player tries to login again, AccountId = {}", GetAccountId());
1067 KickPlayer("WorldSession::HandlePlayerLoginOpcode Another client logging in");
1068 return;
1069 }
1070
1071 m_playerLoading = playerLogin.Guid;
1072
1073 TC_LOG_DEBUG("network", "Character {} logging in", playerLogin.Guid.ToString());
1074
1075 if (!IsLegitCharacterForAccount(playerLogin.Guid))
1076 {
1077 TC_LOG_ERROR("network", "Account ({}) can't login with that character ({}).", GetAccountId(), playerLogin.Guid.ToString());
1078 KickPlayer("WorldSession::HandlePlayerLoginOpcode Trying to login with a character of another account");
1079 return;
1080 }
1081
1083}
1084
1086{
1087 if (!PlayerLoading() || GetPlayer())
1088 {
1089 KickPlayer("WorldSession::HandleContinuePlayerLogin incorrect player state when logging in");
1090 return;
1091 }
1092
1093 std::shared_ptr<LoginQueryHolder> holder = std::make_shared<LoginQueryHolder>(GetAccountId(), m_playerLoading);
1094 if (!holder->Initialize())
1095 {
1097 return;
1098 }
1099
1101
1102 AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder)).AfterComplete([this](SQLQueryHolderBase const& holder)
1103 {
1104 HandlePlayerLogin(static_cast<LoginQueryHolder const&>(holder));
1105 });
1106}
1107
1109{
1110 if (!PlayerLoading() || GetPlayer())
1111 {
1112 KickPlayer("WorldSession::AbortLogin incorrect player state when logging in");
1113 return;
1114 }
1115
1118}
1119
1121{
1122 // TODO: Do something with this packet
1123}
1124
1126{
1127 ObjectGuid playerGuid = holder.GetGuid();
1128
1129 Player* pCurrChar = new Player(this);
1130 // for send server info and strings (config)
1131 ChatHandler chH = ChatHandler(pCurrChar->GetSession());
1132
1133 // "GetAccountId() == db stored account id" checked in LoadFromDB (prevent login not own character using cheating tools)
1134 if (!pCurrChar->LoadFromDB(playerGuid, holder))
1135 {
1136 SetPlayer(nullptr);
1137 KickPlayer("WorldSession::HandlePlayerLogin Player::LoadFromDB failed"); // disconnect client, player no set to session and it will not deleted or saved at kick
1138 delete pCurrChar; // delete it manually
1140 return;
1141 }
1142
1144
1147
1148 pCurrChar->GetMotionMaster()->Initialize();
1149 pCurrChar->SendDungeonDifficulty();
1150
1152 loginVerifyWorld.MapID = pCurrChar->GetMapId();
1153 loginVerifyWorld.Pos = pCurrChar->GetPosition();
1154 SendPacket(loginVerifyWorld.Write());
1155
1156 // load player specific part before send times
1159
1161
1162 // Send MOTD
1163 {
1164 for (std::string const& motdLine : sWorld->GetMotd())
1165 sWorld->SendServerMessage(SERVER_MSG_STRING, motdLine, pCurrChar);
1166 }
1167
1169
1170 // Send PVPSeason
1171 {
1173 seasonInfo.PreviousArenaSeason = sWorld->getIntConfig(CONFIG_ARENA_SEASON_ID) - sWorld->getBoolConfig(CONFIG_ARENA_SEASON_IN_PROGRESS);
1174
1175 if (sWorld->getBoolConfig(CONFIG_ARENA_SEASON_IN_PROGRESS))
1176 seasonInfo.CurrentArenaSeason = sWorld->getIntConfig(CONFIG_ARENA_SEASON_ID);
1177
1178 SendPacket(seasonInfo.Write());
1179 }
1180
1181 // send server info
1182 {
1183 if (sWorld->getIntConfig(CONFIG_ENABLE_SINFO_LOGIN) == 1)
1185 }
1186
1187 //QueryResult* result = CharacterDatabase.PQuery("SELECT guildid, `rank` FROM guild_member WHERE guid = '{}'", pCurrChar->GetGUIDLow());
1189 {
1190 Field* fields = resultGuild->Fetch();
1191 pCurrChar->SetInGuild(fields[0].GetUInt64());
1192 pCurrChar->SetGuildRank(fields[1].GetUInt8());
1193 if (Guild* guild = sGuildMgr->GetGuildById(pCurrChar->GetGuildId()))
1194 pCurrChar->SetGuildLevel(guild->GetLevel());
1195 }
1196 else if (pCurrChar->GetGuildId()) // clear guild related fields in case wrong data about non existed membership
1197 {
1198 pCurrChar->SetInGuild(UI64LIT(0));
1199 pCurrChar->SetGuildRank(0);
1200 pCurrChar->SetGuildLevel(0);
1201 }
1202
1204
1206
1207 //Show cinematic at the first time that player login
1208 if (!pCurrChar->getCinematic())
1209 {
1210 pCurrChar->setCinematic(1);
1211
1212 if (PlayerInfo const* playerInfo = sObjectMgr->GetPlayerInfo(pCurrChar->GetRace(), pCurrChar->GetClass()))
1213 {
1214 switch (pCurrChar->GetCreateMode())
1215 {
1217 if (playerInfo->introMovieId)
1218 pCurrChar->SendMovieStart(*playerInfo->introMovieId);
1219 else if (playerInfo->introSceneId)
1220 pCurrChar->GetSceneMgr().PlayScene(*playerInfo->introSceneId);
1221 else if (sChrClassesStore.AssertEntry(pCurrChar->GetClass())->CinematicSequenceID)
1222 pCurrChar->SendCinematicStart(sChrClassesStore.AssertEntry(pCurrChar->GetClass())->CinematicSequenceID);
1223 else if (sChrRacesStore.AssertEntry(pCurrChar->GetRace())->CinematicSequenceID)
1224 pCurrChar->SendCinematicStart(sChrRacesStore.AssertEntry(pCurrChar->GetRace())->CinematicSequenceID);
1225 break;
1227 if (playerInfo->introSceneIdNPE)
1228 pCurrChar->GetSceneMgr().PlayScene(*playerInfo->introSceneIdNPE);
1229 break;
1230 default:
1231 break;
1232 }
1233 }
1234
1235 // send new char string if not empty
1236 if (!sWorld->GetNewCharString().empty())
1237 chH.PSendSysMessage("%s", sWorld->GetNewCharString().c_str());
1238 }
1239
1240 if (!pCurrChar->GetMap()->AddPlayerToMap(pCurrChar))
1241 {
1242 AreaTriggerStruct const* at = sObjectMgr->GetGoBackTrigger(pCurrChar->GetMapId());
1243 if (at)
1244 pCurrChar->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, pCurrChar->GetOrientation());
1245 else
1246 pCurrChar->TeleportTo(pCurrChar->m_homebind);
1247 }
1248
1249 ObjectAccessor::AddObject(pCurrChar);
1250 //TC_LOG_DEBUG("Player {} added to Map.", pCurrChar->GetName());
1251
1252 if (pCurrChar->GetGuildId())
1253 {
1254 if (Guild* guild = sGuildMgr->GetGuildById(pCurrChar->GetGuildId()))
1255 guild->SendLoginInfo(this);
1256 else
1257 {
1258 // remove wrong guild data
1259 TC_LOG_ERROR("misc", "Player {} ({}) marked as member of not existing guild (id: {}), removing guild membership for player.", pCurrChar->GetName(), pCurrChar->GetGUID().ToString(), pCurrChar->GetGuildId());
1260 pCurrChar->SetInGuild(UI64LIT(0));
1261 }
1262 }
1263
1265
1267
1269 stmt->setUInt64(0, pCurrChar->GetGUID().GetCounter());
1270 CharacterDatabase.Execute(stmt);
1271
1273 loginStmt->setUInt32(0, GetAccountId());
1274 LoginDatabase.Execute(loginStmt);
1275
1277
1278 // announce group about member online (must be after add to player list to receive announce to self)
1279 if (Group* group = pCurrChar->GetGroup())
1280 {
1281 //pCurrChar->groupInfo.group->SendInit(this); // useless
1282 group->SendUpdate();
1283 if (group->GetLeaderGUID() == pCurrChar->GetGUID())
1284 group->StopLeaderOfflineTimer();
1285 }
1286
1287 // friend status
1288 sSocialMgr->SendFriendStatus(pCurrChar, FRIEND_ONLINE, pCurrChar->GetGUID(), true);
1289
1290 // Place character in world (and load zone) before some object loading
1292
1293 // setting Ghost+speed if dead
1294 if (pCurrChar->m_deathState == DEAD)
1295 {
1296 // not blizz like, we must correctly save and load player instead...
1297 if (pCurrChar->GetRace() == RACE_NIGHTELF && !pCurrChar->HasAura(20584))
1298 pCurrChar->CastSpell(pCurrChar, 20584, true);// auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form)
1299
1300 if (!pCurrChar->HasAura(8326))
1301 pCurrChar->CastSpell(pCurrChar, 8326, true); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?)
1302
1303 pCurrChar->SetWaterWalking(true);
1304 }
1305
1306 pCurrChar->ContinueTaxiFlight();
1307
1308 // reset for all pets before pet loading
1310 {
1311 // Delete all of the player's pet spells
1313 stmtSpells->setUInt64(0, pCurrChar->GetGUID().GetCounter());
1314 CharacterDatabase.Execute(stmtSpells);
1315
1316 // Then reset all of the player's pet specualizations
1318 stmtSpec->setUInt64(0, pCurrChar->GetGUID().GetCounter());
1319 CharacterDatabase.Execute(stmtSpec);
1320 }
1321
1322 // Load pet if any (if player not alive and in taxi flight or another then pet will remember as temporary unsummoned)
1324
1325 // Set FFA PvP for non GM in non-rest mode
1326 if (sWorld->IsFFAPvPRealm() && !pCurrChar->IsGameMaster() && !pCurrChar->HasPlayerFlag(PLAYER_FLAGS_RESTING))
1328
1330 pCurrChar->SetContestedPvP();
1331
1332 // Apply at_login requests
1333 if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_SPELLS))
1334 {
1335 pCurrChar->ResetSpells();
1337 }
1338
1339 if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_TALENTS))
1340 {
1341 pCurrChar->ResetTalents(true);
1342 pCurrChar->ResetTalentSpecialization();
1343 pCurrChar->SendTalentsInfoData(); // original talents send already in to SendInitialPacketsBeforeAddToMap, resend reset state
1345 }
1346
1347 bool firstLogin = pCurrChar->HasAtLoginFlag(AT_LOGIN_FIRST);
1348 if (firstLogin)
1349 {
1351
1352 PlayerInfo const* info = sObjectMgr->GetPlayerInfo(pCurrChar->GetRace(), pCurrChar->GetClass());
1353 for (uint32 spellId : info->castSpells[AsUnderlyingType(pCurrChar->GetCreateMode())])
1354 pCurrChar->CastSpell(pCurrChar, spellId, true);
1355
1356 // start with every map explored
1357 if (sWorld->getBoolConfig(CONFIG_START_ALL_EXPLORED))
1358 {
1359 for (uint32 i = 0; i < PLAYER_EXPLORED_ZONES_SIZE; ++i)
1360 pCurrChar->AddExploredZones(i, UI64LIT(0xFFFFFFFFFFFFFFFF));
1361 }
1362
1363 // Max relevant reputations if "StartAllReputation" is enabled
1364 if (sWorld->getBoolConfig(CONFIG_START_ALL_REP))
1365 {
1366 ReputationMgr& repMgr = pCurrChar->GetReputationMgr();
1367 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 942), 42999, false); // Cenarion Expedition
1368 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 935), 42999, false); // The Sha'tar
1369 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 936), 42999, false); // Shattrath City
1370 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1011), 42999, false); // Lower City
1371 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 970), 42999, false); // Sporeggar
1372 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 967), 42999, false); // The Violet Eye
1373 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 989), 42999, false); // Keepers of Time
1374 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 932), 42999, false); // The Aldor
1375 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 934), 42999, false); // The Scryers
1376 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1038), 42999, false); // Ogri'la
1377 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1077), 42999, false); // Shattered Sun Offensive
1378 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1106), 42999, false); // Argent Crusade
1379 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1104), 42999, false); // Frenzyheart Tribe
1380 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1090), 42999, false); // Kirin Tor
1381 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1098), 42999, false); // Knights of the Ebon Blade
1382 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1156), 42999, false); // The Ashen Verdict
1383 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1073), 42999, false); // The Kalu'ak
1384 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1105), 42999, false); // The Oracles
1385 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1119), 42999, false); // The Sons of Hodir
1386 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1091), 42999, false); // The Wyrmrest Accord
1387
1388 // Factions depending on team, like cities and some more stuff
1389 switch (pCurrChar->GetTeam())
1390 {
1391 case ALLIANCE:
1392 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 72), 42999, false); // Stormwind
1393 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 47), 42999, false); // Ironforge
1394 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 69), 42999, false); // Darnassus
1395 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 930), 42999, false); // Exodar
1396 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 730), 42999, false); // Stormpike Guard
1397 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 978), 42999, false); // Kurenai
1398 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 54), 42999, false); // Gnomeregan Exiles
1399 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 946), 42999, false); // Honor Hold
1400 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1037), 42999, false); // Alliance Vanguard
1401 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1068), 42999, false); // Explorers' League
1402 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1126), 42999, false); // The Frostborn
1403 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1094), 42999, false); // The Silver Covenant
1404 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1050), 42999, false); // Valiance Expedition
1405 break;
1406 case HORDE:
1407 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 76), 42999, false); // Orgrimmar
1408 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 68), 42999, false); // Undercity
1409 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 81), 42999, false); // Thunder Bluff
1410 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 911), 42999, false); // Silvermoon City
1411 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 729), 42999, false); // Frostwolf Clan
1412 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 941), 42999, false); // The Mag'har
1413 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 530), 42999, false); // Darkspear Trolls
1414 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 947), 42999, false); // Thrallmar
1415 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1052), 42999, false); // Horde Expedition
1416 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1067), 42999, false); // The Hand of Vengeance
1417 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1124), 42999, false); // The Sunreavers
1418 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1064), 42999, false); // The Taunka
1419 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1085), 42999, false); // Warsong Offensive
1420 break;
1421 default:
1422 break;
1423 }
1424 repMgr.SendState(nullptr);
1425 }
1426 }
1427
1428 // show time before shutdown if shutdown planned.
1429 if (sWorld->IsShuttingDown())
1430 sWorld->ShutdownMsg(true, pCurrChar);
1431
1432 if (sWorld->getBoolConfig(CONFIG_ALL_TAXI_PATHS))
1433 pCurrChar->SetTaxiCheater(true);
1434
1435 if (pCurrChar->IsGameMaster())
1437
1438 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Login Character: [{}] {} Level: {}, XP: {}/{} ({} left)",
1439 GetAccountId(), GetRemoteAddress(), pCurrChar->GetName(), pCurrChar->GetGUID().ToString(), pCurrChar->GetLevel(),
1441
1442 if (!pCurrChar->IsStandState() && !pCurrChar->HasUnitState(UNIT_STATE_STUNNED))
1444
1445 pCurrChar->UpdateAverageItemLevelTotal();
1446 pCurrChar->UpdateAverageItemLevelEquipped();
1447
1449
1451
1452 // Handle Login-Achievements (should be handled after loading)
1454
1455 sScriptMgr->OnPlayerLogin(pCurrChar, firstLogin);
1456
1457 TC_METRIC_EVENT("player_events", "Login", pCurrChar->GetName());
1458}
1459
1461{
1463
1466 features.CfgRealmID = 2;
1467 features.CfgRealmRecID = 0;
1468 features.TokenPollTimeSeconds = 300;
1469 features.VoiceEnabled = false;
1470 features.BrowserEnabled = false; // Has to be false, otherwise client will crash if "Customer Support" is opened
1471
1472 // Enable guilds only.
1473 // This is required to restore old guild channel behavior for GMs.
1474 // The new club streams do not support sending messages through the guild channel when you are not in a guild.
1475 features.ClubsEnabled = true;
1476 features.ClubsBattleNetClubTypeAllowed = false;
1477 features.ClubsCharacterClubTypeAllowed = false;
1478 features.ClubsPresenceUpdateEnabled = true;
1479 features.HiddenUIClubsPresenceUpdateTimer = 60000;
1480
1481 features.EuropaTicketSystemStatus.emplace();
1482 features.EuropaTicketSystemStatus->ThrottleState.MaxTries = 10;
1483 features.EuropaTicketSystemStatus->ThrottleState.PerMilliseconds = 60000;
1484 features.EuropaTicketSystemStatus->ThrottleState.TryCount = 1;
1485 features.EuropaTicketSystemStatus->ThrottleState.LastResetTimeBeforeNow = 111111;
1486 features.TutorialsEnabled = true;
1487 features.NPETutorialsEnabled = true;
1489
1490 features.EuropaTicketSystemStatus->TicketsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_TICKETS_ENABLED);
1491 features.EuropaTicketSystemStatus->BugsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_BUGS_ENABLED);
1492 features.EuropaTicketSystemStatus->ComplaintsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_COMPLAINTS_ENABLED);
1493 features.EuropaTicketSystemStatus->SuggestionsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_SUGGESTIONS_ENABLED);
1494
1497 features.IsMuted = !CanSpeak();
1498
1499 features.TextToSpeechFeatureEnabled = false;
1500
1501 SendPacket(features.Write());
1502}
1503
1505{
1507}
1508
1510{
1511 GetPlayer()->GetReputationMgr().SetAtWar(packet.FactionIndex, false);
1512}
1513
1515{
1516 switch (packet.Action)
1517 {
1519 {
1520 uint8 index = uint8(packet.TutorialBit >> 5);
1521 if (index >= MAX_ACCOUNT_TUTORIAL_VALUES)
1522 {
1523 TC_LOG_ERROR("network", "CMSG_TUTORIAL_FLAG received bad TutorialBit {}.", packet.TutorialBit);
1524 return;
1525 }
1526 uint32 flag = GetTutorialInt(index);
1527 flag |= (1 << (packet.TutorialBit & 0x1F));
1528 SetTutorialInt(index, flag);
1529 break;
1530 }
1532 for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i)
1533 SetTutorialInt(i, 0xFFFFFFFF);
1534 break;
1536 for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i)
1537 SetTutorialInt(i, 0x00000000);
1538 break;
1539 default:
1540 TC_LOG_ERROR("network", "CMSG_TUTORIAL_FLAG received unknown TutorialAction {}.", packet.Action);
1541 return;
1542 }
1543}
1544
1546{
1548}
1549
1551{
1552 _player->GetReputationMgr().SetInactive(packet.Index, packet.State);
1553}
1554
1556{
1558}
1559
1561{
1562 // prevent character rename to invalid name
1563 if (!normalizePlayerName(checkCharacterNameAvailability.Name))
1564 {
1566 return;
1567 }
1568
1569 ResponseCodes res = ObjectMgr::CheckPlayerName(checkCharacterNameAvailability.Name, GetSessionDbcLocale(), true);
1570 if (res != CHAR_NAME_SUCCESS)
1571 {
1573 return;
1574 }
1575
1576 // check name limitations
1577 if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(checkCharacterNameAvailability.Name))
1578 {
1580 return;
1581 }
1582
1583 // Ensure that there is no character with the desired new name
1585 stmt->setString(0, checkCharacterNameAvailability.Name);
1586
1588 .WithPreparedCallback([this, sequenceIndex = checkCharacterNameAvailability.SequenceIndex](PreparedQueryResult result)
1589 {
1590 SendPacket(WorldPackets::Character::CheckCharacterNameAvailabilityResult(sequenceIndex, result ? CHAR_CREATE_NAME_IN_USE : RESPONSE_SUCCESS).Write());
1591 }));
1592}
1593
1595{
1596 if (!IsLegitCharacterForAccount(request.RenameInfo->Guid))
1597 {
1598 TC_LOG_ERROR("network", "Account {}, IP: {} tried to rename character {}, but it does not belong to their account!",
1599 GetAccountId(), GetRemoteAddress(), request.RenameInfo->Guid.ToString());
1600 KickPlayer("WorldSession::HandleCharRenameOpcode rename character from a different account");
1601 return;
1602 }
1603
1604 // prevent character rename to invalid name
1605 if (!normalizePlayerName(request.RenameInfo->NewName))
1606 {
1608 return;
1609 }
1610
1612 if (res != CHAR_NAME_SUCCESS)
1613 {
1614 SendCharRename(res, request.RenameInfo.get());
1615 return;
1616 }
1617
1618 // check name limitations
1620 {
1622 return;
1623 }
1624
1625 // Ensure that there is no character with the desired new name
1627 stmt->setUInt64(0, request.RenameInfo->Guid.GetCounter());
1628 stmt->setString(1, request.RenameInfo->NewName);
1629
1631 .WithPreparedCallback([this, renameInfo = std::move(request.RenameInfo)](PreparedQueryResult result) mutable
1632 {
1633 HandleCharRenameCallBack(std::move(renameInfo), std::move(result));
1634 }));
1635}
1636
1637void WorldSession::HandleCharRenameCallBack(std::shared_ptr<WorldPackets::Character::CharacterRenameInfo> renameInfo, PreparedQueryResult result)
1638{
1639 if (!result)
1640 {
1641 SendCharRename(CHAR_CREATE_ERROR, renameInfo.get());
1642 return;
1643 }
1644
1645 Field* fields = result->Fetch();
1646
1647 std::string oldName = fields[0].GetString();
1648 uint16 atLoginFlags = fields[1].GetUInt16();
1649
1650 if (!(atLoginFlags & AT_LOGIN_RENAME))
1651 {
1652 SendCharRename(CHAR_CREATE_ERROR, renameInfo.get());
1653 return;
1654 }
1655
1656 atLoginFlags &= ~AT_LOGIN_RENAME;
1657
1658 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1659 ObjectGuid::LowType lowGuid = renameInfo->Guid.GetCounter();
1660
1661 // Update name and at_login flag in the db
1663 stmt->setString(0, renameInfo->NewName);
1664 stmt->setUInt16(1, atLoginFlags);
1665 stmt->setUInt64(2, lowGuid);
1666
1667 trans->Append(stmt);
1668
1669 // Removed declined name from db
1670 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_DECLINED_NAME);
1671 stmt->setUInt64(0, lowGuid);
1672
1673 trans->Append(stmt);
1674
1675 CharacterDatabase.CommitTransaction(trans);
1676
1677 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Character:[{}] ({}) Changed name to: {}",
1678 GetAccountId(), GetRemoteAddress(), oldName, renameInfo->Guid.ToString(), renameInfo->NewName);
1679
1680 SendCharRename(RESPONSE_SUCCESS, renameInfo.get());
1681
1682 sCharacterCache->UpdateCharacterData(renameInfo->Guid, renameInfo->NewName);
1683}
1684
1686{
1687 // not accept declined names for unsupported languages
1688 std::string name;
1689 if (!sCharacterCache->GetCharacterNameByGuid(packet.Player, name))
1690 {
1692 return;
1693 }
1694
1695 std::wstring wname;
1696 if (!Utf8toWStr(name, wname))
1697 {
1699 return;
1700 }
1701
1702 if (!isCyrillicCharacter(wname[0])) // name already stored as only single alphabet using
1703 {
1705 return;
1706 }
1707
1708 for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
1709 {
1710 if (!normalizePlayerName(packet.DeclinedNames.name[i]))
1711 {
1713 return;
1714 }
1715 }
1716
1717 if (!ObjectMgr::CheckDeclinedNames(wname, packet.DeclinedNames))
1718 {
1720 return;
1721 }
1722
1723 for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
1724 CharacterDatabase.EscapeString(packet.DeclinedNames.name[i]);
1725
1726 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1727
1729 stmt->setUInt64(0, packet.Player.GetCounter());
1730 trans->Append(stmt);
1731
1732 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_DECLINED_NAME);
1733 stmt->setUInt64(0, packet.Player.GetCounter());
1734
1735 for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; i++)
1736 stmt->setString(i + 1, packet.DeclinedNames.name[i]);
1737
1738 trans->Append(stmt);
1739
1740 CharacterDatabase.CommitTransaction(trans);
1741
1743}
1744
1746{
1748 if (packet.CustomizedChrModelID)
1749 {
1751 if (!conditionalChrModel)
1752 return;
1753
1754 if (ChrCustomizationReqEntry const* req = sChrCustomizationReqStore.LookupEntry(conditionalChrModel->ChrCustomizationReqID))
1755 if (!MeetsChrCustomizationReq(req, Races(packet.CustomizedRace), Classes(_player->GetClass()), false, customizations))
1756 return;
1757
1758 if (PlayerConditionEntry const* condition = sPlayerConditionStore.LookupEntry(conditionalChrModel->PlayerConditionID))
1760 return;
1761 }
1762
1763 if (!ValidateAppearance(Races(_player->GetRace()), Classes(_player->GetClass()), Gender(packet.NewSex), customizations))
1764 return;
1765
1767 if (!go)
1768 {
1770 return;
1771 }
1772
1774 {
1776 return;
1777 }
1778
1779 int64 cost = _player->GetBarberShopCost(customizations);
1780
1781 // 0 - ok
1782 // 1, 3 - not enough money
1783 // 2 - you have to sit on barber chair
1784 if (!_player->HasEnoughMoney(cost))
1785 {
1787 return;
1788 }
1789
1791
1792 _player->ModifyMoney(-cost); // it isn't free
1794
1795 if (_player->GetNativeGender() != packet.NewSex)
1796 {
1799 _player->RestoreDisplayId(false);
1800 }
1801
1803
1805
1807
1808 sCharacterCache->UpdateCharacterGender(_player->GetGUID(), packet.NewSex);
1809}
1810
1812{
1813 if (!IsLegitCharacterForAccount(packet.CustomizeInfo->CharGUID))
1814 {
1815 TC_LOG_ERROR("entities.player.cheat", "Account {}, IP: {} tried to customise {}, but it does not belong to their account!",
1816 GetAccountId(), GetRemoteAddress(), packet.CustomizeInfo->CharGUID.ToString());
1817 KickPlayer("WorldSession::HandleCharCustomize Trying to customise character of another account");
1818 return;
1819 }
1820
1822 stmt->setUInt64(0, packet.CustomizeInfo->CharGUID.GetCounter());
1823
1825 .WithPreparedCallback([this, customizeInfo = std::move(packet.CustomizeInfo)](PreparedQueryResult result) mutable
1826 {
1827 HandleCharCustomizeCallback(std::move(customizeInfo), std::move(result));
1828 }));
1829}
1830
1831void WorldSession::HandleCharCustomizeCallback(std::shared_ptr<WorldPackets::Character::CharCustomizeInfo> customizeInfo, PreparedQueryResult result)
1832{
1833 if (!result)
1834 {
1835 SendCharCustomize(CHAR_CREATE_ERROR, customizeInfo.get());
1836 return;
1837 }
1838
1839 Field* fields = result->Fetch();
1840
1841 std::string oldName = fields[0].GetString();
1842 Races plrRace = Races(fields[1].GetUInt8());
1843 Classes plrClass = Classes(fields[2].GetUInt8());
1844 Gender plrGender = Gender(fields[3].GetUInt8());
1845 uint16 atLoginFlags = fields[4].GetUInt16();
1846
1847 if (!ValidateAppearance(plrRace, plrClass, plrGender, MakeChrCustomizationChoiceRange(customizeInfo->Customizations)))
1848 {
1849 SendCharCustomize(CHAR_CREATE_ERROR, customizeInfo.get());
1850 return;
1851 }
1852
1853 if (!(atLoginFlags & AT_LOGIN_CUSTOMIZE))
1854 {
1855 SendCharCustomize(CHAR_CREATE_ERROR, customizeInfo.get());
1856 return;
1857 }
1858
1859 // prevent character rename
1860 if (sWorld->getBoolConfig(CONFIG_PREVENT_RENAME_CUSTOMIZATION) && (customizeInfo->CharName != oldName))
1861 {
1862 SendCharCustomize(CHAR_NAME_FAILURE, customizeInfo.get());
1863 return;
1864 }
1865
1866 atLoginFlags &= ~AT_LOGIN_CUSTOMIZE;
1867
1868 // prevent character rename to invalid name
1869 if (!normalizePlayerName(customizeInfo->CharName))
1870 {
1871 SendCharCustomize(CHAR_NAME_NO_NAME, customizeInfo.get());
1872 return;
1873 }
1874
1875 ResponseCodes res = ObjectMgr::CheckPlayerName(customizeInfo->CharName, GetSessionDbcLocale(), true);
1876 if (res != CHAR_NAME_SUCCESS)
1877 {
1878 SendCharCustomize(res, customizeInfo.get());
1879 return;
1880 }
1881
1882 // check name limitations
1883 if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(customizeInfo->CharName))
1884 {
1885 SendCharCustomize(CHAR_NAME_RESERVED, customizeInfo.get());
1886 return;
1887 }
1888
1889 // character with this name already exist
1891 ObjectGuid newGuid = sCharacterCache->GetCharacterGuidByName(customizeInfo->CharName);
1892 if (!newGuid.IsEmpty())
1893 {
1894 if (newGuid != customizeInfo->CharGUID)
1895 {
1896 SendCharCustomize(CHAR_CREATE_NAME_IN_USE, customizeInfo.get());
1897 return;
1898 }
1899 }
1900
1901 CharacterDatabasePreparedStatement* stmt = nullptr;
1902 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1903
1904 ObjectGuid::LowType lowGuid = customizeInfo->CharGUID.GetCounter();
1905
1907 Player::SaveCustomizations(trans, lowGuid, MakeChrCustomizationChoiceRange(customizeInfo->Customizations));
1908
1910 {
1911 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_NAME_AT_LOGIN);
1912 stmt->setString(0, customizeInfo->CharName);
1913 stmt->setUInt16(1, atLoginFlags);
1914 stmt->setUInt64(2, lowGuid);
1915
1916 trans->Append(stmt);
1917
1918 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_DECLINED_NAME);
1919 stmt->setUInt64(0, lowGuid);
1920
1921 trans->Append(stmt);
1922 }
1923
1924 CharacterDatabase.CommitTransaction(trans);
1925
1926 sCharacterCache->UpdateCharacterData(customizeInfo->CharGUID, customizeInfo->CharName, customizeInfo->SexID);
1927
1928 SendCharCustomize(RESPONSE_SUCCESS, customizeInfo.get());
1929
1930 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}), Character[{}] ({}) Customized to: {}",
1931 GetAccountId(), GetRemoteAddress(), oldName, customizeInfo->CharGUID.ToString(), customizeInfo->CharName);
1932}
1933
1935{
1936 if (saveEquipmentSet.Set.SetID >= MAX_EQUIPMENT_SET_INDEX) // client set slots amount
1937 return;
1938
1939 if (saveEquipmentSet.Set.Type > EquipmentSetInfo::TRANSMOG)
1940 return;
1941
1942 for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i)
1943 {
1944 if (!(saveEquipmentSet.Set.IgnoreMask & (1 << i)))
1945 {
1946 if (saveEquipmentSet.Set.Type == EquipmentSetInfo::EQUIPMENT)
1947 {
1948 saveEquipmentSet.Set.Appearances[i] = 0;
1949
1950 ObjectGuid const& itemGuid = saveEquipmentSet.Set.Pieces[i];
1951 if (!itemGuid.IsEmpty())
1952 {
1954
1956 if (!item)
1957 return;
1958
1960 if (item->GetGUID() != itemGuid)
1961 return;
1962 }
1963 else
1964 saveEquipmentSet.Set.IgnoreMask |= 1 << i;
1965 }
1966 else
1967 {
1968 saveEquipmentSet.Set.Pieces[i].Clear();
1969 if (saveEquipmentSet.Set.Appearances[i])
1970 {
1971 if (!sItemModifiedAppearanceStore.LookupEntry(saveEquipmentSet.Set.Appearances[i]))
1972 return;
1973
1974 auto [hasAppearance, isTemporary] = GetCollectionMgr()->HasItemAppearance(saveEquipmentSet.Set.Appearances[i]);
1975 if (!hasAppearance)
1976 return;
1977 }
1978 else
1979 saveEquipmentSet.Set.IgnoreMask |= 1 << i;
1980 }
1981 }
1982 else
1983 {
1984 saveEquipmentSet.Set.Pieces[i].Clear();
1985 saveEquipmentSet.Set.Appearances[i] = 0;
1986 }
1987 }
1988
1989 saveEquipmentSet.Set.IgnoreMask &= 0x7FFFF;
1990 if (saveEquipmentSet.Set.Type == EquipmentSetInfo::EQUIPMENT)
1991 {
1992 saveEquipmentSet.Set.Enchants[0] = 0;
1993 saveEquipmentSet.Set.Enchants[1] = 0;
1994 }
1995 else
1996 {
1997 auto validateIllusion = [this](uint32 enchantId) -> bool
1998 {
1999 SpellItemEnchantmentEntry const* illusion = sSpellItemEnchantmentStore.LookupEntry(enchantId);
2000 if (!illusion)
2001 return false;
2002
2003 if (!illusion->ItemVisual || !illusion->GetFlags().HasFlag(SpellItemEnchantmentFlags::AllowTransmog))
2004 return false;
2005
2006 if (PlayerConditionEntry const* condition = sPlayerConditionStore.LookupEntry(illusion->TransmogUseConditionID))
2007 if (!sConditionMgr->IsPlayerMeetingCondition(_player, condition))
2008 return false;
2009
2010 if (illusion->ScalingClassRestricted > 0 && uint8(illusion->ScalingClassRestricted) != _player->GetClass())
2011 return false;
2012
2013 return true;
2014 };
2015
2016 if (saveEquipmentSet.Set.Enchants[0] && !validateIllusion(saveEquipmentSet.Set.Enchants[0]))
2017 return;
2018
2019 if (saveEquipmentSet.Set.Enchants[1] && !validateIllusion(saveEquipmentSet.Set.Enchants[1]))
2020 return;
2021 }
2022
2023 _player->SetEquipmentSet(saveEquipmentSet.Set);
2024}
2025
2027{
2028 _player->DeleteEquipmentSet(deleteEquipmentSet.ID);
2029}
2030
2032{
2033 ObjectGuid ignoredItemGuid;
2034 ignoredItemGuid.SetRawValue(0x0C00040000000000, 0xFFFFFFFFFFFFFFFF);
2035
2036 for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i)
2037 {
2038 TC_LOG_DEBUG("entities.player.items", "{}: ContainerSlot: {}, Slot: {}", useEquipmentSet.Items[i].Item.ToString(), useEquipmentSet.Items[i].ContainerSlot, useEquipmentSet.Items[i].Slot);
2039
2040 // check if item slot is set to "ignored" (raw value == 1), must not be unequipped then
2041 if (useEquipmentSet.Items[i].Item == ignoredItemGuid)
2042 continue;
2043
2044 // Only equip weapons in combat
2046 continue;
2047
2048 Item* item = _player->GetItemByGuid(useEquipmentSet.Items[i].Item);
2049
2050 uint16 dstPos = i | (INVENTORY_SLOT_BAG_0 << 8);
2051
2052 if (!item)
2053 {
2055 if (!uItem)
2056 continue;
2057
2058 ItemPosCountVec itemPosCountVec;
2059 InventoryResult inventoryResult = _player->CanStoreItem(NULL_BAG, NULL_SLOT, itemPosCountVec, uItem, false);
2060 if (inventoryResult == EQUIP_ERR_OK)
2061 {
2062 if (_player->CanUnequipItem(dstPos, true) != EQUIP_ERR_OK)
2063 continue;
2064
2066 _player->StoreItem(itemPosCountVec, uItem, true);
2067 }
2068 else
2069 _player->SendEquipError(inventoryResult, uItem, nullptr);
2070 continue;
2071 }
2072
2073 if (item->GetPos() == dstPos)
2074 continue;
2075
2076 if (_player->CanEquipItem(i, dstPos, item, true) != EQUIP_ERR_OK)
2077 continue;
2078
2079 _player->SwapItem(item->GetPos(), dstPos);
2080 }
2081
2083 result.GUID = useEquipmentSet.GUID;
2084 result.Reason = 0; // 4 - equipment swap failed - inventory is full
2085 SendPacket(result.Write());
2086}
2087
2089{
2091 {
2092 TC_LOG_ERROR("entities.player.cheat", "Account {}, IP: {} tried to factionchange character {}, but it does not belong to their account!",
2093 GetAccountId(), GetRemoteAddress(), packet.RaceOrFactionChangeInfo->Guid.ToString());
2094 KickPlayer("WorldSession::HandleCharFactionOrRaceChange Trying to change faction of character of another account");
2095 return;
2096 }
2097
2099 stmt->setUInt64(0, packet.RaceOrFactionChangeInfo->Guid.GetCounter());
2100
2102 .WithPreparedCallback([this, factionChangeInfo = std::move(packet.RaceOrFactionChangeInfo)](PreparedQueryResult result) mutable
2103 {
2104 HandleCharRaceOrFactionChangeCallback(std::move(factionChangeInfo), std::move(result));
2105 }));
2106}
2107
2108void WorldSession::HandleCharRaceOrFactionChangeCallback(std::shared_ptr<WorldPackets::Character::CharRaceOrFactionChangeInfo> factionChangeInfo, PreparedQueryResult result)
2109{
2110 if (!result)
2111 {
2112 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2113 return;
2114 }
2115
2116 // get the players old (at this moment current) race
2117 CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(factionChangeInfo->Guid);
2118 if (!characterInfo)
2119 {
2120 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2121 return;
2122 }
2123
2124 std::string oldName = characterInfo->Name;
2125 uint8 oldRace = characterInfo->Race;
2126 uint8 playerClass = characterInfo->Class;
2127 uint8 level = characterInfo->Level;
2128
2129 if (!sObjectMgr->GetPlayerInfo(factionChangeInfo->RaceID, playerClass))
2130 {
2131 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2132 return;
2133 }
2134
2135 Field* fields = result->Fetch();
2136 uint16 atLoginFlags = fields[0].GetUInt16();
2137 std::string knownTitlesStr = fields[1].GetString();
2138 uint32 groupId = !fields[2].IsNull() ? fields[2].GetUInt32() : 0;
2139
2140 uint16 usedLoginFlag = (factionChangeInfo->FactionChange ? AT_LOGIN_CHANGE_FACTION : AT_LOGIN_CHANGE_RACE);
2141 if (!(atLoginFlags & usedLoginFlag))
2142 {
2143 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2144 return;
2145 }
2146
2147 TeamId newTeamId = Player::TeamIdForRace(factionChangeInfo->RaceID);
2148 if (newTeamId == TEAM_NEUTRAL)
2149 {
2151 return;
2152 }
2153
2154 if (factionChangeInfo->FactionChange == (Player::TeamIdForRace(oldRace) == newTeamId))
2155 {
2156 SendCharFactionChange(factionChangeInfo->FactionChange ? CHAR_CREATE_CHARACTER_SWAP_FACTION : CHAR_CREATE_CHARACTER_RACE_ONLY, factionChangeInfo.get());
2157 return;
2158 }
2159
2161 {
2163 if (raceMaskDisabled.HasRace(factionChangeInfo->RaceID))
2164 {
2165 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2166 return;
2167 }
2168 }
2169
2170 // prevent character rename
2171 if (sWorld->getBoolConfig(CONFIG_PREVENT_RENAME_CUSTOMIZATION) && (factionChangeInfo->Name != oldName))
2172 {
2173 SendCharFactionChange(CHAR_NAME_FAILURE, factionChangeInfo.get());
2174 return;
2175 }
2176
2177 // prevent character rename to invalid name
2178 if (!normalizePlayerName(factionChangeInfo->Name))
2179 {
2180 SendCharFactionChange(CHAR_NAME_NO_NAME, factionChangeInfo.get());
2181 return;
2182 }
2183
2184 ResponseCodes res = ObjectMgr::CheckPlayerName(factionChangeInfo->Name, GetSessionDbcLocale(), true);
2185 if (res != CHAR_NAME_SUCCESS)
2186 {
2187 SendCharFactionChange(res, factionChangeInfo.get());
2188 return;
2189 }
2190
2191 // check name limitations
2192 if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(factionChangeInfo->Name))
2193 {
2194 SendCharFactionChange(CHAR_NAME_RESERVED, factionChangeInfo.get());
2195 return;
2196 }
2197
2198 // character with this name already exist
2199 ObjectGuid newGuid = sCharacterCache->GetCharacterGuidByName(factionChangeInfo->Name);
2200 if (!newGuid.IsEmpty())
2201 {
2202 if (newGuid != factionChangeInfo->Guid)
2203 {
2204 SendCharFactionChange(CHAR_CREATE_NAME_IN_USE, factionChangeInfo.get());
2205 return;
2206 }
2207 }
2208
2209 if (sArenaTeamMgr->GetArenaTeamByCaptain(factionChangeInfo->Guid))
2210 {
2212 return;
2213 }
2214
2215 // All checks are fine, deal with race change now
2216 ObjectGuid::LowType lowGuid = factionChangeInfo->Guid.GetCounter();
2217
2218 CharacterDatabasePreparedStatement* stmt = nullptr;
2219 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
2220
2221 // resurrect the character in case he's dead
2222 Player::OfflineResurrect(factionChangeInfo->Guid, trans);
2223
2224 // Name Change and update atLogin flags
2225 {
2226 CharacterDatabase.EscapeString(factionChangeInfo->Name);
2227
2228 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_NAME_AT_LOGIN);
2229 stmt->setString(0, factionChangeInfo->Name);
2230 stmt->setUInt16(1, uint16((atLoginFlags | AT_LOGIN_RESURRECT) & ~usedLoginFlag));
2231 stmt->setUInt64(2, lowGuid);
2232
2233 trans->Append(stmt);
2234
2235 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_DECLINED_NAME);
2236 stmt->setUInt64(0, lowGuid);
2237
2238 trans->Append(stmt);
2239 }
2240
2241 // Customize
2242 Player::SaveCustomizations(trans, lowGuid, MakeChrCustomizationChoiceRange(factionChangeInfo->Customizations));
2243
2244 // Race Change
2245 {
2246 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_RACE);
2247 stmt->setUInt8(0, factionChangeInfo->RaceID);
2249 stmt->setUInt64(2, lowGuid);
2250
2251 trans->Append(stmt);
2252 }
2253
2254 sCharacterCache->UpdateCharacterData(factionChangeInfo->Guid, factionChangeInfo->Name, factionChangeInfo->SexID, factionChangeInfo->RaceID);
2255
2256 if (oldRace != factionChangeInfo->RaceID)
2257 {
2258 // Switch Languages
2259 // delete all languages first
2260 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SKILL_LANGUAGES);
2261 stmt->setUInt64(0, lowGuid);
2262 trans->Append(stmt);
2263
2264 // Now add them back
2265 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_SKILL_LANGUAGE);
2266 stmt->setUInt64(0, lowGuid);
2267
2268 // Faction specific languages
2269 if (newTeamId == TEAM_HORDE)
2270 stmt->setUInt16(1, 109);
2271 else
2272 stmt->setUInt16(1, 98);
2273
2274 trans->Append(stmt);
2275
2276 // Race specific languages
2277 std::array<uint8, 4> const racesWithoutSpecificLanguages = { RACE_ORC, RACE_HUMAN, RACE_MAGHAR_ORC, RACE_KUL_TIRAN };
2278 if (std::find(racesWithoutSpecificLanguages.begin(), racesWithoutSpecificLanguages.end(), factionChangeInfo->RaceID) == racesWithoutSpecificLanguages.end())
2279 {
2280 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_SKILL_LANGUAGE);
2281 stmt->setUInt64(0, lowGuid);
2282
2283 switch (factionChangeInfo->RaceID)
2284 {
2285 case RACE_DWARF:
2287 stmt->setUInt16(1, 111);
2288 break;
2289 case RACE_DRAENEI:
2291 stmt->setUInt16(1, 759);
2292 break;
2293 case RACE_GNOME:
2294 case RACE_MECHAGNOME:
2295 stmt->setUInt16(1, 313);
2296 break;
2297 case RACE_NIGHTELF:
2298 stmt->setUInt16(1, 113);
2299 break;
2300 case RACE_WORGEN:
2301 stmt->setUInt16(1, 791);
2302 break;
2303 case RACE_UNDEAD_PLAYER:
2304 stmt->setUInt16(1, 673);
2305 break;
2306 case RACE_TAUREN:
2308 stmt->setUInt16(1, 115);
2309 break;
2310 case RACE_TROLL:
2312 stmt->setUInt16(1, 315);
2313 break;
2314 case RACE_BLOODELF:
2315 case RACE_VOID_ELF:
2316 stmt->setUInt16(1, 137);
2317 break;
2318 case RACE_GOBLIN:
2319 stmt->setUInt16(1, 792);
2320 break;
2321 case RACE_NIGHTBORNE:
2322 stmt->setUInt16(1, 2464);
2323 break;
2324 case RACE_VULPERA:
2325 stmt->setUInt16(1, 2776);
2326 break;
2329 stmt->setUInt16(1, 905);
2330 break;
2333 stmt->setUInt16(1, 138);
2334 break;
2335 default:
2336 TC_LOG_ERROR("entities.player", "Could not find language data for race ({}).", factionChangeInfo->RaceID);
2337 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2338 return;
2339 }
2340
2341 trans->Append(stmt);
2342 }
2343
2344 // Team Conversion
2345 if (factionChangeInfo->FactionChange)
2346 {
2347 // Delete all Flypaths
2348 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TAXI_PATH);
2349 stmt->setUInt64(0, lowGuid);
2350 trans->Append(stmt);
2351
2352 if (level > 7)
2353 {
2354 // Update Taxi path
2355 // this doesn't seem to be 100% blizzlike... but it can't really be helped.
2356 std::ostringstream taximaskstream;
2357 TaxiMask const& factionMask = newTeamId == TEAM_HORDE ? sHordeTaxiNodesMask : sAllianceTaxiNodesMask;
2358 for (std::size_t i = 0; i < factionMask.size(); ++i)
2359 {
2360 // i = (315 - 1) / 8 = 39
2361 // m = 1 << ((315 - 1) % 8) = 4
2362 uint8 deathKnightExtraNode = playerClass != CLASS_DEATH_KNIGHT || i != 39 ? 0 : 4;
2363 taximaskstream << uint32(factionMask[i] | deathKnightExtraNode) << ' ';
2364 }
2365
2366 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TAXIMASK);
2367 stmt->setString(0, taximaskstream.str());
2368 stmt->setUInt64(1, lowGuid);
2369 trans->Append(stmt);
2370 }
2371
2373 {
2374 // Reset guild
2375 if (Guild* guild = sGuildMgr->GetGuildById(characterInfo->GuildId))
2376 guild->DeleteMember(trans, factionChangeInfo->Guid, false, false);
2377
2378 Player::LeaveAllArenaTeams(factionChangeInfo->Guid);
2379 }
2380
2381 if (groupId && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
2382 {
2383 if (Group* group = sGroupMgr->GetGroupByDbStoreId(groupId))
2384 group->RemoveMember(factionChangeInfo->Guid);
2385 }
2386
2388 {
2389 // Delete Friend List
2390 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SOCIAL_BY_GUID);
2391 stmt->setUInt64(0, lowGuid);
2392 trans->Append(stmt);
2393
2394 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SOCIAL_BY_FRIEND);
2395 stmt->setUInt64(0, lowGuid);
2396 trans->Append(stmt);
2397 }
2398
2399 // Reset homebind and position
2400 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_HOMEBIND);
2401 stmt->setUInt64(0, lowGuid);
2402 trans->Append(stmt);
2403
2404 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PLAYER_HOMEBIND);
2405 stmt->setUInt64(0, lowGuid);
2406
2407 WorldLocation loc;
2408 uint16 zoneId = 0;
2409 if (newTeamId == TEAM_ALLIANCE)
2410 {
2411 loc.WorldRelocate(0, -8867.68f, 673.373f, 97.9034f, 0.0f);
2412 zoneId = 1519;
2413 }
2414 else
2415 {
2416 loc.WorldRelocate(1, 1633.33f, -4439.11f, 15.7588f, 0.0f);
2417 zoneId = 1637;
2418 }
2419
2420 stmt->setUInt16(1, loc.GetMapId());
2421 stmt->setUInt16(2, zoneId);
2422 stmt->setFloat(3, loc.GetPositionX());
2423 stmt->setFloat(4, loc.GetPositionY());
2424 stmt->setFloat(5, loc.GetPositionZ());
2425 trans->Append(stmt);
2426
2427 Player::SavePositionInDB(loc, zoneId, factionChangeInfo->Guid, trans);
2428
2429 // Achievement conversion
2430 for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChangeAchievements.begin(); it != sObjectMgr->FactionChangeAchievements.end(); ++it)
2431 {
2432 uint32 achiev_alliance = it->first;
2433 uint32 achiev_horde = it->second;
2434
2436 stmt->setUInt16(0, uint16(newTeamId == TEAM_ALLIANCE ? achiev_alliance : achiev_horde));
2437 stmt->setUInt64(1, lowGuid);
2438 trans->Append(stmt);
2439
2440 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_ACHIEVEMENT);
2441 stmt->setUInt32(0, uint16(newTeamId == TEAM_ALLIANCE ? achiev_alliance : achiev_horde));
2442 stmt->setUInt32(1, uint16(newTeamId == TEAM_ALLIANCE ? achiev_horde : achiev_alliance));
2443 stmt->setUInt64(2, lowGuid);
2444 trans->Append(stmt);
2445 }
2446
2447 // Item conversion
2448 ObjectMgr::CharacterConversionMap const& itemConversionMap = newTeamId == TEAM_ALLIANCE
2449 ? sObjectMgr->FactionChangeItemsHordeToAlliance
2450 : sObjectMgr->FactionChangeItemsAllianceToHorde;
2451 for (std::map<uint32, uint32>::const_iterator it = itemConversionMap.begin(); it != itemConversionMap.end(); ++it)
2452 {
2453 uint32 oldItemId = it->first;
2454 uint32 newItemId = it->second;
2455
2456 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_INVENTORY_FACTION_CHANGE);
2457 stmt->setUInt32(0, newItemId);
2458 stmt->setUInt32(1, oldItemId);
2459 stmt->setUInt64(2, lowGuid);
2460 trans->Append(stmt);
2461 }
2462
2463 // Delete all current quests
2464 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS);
2465 stmt->setUInt64(0, lowGuid);
2466 trans->Append(stmt);
2467
2468 // Quest conversion
2469 for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChangeQuests.begin(); it != sObjectMgr->FactionChangeQuests.end(); ++it)
2470 {
2471 uint32 quest_alliance = it->first;
2472 uint32 quest_horde = it->second;
2473
2475 stmt->setUInt64(0, lowGuid);
2476 stmt->setUInt32(1, (newTeamId == TEAM_ALLIANCE ? quest_alliance : quest_horde));
2477 trans->Append(stmt);
2478
2480 stmt->setUInt32(0, (newTeamId == TEAM_ALLIANCE ? quest_alliance : quest_horde));
2481 stmt->setUInt32(1, (newTeamId == TEAM_ALLIANCE ? quest_horde : quest_alliance));
2482 stmt->setUInt64(2, lowGuid);
2483 trans->Append(stmt);
2484 }
2485
2486 // Mark all rewarded quests as "active" (will count for completed quests achievements)
2488 stmt->setUInt64(0, lowGuid);
2489 trans->Append(stmt);
2490
2491 // Disable all old-faction specific quests
2492 {
2493 ObjectMgr::QuestContainer const& questTemplates = sObjectMgr->GetQuestTemplates();
2494 for (auto const& [questId, quest] : questTemplates)
2495 {
2497 if (quest->GetAllowableRaces().RawValue != uint64(-1) && (quest->GetAllowableRaces() & newRaceMask).IsEmpty())
2498 {
2500 stmt->setUInt64(0, lowGuid);
2501 stmt->setUInt32(1, questId);
2502 trans->Append(stmt);
2503 }
2504 }
2505 }
2506
2507 // Spell conversion
2508 for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChangeSpells.begin(); it != sObjectMgr->FactionChangeSpells.end(); ++it)
2509 {
2510 uint32 spell_alliance = it->first;
2511 uint32 spell_horde = it->second;
2512
2513 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_BY_SPELL);
2514 stmt->setUInt32(0, (newTeamId == TEAM_ALLIANCE ? spell_alliance : spell_horde));
2515 stmt->setUInt64(1, lowGuid);
2516 trans->Append(stmt);
2517
2518 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_SPELL_FACTION_CHANGE);
2519 stmt->setUInt32(0, (newTeamId == TEAM_ALLIANCE ? spell_alliance : spell_horde));
2520 stmt->setUInt32(1, (newTeamId == TEAM_ALLIANCE ? spell_horde : spell_alliance));
2521 stmt->setUInt64(2, lowGuid);
2522 trans->Append(stmt);
2523 }
2524
2525 // Reputation conversion
2526 for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChangeReputation.begin(); it != sObjectMgr->FactionChangeReputation.end(); ++it)
2527 {
2528 uint32 reputation_alliance = it->first;
2529 uint32 reputation_horde = it->second;
2530 uint32 newReputation = (newTeamId == TEAM_ALLIANCE) ? reputation_alliance : reputation_horde;
2531 uint32 oldReputation = (newTeamId == TEAM_ALLIANCE) ? reputation_horde : reputation_alliance;
2532
2533 // select old standing set in db
2534 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_REP_BY_FACTION);
2535 stmt->setUInt32(0, oldReputation);
2536 stmt->setUInt64(1, lowGuid);
2537
2538 if (PreparedQueryResult reputationResult = CharacterDatabase.Query(stmt))
2539 {
2540 fields = reputationResult->Fetch();
2541 int32 oldDBRep = fields[0].GetInt32();
2542 FactionEntry const* factionEntry = sFactionStore.LookupEntry(oldReputation);
2543
2544 // old base reputation
2545 int32 oldBaseRep = sObjectMgr->GetBaseReputationOf(factionEntry, oldRace, playerClass);
2546
2547 // new base reputation
2548 int32 newBaseRep = sObjectMgr->GetBaseReputationOf(sFactionStore.LookupEntry(newReputation), factionChangeInfo->RaceID, playerClass);
2549
2550 // final reputation shouldnt change
2551 int32 FinalRep = oldDBRep + oldBaseRep;
2552 int32 newDBRep = FinalRep - newBaseRep;
2553
2554 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_REP_BY_FACTION);
2555 stmt->setUInt32(0, newReputation);
2556 stmt->setUInt64(1, lowGuid);
2557 trans->Append(stmt);
2558
2559 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_REP_FACTION_CHANGE);
2560 stmt->setUInt16(0, uint16(newReputation));
2561 stmt->setInt32(1, newDBRep);
2562 stmt->setUInt16(2, uint16(oldReputation));
2563 stmt->setUInt64(3, lowGuid);
2564 trans->Append(stmt);
2565 }
2566 }
2567
2568 // Title conversion
2569 if (!knownTitlesStr.empty())
2570 {
2571 std::vector<std::string_view> tokens = Trinity::Tokenize(knownTitlesStr, ' ', false);
2572 std::vector<uint32> knownTitles;
2573
2574 for (std::string_view token : tokens)
2575 {
2576 if (Optional<uint32> thisMask = Trinity::StringTo<uint32>(token))
2577 knownTitles.push_back(*thisMask);
2578 else
2579 {
2580 TC_LOG_WARN("entities.player", "{} has invalid title data '{}' - skipped, this may result in titles being lost",
2581 GetPlayerInfo(), token);
2582 knownTitles.push_back(0);
2583 }
2584 }
2585
2586 for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChangeTitles.begin(); it != sObjectMgr->FactionChangeTitles.end(); ++it)
2587 {
2588 uint32 title_alliance = it->first;
2589 uint32 title_horde = it->second;
2590
2591 CharTitlesEntry const* atitleInfo = sCharTitlesStore.AssertEntry(title_alliance);
2592 CharTitlesEntry const* htitleInfo = sCharTitlesStore.AssertEntry(title_horde);
2593 // new team
2594 if (newTeamId == TEAM_ALLIANCE)
2595 {
2596 uint32 bitIndex = htitleInfo->MaskID;
2597 uint32 index = bitIndex / 32;
2598 if (index >= knownTitles.size())
2599 continue;
2600
2601 uint32 old_flag = 1 << (bitIndex % 32);
2602 uint32 new_flag = 1 << (atitleInfo->MaskID % 32);
2603 if (knownTitles[index] & old_flag)
2604 {
2605 knownTitles[index] &= ~old_flag;
2606 // use index of the new title
2607 knownTitles[atitleInfo->MaskID / 32] |= new_flag;
2608 }
2609 }
2610 else
2611 {
2612 uint32 bitIndex = htitleInfo->MaskID;
2613 uint32 index = bitIndex / 32;
2614 if (index >= knownTitles.size())
2615 continue;
2616
2617 uint32 old_flag = 1 << (bitIndex % 32);
2618 uint32 new_flag = 1 << (htitleInfo->MaskID % 32);
2619 if (knownTitles[index] & old_flag)
2620 {
2621 knownTitles[index] &= ~old_flag;
2622 // use index of the new title
2623 knownTitles[htitleInfo->MaskID / 32] |= new_flag;
2624 }
2625 }
2626
2627 std::ostringstream ss;
2628 for (uint32 mask : knownTitles)
2629 ss << mask << ' ';
2630
2631 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TITLES_FACTION_CHANGE);
2632 stmt->setString(0, ss.str());
2633 stmt->setUInt64(1, lowGuid);
2634 trans->Append(stmt);
2635
2636 // unset any currently chosen title
2637 stmt = CharacterDatabase.GetPreparedStatement(CHAR_RES_CHAR_TITLES_FACTION_CHANGE);
2638 stmt->setUInt64(0, lowGuid);
2639 trans->Append(stmt);
2640 }
2641 }
2642 }
2643 }
2644
2645 CharacterDatabase.CommitTransaction(trans);
2646
2647 TC_LOG_DEBUG("entities.player", "{} (IP: {}) changed race from {} to {}", GetPlayerInfo(), GetRemoteAddress(), oldRace, factionChangeInfo->RaceID);
2648
2649 SendCharFactionChange(RESPONSE_SUCCESS, factionChangeInfo.get());
2650}
2651
2653{
2654 if (!Player::IsValidRace(packet.Race))
2655 {
2656 TC_LOG_ERROR("misc", "Invalid race ({}) sent by accountId: {}", packet.Race, GetAccountId());
2657 return;
2658 }
2659
2660 if (!Player::IsValidGender(packet.Sex))
2661 {
2662 TC_LOG_ERROR("misc", "Invalid gender ({}) sent by accountId: {}", packet.Sex, GetAccountId());
2663 return;
2664 }
2665
2667 result.Success = true;
2668 result.Name = sDB2Manager.GetNameGenEntry(packet.Race, packet.Sex);
2669
2670 SendPacket(result.Write());
2671}
2672
2674{
2675 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
2676
2677 for (WorldPackets::Character::ReorderCharacters::ReorderInfo const& reorderInfo : reorderChars.Entries)
2678 {
2680 stmt->setUInt8(0, reorderInfo.NewPosition);
2681 stmt->setUInt64(1, reorderInfo.PlayerGUID.GetCounter());
2682 stmt->setUInt32(2, GetAccountId());
2683 trans->Append(stmt);
2684 }
2685
2686 CharacterDatabase.CommitTransaction(trans);
2687}
2688
2690{
2691 // Only players that has not yet gained any experience can use this
2692 if (*_player->m_activePlayerData->XP)
2693 return;
2694
2695 if (ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(_player->GetClass()))
2696 {
2697 if (classEntry->CinematicSequenceID)
2698 _player->SendCinematicStart(classEntry->CinematicSequenceID);
2699 else if (ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(_player->GetRace()))
2700 _player->SendCinematicStart(raceEntry->CinematicSequenceID);
2701 }
2702}
2703
2705{
2707 stmt->setUInt32(0, GetBattlenetAccountId());
2708
2709 _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback([this](PreparedQueryResult result)
2710 {
2711 HandleUndeleteCooldownStatusCallback(std::move(result));
2712 }));
2713}
2714
2716{
2717 uint32 cooldown = 0;
2719 if (result)
2720 {
2721 uint32 lastUndelete = result->Fetch()[0].GetUInt32();
2723 if (lastUndelete + maxCooldown > now)
2724 cooldown = std::max<uint32>(0, lastUndelete + maxCooldown - now);
2725 }
2726
2727 SendUndeleteCooldownStatusResponse(cooldown, maxCooldown);
2728}
2729
2731{
2733 {
2735 return;
2736 }
2737
2739 stmt->setUInt32(0, GetBattlenetAccountId());
2740
2741 std::shared_ptr<WorldPackets::Character::CharacterUndeleteInfo> undeleteInfo = undeleteCharacter.UndeleteInfo;
2743 .WithChainingPreparedCallback([this, undeleteInfo](QueryCallback& queryCallback, PreparedQueryResult result)
2744 {
2745 if (result)
2746 {
2747 uint32 lastUndelete = result->Fetch()[0].GetUInt32();
2748 uint32 maxCooldown = sWorld->getIntConfig(CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_COOLDOWN);
2749 if (lastUndelete && (lastUndelete + maxCooldown > GameTime::GetGameTime()))
2750 {
2751 SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_COOLDOWN, undeleteInfo.get());
2752 return;
2753 }
2754 }
2755
2757 stmt->setUInt64(0, undeleteInfo->CharacterGuid.GetCounter());
2758 queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt));
2759 })
2760 .WithChainingPreparedCallback([this, undeleteInfo](QueryCallback& queryCallback, PreparedQueryResult result)
2761 {
2762 if (!result)
2763 {
2764 SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_CHAR_CREATE, undeleteInfo.get());
2765 return;
2766 }
2767
2768 Field* fields = result->Fetch();
2769 undeleteInfo->Name = fields[1].GetString();
2770 uint32 account = fields[2].GetUInt32();
2771
2772 if (account != GetAccountId())
2773 {
2774 SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_UNKNOWN, undeleteInfo.get());
2775 return;
2776 }
2777
2779 stmt->setString(0, undeleteInfo->Name);
2780 queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt));
2781 })
2782 .WithChainingPreparedCallback([this, undeleteInfo](QueryCallback& queryCallback, PreparedQueryResult result)
2783 {
2784 if (result)
2785 {
2786 SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_NAME_TAKEN_BY_THIS_ACCOUNT, undeleteInfo.get());
2787 return;
2788 }
2789
2795
2797 stmt->setUInt32(0, GetAccountId());
2798 queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt));
2799 })
2800 .WithPreparedCallback([this, undeleteInfo](PreparedQueryResult result)
2801 {
2802 if (result)
2803 {
2804 Field* fields = result->Fetch();
2805
2806 if (fields[0].GetUInt64() >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM)) // SQL's COUNT() returns uint64 but it will always be less than uint8.Max
2807 {
2808 SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_CHAR_CREATE, undeleteInfo.get());
2809 return;
2810 }
2811 }
2812
2814 stmt->setString(0, undeleteInfo->Name);
2815 stmt->setUInt32(1, GetAccountId());
2816 stmt->setUInt64(2, undeleteInfo->CharacterGuid.GetCounter());
2817 CharacterDatabase.Execute(stmt);
2818
2820 loginStmt->setUInt32(0, GetBattlenetAccountId());
2821 LoginDatabase.Execute(loginStmt);
2822
2823 sCharacterCache->UpdateCharacterInfoDeleted(undeleteInfo->CharacterGuid, false, undeleteInfo->Name);
2824
2825 SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_OK, undeleteInfo.get());
2826 }));
2827}
2828
2830{
2832 {
2834 return;
2835 }
2836
2837 if (!EmblemInfo::ValidateEmblemColors(savePersonalEmblem.PersonalTabard.EmblemStyle, savePersonalEmblem.PersonalTabard.EmblemColor,
2838 savePersonalEmblem.PersonalTabard.BorderStyle, savePersonalEmblem.PersonalTabard.BorderColor,
2839 savePersonalEmblem.PersonalTabard.BackgroundColor))
2840 {
2842 return;
2843 }
2844
2845 _player->SetPersonalTabard(savePersonalEmblem.PersonalTabard.EmblemStyle, savePersonalEmblem.PersonalTabard.EmblemColor,
2846 savePersonalEmblem.PersonalTabard.BorderStyle, savePersonalEmblem.PersonalTabard.BorderColor,
2847 savePersonalEmblem.PersonalTabard.BackgroundColor);
2848
2850}
2851
2852void WorldSession::SendCharCreate(ResponseCodes result, ObjectGuid const& guid /*= ObjectGuid::Empty*/)
2853{
2855 response.Code = result;
2856 response.Guid = guid;
2857
2858 SendPacket(response.Write());
2859}
2860
2862{
2864 response.Code = result;
2865
2866 SendPacket(response.Write());
2867}
2868
2870{
2872 packet.Result = result;
2873 packet.Name = renameInfo->NewName;
2874 if (result == RESPONSE_SUCCESS)
2875 packet.Guid = renameInfo->Guid;
2876
2877 SendPacket(packet.Write());
2878}
2879
2881{
2882 if (result == RESPONSE_SUCCESS)
2883 {
2884 WorldPackets::Character::CharCustomizeSuccess response(customizeInfo);
2885 SendPacket(response.Write());
2886 }
2887 else
2888 {
2890 failed.Result = uint8(result);
2891 failed.CharGUID = customizeInfo->CharGUID;
2892 SendPacket(failed.Write());
2893 }
2894}
2895
2897{
2899 packet.Result = result;
2900 packet.Guid = factionChangeInfo->Guid;
2901
2902 if (result == RESPONSE_SUCCESS)
2903 {
2904 packet.Display.emplace();
2905 packet.Display->Name = factionChangeInfo->Name;
2906 packet.Display->SexID = factionChangeInfo->SexID;
2907 packet.Display->Customizations = &factionChangeInfo->Customizations;
2908 packet.Display->RaceID = factionChangeInfo->RaceID;
2909 }
2910
2911 SendPacket(packet.Write());
2912}
2913
2915{
2917 packet.ResultCode = result;
2918 packet.Player = guid;
2919
2920 SendPacket(packet.Write());
2921}
2922
2924{
2926 response.OnCooldown = (currentCooldown > 0);
2927 response.MaxCooldown = maxCooldown;
2928 response.CurrentCooldown = currentCooldown;
2929
2930 SendPacket(response.Write());
2931}
2932
2934{
2936 response.UndeleteInfo = undeleteInfo;
2937 response.Result = result;
2938
2939 SendPacket(response.Write());
2940}
#define sArenaTeamMgr
Definition: ArenaTeamMgr.h:53
#define sCalendarMgr
Definition: CalendarMgr.h:370
#define sCharacterCache
CharacterDatabaseStatements
@ CHAR_SEL_CHARACTER_GARRISON_BUILDINGS
@ CHAR_SEL_CHAR_CUSTOMIZE_INFO
@ CHAR_DEL_CHAR_SOCIAL_BY_FRIEND
@ CHAR_SEL_CHAR_TRAIT_CONFIGS
@ CHAR_UPD_CHAR_INVENTORY_FACTION_CHANGE
@ CHAR_SEL_CHECK_NAME
@ CHAR_SEL_CHARACTER_PVP_TALENTS
@ CHAR_UPD_CHAR_ONLINE
@ CHAR_DEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST
@ CHAR_SEL_CHARACTER
@ CHAR_SEL_PLAYER_CURRENCY
@ CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES_CRITERIA_PROGRESS
@ CHAR_SEL_CHARACTER_QUESTSTATUSREW
@ CHAR_SEL_PLAYER_ACCOUNT_DATA
@ CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_FACTION_CHANGE
@ CHAR_DEL_CHAR_SKILL_LANGUAGES
@ CHAR_SEL_CHARACTER_GARRISON
@ CHAR_SEL_CHARACTER_AURAS
@ CHAR_SEL_CHAR_PETS
@ CHAR_SEL_MAILITEMS_AZERITE
@ CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES
@ CHAR_UPD_CHAR_ACHIEVEMENT
@ CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES_CRITERIA
@ CHAR_DEL_CHAR_DECLINED_NAME
@ CHAR_SEL_MAILITEMS_AZERITE_MILESTONE_POWER
@ CHAR_SEL_MAILITEMS_AZERITE_UNLOCKED_ESSENCE
@ CHAR_SEL_CHAR_RACE_OR_FACTION_CHANGE_INFOS
@ CHAR_SEL_CHARACTER_QUESTSTATUS_MONTHLY
@ CHAR_SEL_MAILITEMS
@ CHAR_SEL_CHAR_VOID_STORAGE
@ CHAR_INS_PLAYER_HOMEBIND
@ CHAR_INS_CHAR_SKILL_LANGUAGE
@ CHAR_SEL_CHARACTER_BGDATA
@ CHAR_SEL_CHARACTER_SOCIALLIST
@ CHAR_UPD_CHAR_SPELL_FACTION_CHANGE
@ CHAR_UPD_CHAR_TAXI_PATH
@ CHAR_UPD_CHAR_TAXIMASK
@ CHAR_DEL_ALL_PET_SPELLS_BY_OWNER
@ CHAR_SEL_CHAR_TRAIT_ENTRIES
@ CHAR_SEL_CHARACTER_QUESTSTATUS_WEEKLY
@ CHAR_DEL_PLAYER_HOMEBIND
@ CHAR_SEL_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE
@ CHAR_SEL_ENUM_CUSTOMIZATIONS
@ CHAR_SEL_CHARACTER_GARRISON_FOLLOWER_ABILITIES
@ CHAR_SEL_ITEM_INSTANCE_AZERITE_EMPOWERED
@ CHAR_SEL_CHAR_REP_BY_FACTION
@ CHAR_SEL_CHARACTER_HOMEBIND
@ CHAR_SEL_FREE_NAME
@ CHAR_SEL_ENUM
@ CHAR_SEL_SUM_CHARS
@ CHAR_SEL_GROUP_MEMBER
@ CHAR_SEL_UNDELETE_ENUM_DECLINED_NAME
@ CHAR_UPD_CHAR_LIST_SLOT
@ CHAR_SEL_ITEM_INSTANCE_AZERITE_MILESTONE_POWER
@ CHAR_DEL_CHAR_SPELL_BY_SPELL
@ CHAR_SEL_CHAR_CREATE_INFO
@ CHAR_SEL_CHARACTER_INVENTORY
@ CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST
@ CHAR_UPD_PET_SPECS_BY_OWNER
@ CHAR_SEL_MAILITEMS_ARTIFACT
@ CHAR_SEL_CHARACTER_QUESTSTATUS
@ CHAR_SEL_CHAR_DEL_INFO_BY_GUID
@ CHAR_DEL_CHAR_ACHIEVEMENT_BY_ACHIEVEMENT
@ CHAR_SEL_CHARACTER_TALENTS
@ CHAR_SEL_CHAR_CUF_PROFILES
@ CHAR_SEL_MAIL
@ CHAR_SEL_CHARACTER_SPELL_FAVORITES
@ CHAR_SEL_UNDELETE_ENUM
@ CHAR_SEL_CORPSE_LOCATION
@ CHAR_SEL_CHARACTER_CRITERIAPROGRESS
@ CHAR_SEL_CHARACTER_GLYPHS
@ CHAR_SEL_CHARACTER_REPUTATION
@ CHAR_DEL_CHAR_QUESTSTATUS
@ CHAR_SEL_CHARACTER_SPELL
@ CHAR_UPD_CHAR_REP_FACTION_CHANGE
@ CHAR_SEL_CHARACTER_QUESTSTATUS_SEASONAL
@ CHAR_UPD_CHAR_RACE
@ CHAR_SEL_CHARACTER_RANDOMBG
@ CHAR_SEL_CHARACTER_EQUIPMENTSETS
@ CHAR_SEL_CHARACTER_SKILLS
@ CHAR_SEL_CHARACTER_QUESTSTATUS_DAILY
@ CHAR_UPD_CHAR_TITLES_FACTION_CHANGE
@ CHAR_DEL_CHAR_REP_BY_FACTION
@ CHAR_SEL_ENUM_DECLINED_NAME
@ CHAR_SEL_CHARACTER_SPELLCOOLDOWNS
@ CHAR_UPD_ADD_AT_LOGIN_FLAG
@ CHAR_RES_CHAR_TITLES_FACTION_CHANGE
@ CHAR_SEL_CHARACTER_AURA_STORED_LOCATIONS
@ CHAR_SEL_CHARACTER_TRANSMOG_OUTFITS
@ CHAR_SEL_UNDELETE_ENUM_CUSTOMIZATIONS
@ CHAR_SEL_CHARACTER_GARRISON_BLUEPRINTS
@ CHAR_SEL_ITEM_INSTANCE_AZERITE
@ CHAR_SEL_CHARACTER_SPELL_CHARGES
@ CHAR_SEL_CHARACTER_AURA_EFFECTS
@ CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE
@ CHAR_DEL_CHAR_SOCIAL_BY_GUID
@ CHAR_SEL_CHARACTER_ACHIEVEMENTS
@ CHAR_SEL_MAILITEMS_AZERITE_EMPOWERED
@ CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES
@ CHAR_DEL_EXPIRED_BANS
@ CHAR_SEL_CHARACTER_GARRISON_FOLLOWERS
@ CHAR_UPD_RESTORE_DELETE_INFO
@ CHAR_SEL_ITEM_INSTANCE_ARTIFACT
@ CHAR_SEL_GUILD_MEMBER
@ CHAR_SEL_CHARACTER_DECLINEDNAMES
@ CHAR_SEL_CHARACTER_ARENAINFO
@ CHAR_UPD_CHAR_NAME_AT_LOGIN
@ CHAR_INS_CHAR_DECLINED_NAME
@ CHAR_SEL_CHARACTER_BANNED
@ CHAR_SEL_CHARACTER_CUSTOMIZATIONS
#define sConditionMgr
Definition: ConditionMgr.h:365
TaxiMask sAllianceTaxiNodesMask
Definition: DB2Stores.cpp:382
DB2Storage< ChrClassesEntry > sChrClassesStore("ChrClasses.db2", &ChrClassesLoadInfo::Instance)
DB2Storage< CharTitlesEntry > sCharTitlesStore("CharTitles.db2", &CharTitlesLoadInfo::Instance)
DB2Storage< ItemModifiedAppearanceEntry > sItemModifiedAppearanceStore("ItemModifiedAppearance.db2", &ItemModifiedAppearanceLoadInfo::Instance)
DB2Storage< ChrRacesEntry > sChrRacesStore("ChrRaces.db2", &ChrRacesLoadInfo::Instance)
DB2Storage< PlayerConditionEntry > sPlayerConditionStore("PlayerCondition.db2", &PlayerConditionLoadInfo::Instance)
DB2Storage< ChrCustomizationReqEntry > sChrCustomizationReqStore("ChrCustomizationReq.db2", &ChrCustomizationReqLoadInfo::Instance)
DB2Storage< SpellItemEnchantmentEntry > sSpellItemEnchantmentStore("SpellItemEnchantment.db2", &SpellItemEnchantmentLoadInfo::Instance)
DB2Storage< FactionEntry > sFactionStore("Faction.db2", &FactionLoadInfo::Instance)
TaxiMask sHordeTaxiNodesMask
Definition: DB2Stores.cpp:381
#define sDB2Manager
Definition: DB2Stores.h:538
constexpr size_t PLAYER_EXPLORED_ZONES_SIZE
Definition: DBCEnums.h:166
@ MoneySpentAtBarberShop
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
SQLTransaction< LoginDatabaseConnection > LoginDatabaseTransaction
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
Definition: DatabaseEnv.cpp:22
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition: DatabaseEnv.cpp:21
uint8_t uint8
Definition: Define.h:144
int64_t int64
Definition: Define.h:137
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
#define UI64LIT(N)
Definition: Define.h:127
uint16_t uint16
Definition: Define.h:143
uint32_t uint32
Definition: Define.h:142
#define MAX_EQUIPMENT_SET_INDEX
Definition: EquipmentSet.h:67
#define sGroupMgr
Definition: GroupMgr.h:61
#define sGuildMgr
Definition: GuildMgr.h:70
InventoryResult
Definition: ItemDefines.h:25
@ EQUIP_ERR_OK
Definition: ItemDefines.h:26
@ LANG_RESET_SPELLS
Definition: Language.h:261
@ LANG_RESET_TALENTS
Definition: Language.h:262
@ LANG_GM_ON
Definition: Language.h:388
@ LOG_LEVEL_INFO
Definition: LogCommon.h:29
#define TC_LOG_WARN(filterType__,...)
Definition: Log.h:162
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
#define sLog
Definition: Log.h:130
#define TC_LOG_INFO(filterType__,...)
Definition: Log.h:159
@ LOGIN_SEL_LAST_CHAR_UNDELETE
@ LOGIN_REP_REALM_CHARACTERS
Definition: LoginDatabase.h:56
@ LOGIN_UPD_LAST_CHAR_UNDELETE
@ LOGIN_SEL_SUM_REALM_CHARACTERS
Definition: LoginDatabase.h:57
@ LOGIN_UPD_ACCOUNT_ONLINE
Definition: LoginDatabase.h:71
#define TC_METRIC_EVENT(category, title, description)
Definition: Metric.h:206
bool normalizePlayerName(std::string &name)
Definition: ObjectMgr.cpp:154
#define sObjectMgr
Definition: ObjectMgr.h:1946
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
@ EQUIPMENT_SLOT_MAINHAND
Definition: Player.h:646
@ EQUIPMENT_SLOT_END
Definition: Player.h:650
@ EQUIPMENT_SLOT_OFFHAND
Definition: Player.h:647
std::vector< ItemPosCount > ItemPosCountVec
Definition: Player.h:750
@ PLAYER_EXTRA_HAS_RACE_CHANGED
Definition: Player.h:529
@ PLAYER_FLAGS_CONTESTED_PVP
Definition: Player.h:436
@ PLAYER_FLAGS_RESTING
Definition: Player.h:433
@ AT_LOGIN_RESET_TALENTS
Definition: Player.h:540
@ AT_LOGIN_RESET_SPELLS
Definition: Player.h:539
@ AT_LOGIN_RESET_PET_TALENTS
Definition: Player.h:542
@ AT_LOGIN_FIRST
Definition: Player.h:543
@ AT_LOGIN_RESURRECT
Definition: Player.h:546
@ AT_LOGIN_CUSTOMIZE
Definition: Player.h:541
@ AT_LOGIN_RENAME
Definition: Player.h:538
@ AT_LOGIN_CHANGE_RACE
Definition: Player.h:545
@ AT_LOGIN_CHANGE_FACTION
Definition: Player.h:544
#define INVENTORY_SLOT_BAG_0
Definition: Player.h:625
Trinity::IteratorPair< UF::ChrCustomizationChoice const * > MakeChrCustomizationChoiceRange(Container const &container)
Definition: Player.h:3247
@ PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS
Definition: Player.h:866
@ PLAYER_LOGIN_QUERY_LOAD_CUSTOMIZATIONS
Definition: Player.h:838
@ PLAYER_LOGIN_QUERY_LOAD_CURRENCY
Definition: Player.h:889
@ PLAYER_LOGIN_QUERY_LOAD_GLYPHS
Definition: Player.h:876
@ PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES
Definition: Player.h:868
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_REW
Definition: Player.h:884
@ MAX_PLAYER_LOGIN_QUERY
Definition: Player.h:900
@ PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS
Definition: Player.h:849
@ PLAYER_LOGIN_QUERY_LOAD_AURA_EFFECTS
Definition: Player.h:841
@ PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES
Definition: Player.h:885
@ PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS
Definition: Player.h:886
@ PLAYER_LOGIN_QUERY_LOAD_SOCIAL_LIST
Definition: Player.h:864
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWERS
Definition: Player.h:896
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA
Definition: Player.h:847
@ PLAYER_LOGIN_QUERY_LOAD_TRAIT_CONFIGS
Definition: Player.h:899
@ PLAYER_LOGIN_QUERY_LOAD_SKILLS
Definition: Player.h:880
@ PLAYER_LOGIN_QUERY_LOAD_BG_DATA
Definition: Player.h:875
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA_PROGRESS
Definition: Player.h:848
@ PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFITS
Definition: Player.h:874
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWER_ABILITIES
Definition: Player.h:897
@ PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA
Definition: Player.h:879
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS
Definition: Player.h:858
@ PLAYER_LOGIN_QUERY_LOAD_VOID_STORAGE
Definition: Player.h:888
@ PLAYER_LOGIN_QUERY_LOAD_PET_SLOTS
Definition: Player.h:892
@ PLAYER_LOGIN_QUERY_LOAD_ARTIFACTS
Definition: Player.h:852
@ PLAYER_LOGIN_QUERY_LOAD_INVENTORY
Definition: Player.h:851
@ PLAYER_LOGIN_QUERY_LOAD_REPUTATION
Definition: Player.h:850
@ PLAYER_LOGIN_QUERY_LOAD_AZERITE_MILESTONE_POWERS
Definition: Player.h:854
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON_BLUEPRINTS
Definition: Player.h:894
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_AZERITE
Definition: Player.h:860
@ PLAYER_LOGIN_QUERY_LOAD_FROM
Definition: Player.h:837
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS
Definition: Player.h:845
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES
Definition: Player.h:846
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_AZERITE_UNLOCKED_ESSENCE
Definition: Player.h:862
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON_BUILDINGS
Definition: Player.h:895
@ PLAYER_LOGIN_QUERY_LOAD_WEEKLY_QUEST_STATUS
Definition: Player.h:881
@ PLAYER_LOGIN_QUERY_LOAD_SPELL_CHARGES
Definition: Player.h:867
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_AZERITE_MILESTONE_POWER
Definition: Player.h:861
@ PLAYER_LOGIN_QUERY_LOAD_AZERITE
Definition: Player.h:853
@ PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS
Definition: Player.h:887
@ PLAYER_LOGIN_QUERY_LOAD_GUILD
Definition: Player.h:869
@ PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS
Definition: Player.h:873
@ PLAYER_LOGIN_QUERY_LOAD_MAILS
Definition: Player.h:857
@ PLAYER_LOGIN_QUERY_LOAD_AURAS
Definition: Player.h:840
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_AZERITE_EMPOWERED
Definition: Player.h:863
@ PLAYER_LOGIN_QUERY_LOAD_TALENTS
Definition: Player.h:877
@ PLAYER_LOGIN_QUERY_LOAD_AZERITE_UNLOCKED_ESSENCES
Definition: Player.h:855
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON
Definition: Player.h:893
@ PLAYER_LOGIN_QUERY_LOAD_BANNED
Definition: Player.h:883
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_ARTIFACT
Definition: Player.h:859
@ PLAYER_LOGIN_QUERY_LOAD_ARENA_INFO
Definition: Player.h:870
@ PLAYER_LOGIN_QUERY_LOAD_GROUP
Definition: Player.h:839
@ PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS
Definition: Player.h:872
@ PLAYER_LOGIN_QUERY_LOAD_HOME_BIND
Definition: Player.h:865
@ PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION
Definition: Player.h:891
@ PLAYER_LOGIN_QUERY_LOAD_SPELLS
Definition: Player.h:843
@ PLAYER_LOGIN_QUERY_LOAD_SPELL_FAVORITES
Definition: Player.h:844
@ PLAYER_LOGIN_QUERY_LOAD_TRAIT_ENTRIES
Definition: Player.h:898
@ PLAYER_LOGIN_QUERY_LOAD_AZERITE_EMPOWERED
Definition: Player.h:856
@ PLAYER_LOGIN_QUERY_LOAD_PVP_TALENTS
Definition: Player.h:878
@ PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES
Definition: Player.h:890
@ PLAYER_LOGIN_QUERY_LOAD_RANDOM_BG
Definition: Player.h:882
@ PLAYER_LOGIN_QUERY_LOAD_AURA_STORED_LOCATIONS
Definition: Player.h:842
@ PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS
Definition: Player.h:871
constexpr Trinity::RaceMask< uint64 > RACEMASK_ALLIANCE
Definition: RaceMask.h:183
constexpr Trinity::RaceMask< uint64 > RACEMASK_HORDE
Definition: RaceMask.h:198
Races
Definition: RaceMask.h:26
@ RACE_DARK_IRON_DWARF
Definition: RaceMask.h:61
@ RACE_TROLL
Definition: RaceMask.h:35
@ RACE_UNDEAD_PLAYER
Definition: RaceMask.h:32
@ RACE_ORC
Definition: RaceMask.h:29
@ RACE_LIGHTFORGED_DRAENEI
Definition: RaceMask.h:57
@ RACE_NONE
Definition: RaceMask.h:27
@ RACE_DRAENEI
Definition: RaceMask.h:38
@ RACE_NIGHTBORNE
Definition: RaceMask.h:54
@ RACE_HIGHMOUNTAIN_TAUREN
Definition: RaceMask.h:55
@ RACE_DRACTHYR_HORDE
Definition: RaceMask.h:66
@ RACE_ZANDALARI_TROLL
Definition: RaceMask.h:58
@ RACE_VOID_ELF
Definition: RaceMask.h:56
@ RACE_NIGHTELF
Definition: RaceMask.h:31
@ RACE_BLOODELF
Definition: RaceMask.h:37
@ RACE_DWARF
Definition: RaceMask.h:30
@ RACE_GNOME
Definition: RaceMask.h:34
@ RACE_GOBLIN
Definition: RaceMask.h:36
@ RACE_KUL_TIRAN
Definition: RaceMask.h:59
@ RACE_HUMAN
Definition: RaceMask.h:28
@ RACE_DRACTHYR_ALLIANCE
Definition: RaceMask.h:65
@ RACE_WORGEN
Definition: RaceMask.h:49
@ RACE_VULPERA
Definition: RaceMask.h:62
@ RACE_MECHAGNOME
Definition: RaceMask.h:64
@ RACE_MAGHAR_ORC
Definition: RaceMask.h:63
@ RACE_TAUREN
Definition: RaceMask.h:33
#define sScriptMgr
Definition: ScriptMgr.h:1418
Classes
@ CLASS_DEATH_KNIGHT
@ CLASS_DEMON_HUNTER
@ CLASS_EVOKER
@ LANG_PANDAREN_ALLIANCE
@ LANG_PANDAREN_HORDE
@ GAMEOBJECT_TYPE_BARBER_CHAIR
Gender
@ CHAR_CUSTOMIZE_FLAG_RACE
@ CHAR_CUSTOMIZE_FLAG_FACTION
@ CHAR_CUSTOMIZE_FLAG_CUSTOMIZE
ResponseCodes
@ CHAR_DELETE_SUCCESS
@ CHAR_CREATE_DRACTHYR_LEVEL_REQUIREMENT
@ CHAR_CREATE_EXPANSION
@ CHAR_CREATE_CHARACTER_ARENA_LEADER
@ CHAR_NAME_NO_NAME
@ CHAR_CREATE_RESTRICTED_RACECLASS
@ CHAR_CREATE_DRACTHYR_DUPLICATE
@ CHAR_CREATE_DISABLED
@ CHAR_NAME_FAILURE
@ RESPONSE_SUCCESS
@ CHAR_CREATE_FAILED
@ CHAR_DELETE_FAILED_GUILD_LEADER
@ CHAR_NAME_RESERVED
@ CHAR_DELETE_FAILED_ARENA_CAPTAIN
@ CHAR_CREATE_ERROR
@ CHAR_CREATE_NAME_IN_USE
@ CHAR_CREATE_CHARACTER_SWAP_FACTION
@ CHAR_CREATE_SERVER_LIMIT
@ CHAR_CREATE_EXPANSION_CLASS
@ CHAR_CREATE_CHARACTER_RACE_ONLY
@ CHAR_CREATE_SUCCESS
@ CHAR_CREATE_PVP_TEAMS_VIOLATION
@ CHAR_CREATE_ACCOUNT_LIMIT
@ CHAR_CREATE_NEW_PLAYER
@ CHAR_NAME_SUCCESS
CharacterUndeleteResult
@ CHARACTER_UNDELETE_RESULT_ERROR_NAME_TAKEN_BY_THIS_ACCOUNT
@ CHARACTER_UNDELETE_RESULT_ERROR_CHAR_CREATE
@ CHARACTER_UNDELETE_RESULT_ERROR_UNKNOWN
@ CHARACTER_UNDELETE_RESULT_ERROR_DISABLED
@ CHARACTER_UNDELETE_RESULT_OK
TeamId
@ TEAM_NEUTRAL
@ TEAM_ALLIANCE
@ TEAM_HORDE
@ ERR_GUILDEMBLEM_INVALIDVENDOR
@ ERR_GUILDEMBLEM_INVALID_TABARD_COLORS
@ ERR_GUILDEMBLEM_SUCCESS
#define MAX_CHARACTERS_PER_REALM
Definition: SharedDefines.h:85
@ TUTORIAL_ACTION_RESET
@ TUTORIAL_ACTION_CLEAR
@ TUTORIAL_ACTION_UPDATE
@ ALLIANCE
@ HORDE
@ CHARACTER_FLAG_LOCKED_BY_BILLING
@ CHARACTER_FLAG_LOCKED_FOR_TRANSFER
@ COMPLAINT_ENABLED_WITH_AUTO_IGNORE
#define MAX_ACCOUNT_TUTORIAL_VALUES
@ FRIEND_ONLINE
Definition: SocialMgr.h:71
#define sSocialMgr
Definition: SocialMgr.h:161
UnitStandStateType
Definition: UnitDefines.h:41
@ UNIT_STAND_STATE_SIT_LOW_CHAIR
Definition: UnitDefines.h:46
@ UNIT_STAND_STATE_STAND
Definition: UnitDefines.h:42
#define MAX_DECLINED_NAME_CASES
Definition: UnitDefines.h:484
@ UNIT_NPC_FLAG_NONE
Definition: UnitDefines.h:296
@ UNIT_NPC_FLAG_2_PERSONAL_TABARD_DESIGNER
Definition: UnitDefines.h:350
@ UNIT_BYTE2_FLAG_FFA_PVP
Definition: UnitDefines.h:95
@ DEAD
Definition: Unit.h:249
@ UNIT_STATE_STUNNED
Definition: Unit.h:258
@ NULL_BAG
Definition: Unit.h:62
@ NULL_SLOT
Definition: Unit.h:63
bool Utf8toWStr(char const *utf8str, size_t csize, wchar_t *wstr, size_t &wsize)
Definition: Util.cpp:383
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition: Util.h:491
bool isCyrillicCharacter(wchar_t wchar)
Definition: Util.h:154
void PSendSysMessage(const char *fmt, Args &&... args)
Definition: Chat.h:57
std::pair< bool, bool > HasItemAppearance(uint32 itemModifiedAppearanceId) const
static bool IsPlayerMeetingCondition(Player const *player, PlayerConditionEntry const *condition)
static ConditionalChrModelEntry const * GetConditionalChrModel(int32 chrModelId)
Definition: DB2Stores.cpp:2072
bool ValidateEmblemColors() const
Definition: Guild.h:278
bool Initialize(uint32 accountId, bool withDeclinedNames, bool isDeletedCharacters)
Class used to access individual fields of database query result.
Definition: Field.h:90
uint8 GetUInt8() const
Definition: Field.cpp:30
std::string GetString() const
Definition: Field.cpp:118
bool IsNull() const
Definition: Field.h:125
uint64 GetUInt64() const
Definition: Field.cpp:78
uint16 GetUInt16() const
Definition: Field.cpp:46
uint32 GetUInt32() const
Definition: Field.cpp:62
int32 GetInt32() const
Definition: Field.cpp:70
GameObjectTemplate const * GetGOInfo() const
Definition: GameObject.h:202
Definition: Group.h:197
Definition: Guild.h:329
Definition: Item.h:170
uint16 GetPos() const
Definition: Item.h:284
LoginQueryHolder(uint32 accountId, ObjectGuid guid)
ObjectGuid GetGuid() const
uint32 GetAccountId() const
virtual bool AddPlayerToMap(Player *player, bool initPlayer=true)
Definition: Map.cpp:415
void Initialize()
LowType GetCounter() const
Definition: ObjectGuid.h:293
static ObjectGuid const Empty
Definition: ObjectGuid.h:274
bool IsEmpty() const
Definition: ObjectGuid.h:319
std::string ToString() const
Definition: ObjectGuid.cpp:554
void SetRawValue(std::vector< uint8 > const &guid)
Definition: ObjectGuid.cpp:584
uint64 LowType
Definition: ObjectGuid.h:278
void Clear()
Definition: ObjectGuid.h:286
static bool CheckDeclinedNames(const std::wstring &w_ownname, DeclinedName const &names)
Definition: ObjectMgr.cpp:8921
std::map< uint32, uint32 > CharacterConversionMap
Definition: ObjectMgr.h:1120
static ResponseCodes CheckPlayerName(std::string_view name, LocaleConstant locale, bool create=false)
Definition: ObjectMgr.cpp:8687
std::unordered_map< uint32, Trinity::unique_trackable_ptr< Quest > > QuestContainer
Definition: ObjectMgr.h:1071
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
void ContinueTaxiFlight() const
Definition: Player.cpp:22722
void SendMovieStart(uint32 movieId)
Definition: Player.cpp:6338
void SendEquipError(InventoryResult msg, Item const *item1=nullptr, Item const *item2=nullptr, uint32 itemId=0) const
Definition: Player.cpp:13254
void SetWatchedFactionIndex(int32 index)
Definition: Player.h:2840
void SendInitialPacketsAfterAddToMap()
Definition: Player.cpp:24316
uint32 GetXP() const
Definition: Player.h:1196
static Team TeamForRace(uint8 race)
Definition: Player.cpp:6454
static TeamId TeamIdForRace(uint8 race)
Definition: Player.cpp:6471
InventoryResult CanUnequipItem(uint16 src, bool swap) const
Definition: Player.cpp:11127
void RemoveAtLoginFlag(AtLoginFlags flags, bool persist=false)
Definition: Player.cpp:27545
void ResetSpells(bool myClassOnly=false)
Definition: Player.cpp:24491
bool ModifyMoney(int64 amount, bool sendError=true)
Definition: Player.cpp:24098
InventoryResult CanEquipItem(uint8 slot, uint16 &dest, Item *pItem, bool swap, bool not_loading=true) const
Definition: Player.cpp:10896
void UpdateAverageItemLevelEquipped()
Definition: Player.cpp:30006
Creature * GetNPCIfCanInteractWith(ObjectGuid const &guid, NPCFlags npcFlags, NPCFlags2 npcFlags2) const
Definition: Player.cpp:1947
void SetNativeGender(Gender gender) override
Definition: Player.h:1218
Gender GetNativeGender() const override
Definition: Player.h:1217
void SetEquipmentSet(EquipmentSetInfo::EquipmentSetData const &newEqSet)
Definition: Player.cpp:27381
InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap=false) const
Definition: Player.cpp:10037
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, TeleportToOptions options=TELE_TO_NONE, Optional< uint32 > instanceId={})
Definition: Player.cpp:1250
void CleanupsBeforeDelete(bool finalCleanup=true) override
Definition: Player.cpp:386
void SendTalentsInfoData()
Definition: Player.cpp:27287
static void OfflineResurrect(ObjectGuid const &guid, CharacterDatabaseTransaction trans)
Definition: Player.cpp:4529
void SendDungeonDifficulty(int32 forcedDifficulty=-1) const
Definition: Player.cpp:21319
SceneMgr & GetSceneMgr()
Definition: Player.h:2715
void SendInitialPacketsBeforeAddToMap()
Definition: Player.cpp:24203
static void SavePositionInDB(WorldLocation const &loc, uint16 zoneId, ObjectGuid guid, CharacterDatabaseTransaction trans)
Definition: Player.cpp:21279
int64 GetBarberShopCost(Trinity::IteratorPair< UF::ChrCustomizationChoice const * > newCustomizations) const
Definition: Player.cpp:26229
static void SaveCustomizations(CharacterDatabaseTransaction trans, ObjectGuid::LowType guid, Trinity::IteratorPair< UF::ChrCustomizationChoice const * > customizations)
Definition: Player.cpp:20392
WorldLocation m_homebind
Definition: Player.h:2503
void SwapItem(uint16 src, uint16 dst)
Definition: Player.cpp:12763
void InitDisplayIds()
Definition: Player.cpp:22796
Item * StoreItem(ItemPosCountVec const &pos, Item *pItem, bool update)
Definition: Player.cpp:11612
WorldSession * GetSession() const
Definition: Player.h:2101
Item * GetItemByPos(uint16 pos) const
Definition: Player.cpp:9582
void ResetTalentSpecialization()
Definition: Player.cpp:26884
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition: Player.cpp:26767
void AddExploredZones(uint32 pos, uint64 mask)
Definition: Player.cpp:6421
void SetInGuild(ObjectGuid::LowType guildId)
Definition: Player.cpp:7419
void SetPersonalTabard(uint32 style, uint32 color, uint32 borderStyle, uint32 borderColor, uint32 backgroundColor)
Definition: Player.cpp:22458
ObjectGuid::LowType GetGuildId() const
Definition: Player.h:1993
bool IsGameMaster() const
Definition: Player.h:1178
void SetGuildRank(uint8 rankId)
Definition: Player.h:1988
void LoadCorpse(PreparedQueryResult result)
Definition: Player.cpp:18754
static void DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRealmChars=true, bool deleteFinally=false)
Definition: Player.cpp:3824
void SendCinematicStart(uint32 CinematicSequenceId) const
Definition: Player.cpp:6329
uint8 getCinematic() const
Definition: Player.h:1939
uint32 GetXPForNextLevel() const
Definition: Player.h:1197
void DeleteEquipmentSet(uint64 id)
Definition: Player.cpp:27529
bool LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const &holder)
Definition: Player.cpp:17618
UF::UpdateField< UF::ActivePlayerData, 0, TYPEID_ACTIVE_PLAYER > m_activePlayerData
Definition: Player.h:2864
static bool IsValidGender(uint8 Gender)
Definition: Player.h:1707
void UpdateAverageItemLevelTotal()
Definition: Player.cpp:29949
bool HasAtLoginFlag(AtLoginFlags f) const
Definition: Player.h:2532
static void LeaveAllArenaTeams(ObjectGuid guid)
Definition: Player.cpp:22468
void RemoveItem(uint8 bag, uint8 slot, bool update)
Definition: Player.cpp:12048
static bool IsValidRace(uint8 Race)
Definition: Player.h:1709
Group * GetGroup(Optional< uint8 > partyIndex)
Definition: Player.h:2606
bool HasPlayerFlag(PlayerFlags flags) const
Definition: Player.h:2737
void SetGuildLevel(uint32 level)
Definition: Player.h:1990
void SetTaxiCheater(bool on)
Definition: Player.h:1185
void SetVirtualPlayerRealm(uint32 virtualRealmAddress)
Definition: Player.h:2780
void SetContestedPvP(Player *attackedPlayer=nullptr)
Definition: Player.cpp:21439
Item * GetItemByGuid(ObjectGuid guid) const
Definition: Player.cpp:9566
void ResummonPetTemporaryUnSummonedIfAny()
Definition: Player.cpp:27180
PlayerCreateMode GetCreateMode() const
Definition: Player.h:1937
bool ResetTalents(bool noCost=false)
Definition: Player.cpp:3529
void SetInGameTime(uint32 time)
Definition: Player.h:1678
void setCinematic(uint8 cine)
Definition: Player.h:1940
ReputationMgr & GetReputationMgr()
Definition: Player.h:2251
bool IsQuestRewarded(uint32 quest_id) const
Definition: Player.cpp:24137
void SetCustomizations(Trinity::IteratorPair< Iter > customizations, bool markChanged=true)
Definition: Player.h:2764
Team GetTeam() const
Definition: Player.h:2235
bool HasEnoughMoney(uint64 amount) const
Definition: Player.h:1740
void setInt32(const uint8 index, const int32 value)
void setFloat(const uint8 index, const float value)
void setUInt8(const uint8 index, const uint8 value)
void setUInt32(const uint8 index, const uint32 value)
void setUInt16(const uint8 index, const uint16 value)
void setString(const uint8 index, const std::string &value)
void setUInt64(const uint8 index, const uint64 value)
void SetNextQuery(QueryCallback &&next)
QueryCallback && WithPreparedCallback(std::function< void(PreparedQueryResult)> &&callback)
void SetAtWar(RepListID repListID, bool on)
void SendState(FactionState const *faction)
bool SetOneFactionReputation(FactionEntry const *factionEntry, int32 standing, bool incremental)
Public for chat command needs.
void SendForceReactions()
void SetInactive(RepListID repListID, bool on)
void SetSize(size_t size)
Definition: QueryHolder.cpp:69
PreparedQueryResult GetPreparedResult(size_t index) const
Definition: QueryHolder.cpp:37
void AfterComplete(std::function< void(SQLQueryHolderBase const &)> callback) &
Definition: QueryHolder.h:69
bool SetPreparedQuery(size_t index, PreparedStatement< T > *stmt)
Definition: QueryHolder.h:47
uint32 PlayScene(uint32 sceneId, Position const *position=nullptr)
Definition: SceneMgr.cpp:36
size_t size() const
Definition: DBCEnums.h:2035
Utility class to enable range for loop syntax for multimap.equal_range uses.
Definition: IteratorPair.h:32
constexpr end_iterator end() const
Definition: IteratorPair.h:39
constexpr iterator begin() const
Definition: IteratorPair.h:38
void RestoreDisplayId(bool ignorePositiveAurasPreventingMounting=false)
Definition: Unit.cpp:10172
void SetStandState(UnitStandStateType state, uint32 animKitID=0)
Definition: Unit.cpp:10100
uint8 GetClass() const
Definition: Unit.h:752
MotionMaster * GetMotionMaster()
Definition: Unit.h:1652
DeathState m_deathState
Definition: Unit.h:1857
bool IsStandState() const
Definition: Unit.cpp:10094
void UpdateMountCapability()
Definition: Unit.cpp:8051
void SetPvpFlag(UnitPVPStateFlags flags)
Definition: Unit.h:868
void RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const *source=nullptr)
Definition: Unit.cpp:4101
bool HasUnitState(const uint32 f) const
Definition: Unit.h:732
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4664
UnitStandStateType GetStandState() const
Definition: Unit.h:886
bool SetWaterWalking(bool enable)
Definition: Unit.cpp:12863
uint8 GetLevel() const
Definition: Unit.h:746
uint8 GetRace() const
Definition: Unit.h:749
bool IsInCombat() const
Definition: Unit.h:1043
constexpr void WorldRelocate(WorldLocation const &loc)
Definition: Position.h:187
constexpr uint32 GetMapId() const
Definition: Position.h:201
Map * GetMap() const
Definition: Object.h:624
GameObject * FindNearestGameObjectOfType(GameobjectTypes type, float range) const
Definition: Object.cpp:2201
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
std::string const & GetName() const
Definition: Object.h:555
WorldPacket const * Write() override
Array< ChrCustomizationChoice, 250 > Customizations
std::shared_ptr< CharCustomizeInfo > CustomizeInfo
ObjectGuid Guid
Guid of the character to delete.
Optional< CharFactionChangeDisplayInfo > Display
std::shared_ptr< CharRaceOrFactionChangeInfo > RaceOrFactionChangeInfo
std::shared_ptr< CharacterRenameInfo > RenameInfo
WorldPacket const * Write() override
std::shared_ptr< CharacterCreateInfo > CreateInfo
WorldPacket const * Write() override
std::vector< CharacterInfo > Characters
all characters on the list
bool IsDeletedCharacters
used for character undelete list
TaggedPosition< Position::XYZO > Pos
WorldPacket const * Write() override
ObjectGuid Guid
Guid of the player that is logging in.
std::shared_ptr< CharacterUndeleteInfo > UndeleteInfo
uint32 CurrentCooldown
Current cooldown until next free character restoration. (in sec)
uint32 MaxCooldown
Max. cooldown until next free character restoration. Displayed in undelete confirm message....
EquipmentSetInfo::EquipmentSetData Set
EquipmentSetItem Items[EQUIPMENT_SET_SLOTS]
Optional< EuropaTicketConfig > EuropaTicketSystemStatus
uint32 HiddenUIClubsPresenceUpdateTimer
Timer for updating club presence when communities ui frame is hidden.
WorldPacket const * Write() override
GuidSet _legitCharacters
void SetPlayer(Player *player)
void HandleRandomizeCharNameOpcode(WorldPackets::Character::GenerateRandomCharacterName &packet)
void HandleOpeningCinematic(WorldPackets::Misc::OpeningCinematic &packet)
void HandleSetFactionAtWar(WorldPackets::Character::SetFactionAtWar &packet)
void HandleCharEnumOpcode(WorldPackets::Character::EnumCharacters &)
void HandleCharEnum(CharacterDatabaseQueryHolder const &holder)
void HandleTutorialFlag(WorldPackets::Misc::TutorialSetFlag &packet)
void AbortLogin(WorldPackets::Character::LoginFailureReason reason)
void HandleAlterAppearance(WorldPackets::Character::AlterApperance &packet)
void HandleCharRaceOrFactionChangeCallback(std::shared_ptr< WorldPackets::Character::CharRaceOrFactionChangeInfo > factionChangeInfo, PreparedQueryResult result)
void SendConnectToInstance(WorldPackets::Auth::ConnectToSerial serial)
void SendNotification(char const *format,...) ATTR_PRINTF(2
void HandleCharCustomizeOpcode(WorldPackets::Character::CharCustomize &packet)
void HandleCharUndeleteOpcode(WorldPackets::Character::UndeleteCharacter &undeleteInfo)
QueryCallbackProcessor _queryProcessor
void HandleReorderCharacters(WorldPackets::Character::ReorderCharacters &reorderChars)
void HandleSetFactionInactiveOpcode(WorldPackets::Character::SetFactionInactive &packet)
void LoadAccountData(PreparedQueryResult result, uint32 mask)
void HandleSetWatchedFactionOpcode(WorldPackets::Character::SetWatchedFaction &packet)
void SendCharDelete(ResponseCodes result)
LocaleConstant GetSessionDbcLocale() const
std::string GetPlayerInfo() const
void KickPlayer(std::string const &reason)
Kick a player out of the World.
void HandleCharRaceOrFactionChangeOpcode(WorldPackets::Character::CharRaceOrFactionChange &packet)
void HandleCharUndeleteEnumOpcode(WorldPackets::Character::EnumCharacters &)
Player * GetPlayer() const
bool PlayerLoading() const
Definition: WorldSession.h:969
void HandleCharRenameOpcode(WorldPackets::Character::CharacterRenameRequest &request)
void SendUndeleteCharacterResponse(CharacterUndeleteResult result, WorldPackets::Character::CharacterUndeleteInfo const *undeleteInfo)
void SendSetTimeZoneInformation()
Definition: AuthHandler.cpp:91
void HandleCharDeleteOpcode(WorldPackets::Character::CharDelete &charDelete)
void HandleCharCreateOpcode(WorldPackets::Character::CreateCharacter &charCreate)
void SendSetPlayerDeclinedNamesResult(DeclinedNameResult result, ObjectGuid guid)
void HandleCharRenameCallBack(std::shared_ptr< WorldPackets::Character::CharacterRenameInfo > renameInfo, PreparedQueryResult result)
void HandleSetPlayerDeclinedNames(WorldPackets::Character::SetPlayerDeclinedNames &packet)
bool CanSpeak() const
ObjectGuid m_playerLoading
SQLQueryHolderCallback & AddQueryHolderCallback(SQLQueryHolderCallback &&callback)
void HandleDeleteEquipmentSet(WorldPackets::EquipmentSet::DeleteEquipmentSet &deleteEquipmentSet)
bool IsLegitCharacterForAccount(ObjectGuid lowGUID)
std::string const & GetRemoteAddress() const
void HandlePlayerLogin(LoginQueryHolder const &holder)
void HandleCheckCharacterNameAvailability(WorldPackets::Character::CheckCharacterNameAvailability &checkCharacterNameAvailability)
bool HasPermission(uint32 permissionId)
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
uint32 GetBattlenetAccountId() const
bool MeetsChrCustomizationReq(ChrCustomizationReqEntry const *req, Races race, Classes playerClass, bool checkRequiredDependentChoices, Trinity::IteratorPair< UF::ChrCustomizationChoice const * > selectedChoices) const
uint32 GetAccountId() const
void SendCharCustomize(ResponseCodes result, WorldPackets::Character::CharCustomizeInfo const *customizeInfo)
uint8 GetAccountExpansion() const
void SendTutorialsData()
Player * _player
uint32 GetTutorialInt(uint8 index) const
CollectionMgr * GetCollectionMgr() const
void SendCharRename(ResponseCodes result, WorldPackets::Character::CharacterRenameInfo const *renameInfo)
void SendUndeleteCooldownStatusResponse(uint32 currentCooldown, uint32 maxCooldown)
void SendFeatureSystemStatus()
uint8 GetExpansion() const
void SendAccountDataTimes(ObjectGuid playerGuid, uint32 mask)
void HandleSetFactionNotAtWar(WorldPackets::Character::SetFactionNotAtWar &packet)
void HandleContinuePlayerLogin()
bool ValidateAppearance(Races race, Classes playerClass, Gender gender, Trinity::IteratorPair< UF::ChrCustomizationChoice const * > customizations)
void SendCharFactionChange(ResponseCodes result, WorldPackets::Character::CharRaceOrFactionChangeInfo const *factionChangeInfo)
void HandleEquipmentSetSave(WorldPackets::EquipmentSet::SaveEquipmentSet &saveEquipmentSet)
void HandleLoadScreenOpcode(WorldPackets::Character::LoadingScreenNotify &loadingScreenNotify)
void HandleUndeleteCooldownStatusCallback(PreparedQueryResult result)
void HandleCharCustomizeCallback(std::shared_ptr< WorldPackets::Character::CharCustomizeInfo > customizeInfo, PreparedQueryResult result)
void HandleRequestForcedReactionsOpcode(WorldPackets::Reputation::RequestForcedReactions &requestForcedReactions)
void HandleSavePersonalEmblem(WorldPackets::Character::SavePersonalEmblem const &savePersonalEmblem)
void SetTutorialInt(uint8 index, uint32 value)
void HandlePlayerLoginOpcode(WorldPackets::Character::PlayerLogin &playerLogin)
BattlePets::BattlePetMgr * GetBattlePetMgr() const
void HandleGetUndeleteCooldownStatus(WorldPackets::Character::GetUndeleteCharacterCooldownStatus &)
void SendCharCreate(ResponseCodes result, ObjectGuid const &guid=ObjectGuid::Empty)
void HandleUseEquipmentSet(WorldPackets::EquipmentSet::UseEquipmentSet &useEquipmentSet)
#define PER_CHARACTER_CACHE_MASK
Definition: WorldSession.h:874
DeclinedNameResult
Definition: WorldSession.h:900
#define GLOBAL_CACHE_MASK
Definition: WorldSession.h:873
#define ALL_ACCOUNT_DATA_CACHE_MASK
Definition: WorldSession.h:872
@ CONNECTION_TYPE_INSTANCE
Definition: Opcodes.h:31
@ DECLINED_NAMES_RESULT_SUCCESS
Definition: WorldSession.h:901
@ DECLINED_NAMES_RESULT_ERROR
Definition: WorldSession.h:902
#define sWorld
Definition: World.h:931
uint32 GetVirtualRealmAddress()
Definition: World.cpp:3968
Realm realm
Definition: World.cpp:3966
@ SERVER_MSG_STRING
Definition: World.h:52
@ CONFIG_ARENA_SEASON_ID
Definition: World.h:347
@ CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK
Definition: World.h:252
@ CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_EVOKER
Definition: World.h:257
@ CONFIG_CHARACTER_CREATING_DISABLED
Definition: World.h:251
@ CONFIG_ENABLE_SINFO_LOGIN
Definition: World.h:356
@ CONFIG_CHARACTERS_PER_ACCOUNT
Definition: World.h:253
@ CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_COOLDOWN
Definition: World.h:418
@ CONFIG_CHARACTER_CREATING_EVOKERS_PER_REALM
Definition: World.h:255
@ CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_DEMON_HUNTER
Definition: World.h:256
@ CONFIG_SKIP_CINEMATICS
Definition: World.h:258
@ CONFIG_CHARACTERS_PER_REALM
Definition: World.h:254
@ CONFIG_SUPPORT_COMPLAINTS_ENABLED
Definition: World.h:158
@ CONFIG_ALL_TAXI_PATHS
Definition: World.h:115
@ CONFIG_SUPPORT_BUGS_ENABLED
Definition: World.h:157
@ CONFIG_DECLINED_NAMES_USED
Definition: World.h:135
@ CONFIG_START_ALL_REP
Definition: World.h:148
@ CONFIG_FEATURE_SYSTEM_BPAY_STORE_ENABLED
Definition: World.h:177
@ CONFIG_CHARACTER_CREATING_DISABLE_ALLIED_RACE_ACHIEVEMENT_REQUIREMENT
Definition: World.h:198
@ CONFIG_ARENA_SEASON_IN_PROGRESS
Definition: World.h:142
@ CONFIG_PREVENT_RENAME_CUSTOMIZATION
Definition: World.h:190
@ CONFIG_SUPPORT_SUGGESTIONS_ENABLED
Definition: World.h:159
@ CONFIG_SUPPORT_TICKETS_ENABLED
Definition: World.h:156
@ CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP
Definition: World.h:111
@ CONFIG_START_ALL_EXPLORED
Definition: World.h:147
@ CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD
Definition: World.h:112
@ CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_ENABLED
Definition: World.h:178
@ CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK
Definition: World.h:446
time_t GetGameTime()
Definition: GameTime.cpp:44
uint32 GetGameTimeMS()
Definition: GameTime.cpp:49
TC_COMMON_API char const * GetFullVersion()
Definition: GitRevision.cpp:96
void AddObject(T *object)
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
constexpr IteratorPair< iterator, end_iterator > MakeIteratorPair(iterator first, end_iterator second)
Definition: IteratorPair.h:48
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition: MapUtils.h:29
TC_COMMON_API std::vector< std::string_view > Tokenize(std::string_view str, char sep, bool keepEmpty)
Definition: Util.cpp:56
@ RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_TEAMMASK
Definition: RBAC.h:67
@ RBAC_PERM_TWO_SIDE_CHARACTER_CREATION
Definition: RBAC.h:77
@ RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME
Definition: RBAC.h:70
@ RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RACEMASK
Definition: RBAC.h:69
@ RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_DEMON_HUNTER
Definition: RBAC.h:65
@ RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_CLASSMASK
Definition: RBAC.h:68
@ RBAC_PERM_TWO_SIDE_ADD_FRIEND
Definition: RBAC.h:82
uint32 target_mapId
Definition: ObjectMgr.h:460
ObjectGuid::LowType GuildId
Trinity::RaceMask< int64 > RaceMask
Definition: DB2Structure.h:746
EnumFlag< ChrCustomizationReqFlag > GetFlags() const
Definition: DB2Structure.h:755
EnumFlag< ChrRacesFlag > GetFlags() const
Definition: DB2Structure.h:851
std::string name[MAX_DECLINED_NAME_CASES]
Definition: UnitDefines.h:491
std::array< ObjectGuid, EQUIPMENT_SET_SLOTS > Pieces
Definition: EquipmentSet.h:54
uint32 IgnoreMask
Mask of EquipmentSlot.
Definition: EquipmentSet.h:50
std::array< int32, 2 > Enchants
SpellItemEnchantmentID.
Definition: EquipmentSet.h:56
std::array< int32, EQUIPMENT_SET_SLOTS > Appearances
ItemModifiedAppearanceID.
Definition: EquipmentSet.h:55
struct GameObjectTemplate::@213::@247 barberChair
PlayerCreateInfoSpells castSpells[size_t(PlayerCreateMode::Max)]
Definition: ObjectMgr.h:665
constexpr float GetPositionX() const
Definition: Position.h:76
constexpr float GetPositionY() const
Definition: Position.h:77
constexpr void GetPosition(float &x, float &y) const
Definition: Position.h:81
constexpr float GetOrientation() const
Definition: Position.h:79
constexpr float GetPositionZ() const
Definition: Position.h:78
Battlenet::RealmHandle Id
Definition: Realm.h:82
EnumFlag< SpellItemEnchantmentFlags > GetFlags() const
constexpr bool HasRace(uint8 raceId) const
Definition: RaceMask.h:88
constexpr bool IsEmpty() const
Definition: RaceMask.h:143
Array< ChrCustomizationChoice, 250 > Customizations