TrinityCore
Loading...
Searching...
No Matches
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 "BattlePetMgr.h"
26#include "Battleground.h"
27#include "BattlegroundPackets.h"
28#include "CalendarMgr.h"
29#include "CharacterCache.h"
30#include "CharacterPackets.h"
31#include "Chat.h"
32#include "Common.h"
33#include "DB2Stores.h"
34#include "DatabaseEnv.h"
35#include "EquipmentSetPackets.h"
36#include "GameObject.h"
37#include "GameTime.h"
38#include "GitRevision.h"
39#include "Group.h"
40#include "GroupMgr.h"
41#include "Guild.h"
42#include "GuildMgr.h"
43#include "Item.h"
44#include "Language.h"
45#include "Log.h"
46#include "Map.h"
47#include "MapUtils.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 "RealmList.h"
59#include "ReputationMgr.h"
60#include "ScriptMgr.h"
61#include "SocialMgr.h"
62#include "StringConvert.h"
63#include "SystemPackets.h"
64#include "TransmogMgr.h"
65#include "Util.h"
66#include "World.h"
67#include <boost/circular_buffer.hpp>
68#include <sstream>
69
71{
72 private:
75 public:
77 : m_accountId(accountId), m_guid(guid) { }
78 ObjectGuid GetGuid() const { return m_guid; }
79 uint32 GetAccountId() const { return m_accountId; }
80 bool Initialize();
81};
82
84{
86
87 bool res = true;
89
91 stmt->setUInt64(0, lowGuid);
93
94 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_CUSTOMIZATIONS);
95 stmt->setUInt64(0, lowGuid);
97
98 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GROUP_MEMBER);
99 stmt->setUInt64(0, lowGuid);
101
102 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_AURAS);
103 stmt->setUInt64(0, lowGuid);
105
106 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_AURA_EFFECTS);
107 stmt->setUInt64(0, lowGuid);
109
111 stmt->setUInt64(0, lowGuid);
113
114 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SPELL);
115 stmt->setUInt64(0, lowGuid);
117
118 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SPELL_FAVORITES);
119 stmt->setUInt64(0, lowGuid);
121
122 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUS);
123 stmt->setUInt64(0, lowGuid);
125
127 stmt->setUInt64(0, lowGuid);
129
131 stmt->setUInt64(0, lowGuid);
133
135 stmt->setUInt64(0, lowGuid);
137
139 stmt->setUInt64(0, lowGuid);
141
142 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_DAILY);
143 stmt->setUInt64(0, lowGuid);
145
146 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_WEEKLY);
147 stmt->setUInt64(0, lowGuid);
149
151 stmt->setUInt64(0, lowGuid);
153
155 stmt->setUInt64(0, lowGuid);
157
158 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_REPUTATION);
159 stmt->setUInt64(0, lowGuid);
161
162 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_INVENTORY);
163 stmt->setUInt64(0, lowGuid);
165
166 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEM_INSTANCE_ARTIFACT);
167 stmt->setUInt64(0, lowGuid);
169
170 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEM_INSTANCE_AZERITE);
171 stmt->setUInt64(0, lowGuid);
173
175 stmt->setUInt64(0, lowGuid);
177
179 stmt->setUInt64(0, lowGuid);
181
183 stmt->setUInt64(0, lowGuid);
185
186 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL);
187 stmt->setUInt64(0, lowGuid);
189
190 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS);
191 stmt->setUInt64(0, lowGuid);
193
194 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS_ARTIFACT);
195 stmt->setUInt64(0, lowGuid);
197
198 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS_AZERITE);
199 stmt->setUInt64(0, lowGuid);
201
203 stmt->setUInt64(0, lowGuid);
205
207 stmt->setUInt64(0, lowGuid);
209
210 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS_AZERITE_EMPOWERED);
211 stmt->setUInt64(0, lowGuid);
213
214 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SOCIALLIST);
215 stmt->setUInt64(0, lowGuid);
217
218 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_HOMEBIND);
219 stmt->setUInt64(0, lowGuid);
221
222 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS);
223 stmt->setUInt64(0, lowGuid);
225
226 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SPELL_CHARGES);
227 stmt->setUInt64(0, lowGuid);
229
230 if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED))
231 {
232 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_DECLINEDNAMES);
233 stmt->setUInt64(0, lowGuid);
235 }
236
237 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER);
238 stmt->setUInt64(0, lowGuid);
240
241 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ARENAINFO);
242 stmt->setUInt64(0, lowGuid);
244
245 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACHIEVEMENTS);
246 stmt->setUInt64(0, lowGuid);
248
249 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_CRITERIAPROGRESS);
250 stmt->setUInt64(0, lowGuid);
252
253 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_EQUIPMENTSETS);
254 stmt->setUInt64(0, lowGuid);
256
257 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_TRANSMOG_OUTFITS);
258 stmt->setUInt64(0, lowGuid);
260
261 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_TRANSMOG_OUTFIT);
262 stmt->setUInt64(0, lowGuid);
264
266 stmt->setUInt64(0, lowGuid);
268
270 stmt->setUInt64(0, lowGuid);
272
273 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_CUF_PROFILES);
274 stmt->setUInt64(0, lowGuid);
276
277 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_BGDATA);
278 stmt->setUInt64(0, lowGuid);
280
281 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GLYPHS);
282 stmt->setUInt64(0, lowGuid);
284
285 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_TALENTS);
286 stmt->setUInt64(0, lowGuid);
288
289 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_PVP_TALENTS);
290 stmt->setUInt64(0, lowGuid);
292
293 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PLAYER_ACCOUNT_DATA);
294 stmt->setUInt64(0, lowGuid);
296
297 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SKILLS);
298 stmt->setUInt64(0, lowGuid);
300
301 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_RANDOMBG);
302 stmt->setUInt64(0, lowGuid);
304
305 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_BANNED);
306 stmt->setUInt64(0, lowGuid);
308
309 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUSREW);
310 stmt->setUInt64(0, lowGuid);
312
313 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES);
314 stmt->setUInt32(0, m_accountId);
316
317 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PLAYER_CURRENCY);
318 stmt->setUInt64(0, lowGuid);
320
321 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CORPSE_LOCATION);
322 stmt->setUInt64(0, lowGuid);
324
325 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_PETS);
326 stmt->setUInt64(0, lowGuid);
328
329 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON);
330 stmt->setUInt64(0, lowGuid);
332
334 stmt->setUInt64(0, lowGuid);
336
337 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON_BUILDINGS);
338 stmt->setUInt64(0, lowGuid);
340
341 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWERS);
342 stmt->setUInt64(0, lowGuid);
344
346 stmt->setUInt64(0, lowGuid);
348
349 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_TRAIT_ENTRIES);
350 stmt->setUInt64(0, lowGuid);
352
353 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_TRAIT_CONFIGS);
354 stmt->setUInt64(0, lowGuid);
356
358 stmt->setUInt64(0, lowGuid);
360
361 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PLAYER_DATA_FLAGS_CHARACTER);
362 stmt->setUInt64(0, lowGuid);
364
365 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_BANK_TAB_SETTINGS);
366 stmt->setUInt64(0, lowGuid);
368
369 return res;
370}
371
373{
374public:
375 enum
376 {
379
380 MAX
381 };
382
387
388 bool Initialize(uint32 accountId, bool withDeclinedNames, bool isDeletedCharacters)
389 {
390 _isDeletedCharacters = isDeletedCharacters;
391
392 constexpr CharacterDatabaseStatements statements[2][3] =
393 {
396 };
397
398 bool result = true;
399 CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(statements[isDeletedCharacters ? 1 : 0][withDeclinedNames ? 1 : 0]);
400 stmt->setUInt32(0, accountId);
401 result &= SetPreparedQuery(CHARACTERS, stmt);
402
403 stmt = CharacterDatabase.GetPreparedStatement(statements[isDeletedCharacters ? 1 : 0][2]);
404 stmt->setUInt32(0, accountId);
405 result &= SetPreparedQuery(CUSTOMIZATIONS, stmt);
406
407 return result;
408 }
409
411
412private:
414};
415
417{
419 charEnum.Success = true;
420 charEnum.IsDeletedCharacters = static_cast<EnumCharactersQueryHolder const&>(holder).IsDeletedCharacters();
422
423 if (!charEnum.IsDeletedCharacters)
424 _legitCharacters.clear();
425
426 std::unordered_map<ObjectGuid::LowType, std::vector<UF::ChrCustomizationChoice>> customizations;
428 {
429 do
430 {
431 Field* fields = customizationsResult->Fetch();
432 UF::ChrCustomizationChoice& choice = customizations[fields[0].GetUInt64()].emplace_back();
433 choice.ChrCustomizationOptionID = fields[1].GetUInt32();
434 choice.ChrCustomizationChoiceID = fields[2].GetUInt32();
435
436 } while (customizationsResult->NextRow());
437 }
438
440 {
441 do
442 {
443 charEnum.Characters.emplace_back(result->Fetch());
444
446
447 if (std::vector<UF::ChrCustomizationChoice>* customizationsForChar = Trinity::Containers::MapGetValuePtr(customizations, charInfo.Guid.GetCounter()))
448 charInfo.Customizations = std::move(*customizationsForChar);
449
450 TC_LOG_INFO("network", "Loading char guid {} from account {}.", charInfo.Guid.ToString(), GetAccountId());
451
452 if (!charEnum.IsDeletedCharacters)
453 {
455 {
456 TC_LOG_ERROR("entities.player.loading", "Player {} has wrong Appearance values (Hair/Skin/Color), forcing recustomize", charInfo.Guid.ToString());
457
458 charInfo.Customizations.clear();
459
461 {
464 stmt->setUInt64(1, charInfo.Guid.GetCounter());
465 CharacterDatabase.Execute(stmt);
467 }
468 }
469
470 // Do not allow locked characters to login
472 _legitCharacters.insert(charInfo.Guid);
473 }
474
475 if (!sCharacterCache->HasCharacterCacheEntry(charInfo.Guid)) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet.
476 sCharacterCache->AddCharacterCacheEntry(charInfo.Guid, GetAccountId(), charInfo.Name, charInfo.SexID, charInfo.RaceID, charInfo.ClassID, charInfo.ExperienceLevel, false);
477
478 charEnum.MaxCharacterLevel = std::max<int32>(charEnum.MaxCharacterLevel, charInfo.ExperienceLevel);
479 }
480 while (result->NextRow() && charEnum.Characters.size() < MAX_CHARACTERS_PER_REALM);
481 }
482
483 for (std::pair<uint8 const, RaceUnlockRequirement> const& requirement : sObjectMgr->GetRaceUnlockRequirements())
484 {
486 raceUnlock.RaceID = requirement.first;
487 raceUnlock.HasUnlockedLicense = GetAccountExpansion() >= requirement.second.Expansion;
488 raceUnlock.HasUnlockedAchievement = requirement.second.AchievementId != 0
490 /* || HasAccountAchievement(requirement.second.AchievementId)*/);
491 charEnum.RaceUnlockData.push_back(raceUnlock);
492 }
493
494 SendPacket(charEnum.Write());
495
496 if (!charEnum.IsDeletedCharacters)
497 _collectionMgr->SendWarbandSceneCollectionData();
498}
499
501{
502 // remove expired bans
504 CharacterDatabase.Execute(stmt);
505
507 std::shared_ptr<EnumCharactersQueryHolder> holder = std::make_shared<EnumCharactersQueryHolder>();
508 if (!holder->Initialize(GetAccountId(), sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED), false))
509 {
510 HandleCharEnum(*holder);
511 return;
512 }
513
514 AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder)).AfterComplete([this](SQLQueryHolderBase const& result)
515 {
516 HandleCharEnum(static_cast<EnumCharactersQueryHolder const&>(result));
517 });
518}
519
521{
523 std::shared_ptr<EnumCharactersQueryHolder> holder = std::make_shared<EnumCharactersQueryHolder>();
524 if (!holder->Initialize(GetAccountId(), sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED), true))
525 {
526 HandleCharEnum(*holder);
527 return;
528 }
529
530 AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder)).AfterComplete([this](SQLQueryHolderBase const& result)
531 {
532 HandleCharEnum(static_cast<EnumCharactersQueryHolder const&>(result));
533 });
534}
535
537 bool checkRequiredDependentChoices, Trinity::IteratorPair<UF::ChrCustomizationChoice const*> selectedChoices) const
538{
540 return true;
541
542 if (req->ClassMask && !(req->ClassMask & (1 << (playerClass - 1))))
543 return false;
544
545 if (race != RACE_NONE && !req->RaceMask.IsEmpty() && req->RaceMask != RACEMASK_ALL_v<int64> && !req->RaceMask.HasRace(race))
546 return false;
547
548 if (req->AchievementID /*&& !HasAchieved(req->AchievementID)*/)
549 return false;
550
551 if (req->ItemModifiedAppearanceID && !GetCollectionMgr()->HasItemAppearance(req->ItemModifiedAppearanceID).first)
552 return false;
553
554 if (req->QuestID)
555 {
556 if (!_player)
557 return false;
558
559 if (!_player->IsQuestRewarded(req->QuestID))
560 return false;
561 }
562
563 if (checkRequiredDependentChoices)
564 {
565 if (std::vector<std::pair<uint32, std::vector<uint32>>> const* requiredChoices = sDB2Manager.GetRequiredCustomizationChoices(req->ID))
566 {
567 for (auto const& [chrCustomizationOptionId, requiredChoicesForOption] : *requiredChoices)
568 {
569 bool hasRequiredChoiceForOption = false;
570 for (uint32 requiredChoice : requiredChoicesForOption)
571 {
572 auto choiceItr = std::find_if(selectedChoices.begin(), selectedChoices.end(), [requiredChoice](UF::ChrCustomizationChoice const& choice)
573 {
574 return choice.ChrCustomizationChoiceID == requiredChoice;
575 });
576
577 if (choiceItr != selectedChoices.end())
578 {
579 hasRequiredChoiceForOption = true;
580 break;
581 }
582 }
583
584 if (!hasRequiredChoiceForOption)
585 return false;
586 }
587 }
588 }
589
590 return true;
591}
592
594{
595 std::vector<ChrCustomizationOptionEntry const*> const* options = sDB2Manager.GetCustomiztionOptions(race, gender);
596 if (!options)
597 return false;
598
599 uint32 previousOption = 0;
600
601 for (UF::ChrCustomizationChoice playerChoice : customizations)
602 {
603 // check uniqueness of options
604 if (playerChoice.ChrCustomizationOptionID == previousOption)
605 return false;
606
607 previousOption = playerChoice.ChrCustomizationOptionID;
608
609 // check if we can use this option
610 auto customizationOptionDataItr = std::find_if(options->begin(), options->end(), [&](ChrCustomizationOptionEntry const* option)
611 {
612 return option->ID == playerChoice.ChrCustomizationOptionID;
613 });
614
615 // option not found for race/gender combination
616 if (customizationOptionDataItr == options->end())
617 return false;
618
619 if (ChrCustomizationReqEntry const* req = sChrCustomizationReqStore.LookupEntry((*customizationOptionDataItr)->ChrCustomizationReqID))
620 if (!MeetsChrCustomizationReq(req, race, playerClass, false, customizations))
621 return false;
622
623 std::vector<ChrCustomizationChoiceEntry const*> const* choicesForOption = sDB2Manager.GetCustomiztionChoices(playerChoice.ChrCustomizationOptionID);
624 if (!choicesForOption)
625 return false;
626
627 auto customizationChoiceDataItr = std::find_if(choicesForOption->begin(), choicesForOption->end(), [&](ChrCustomizationChoiceEntry const* choice)
628 {
629 return choice->ID == playerChoice.ChrCustomizationChoiceID;
630 });
631
632 // choice not found for option
633 if (customizationChoiceDataItr == choicesForOption->end())
634 return false;
635
636 if (ChrCustomizationReqEntry const* req = sChrCustomizationReqStore.LookupEntry((*customizationChoiceDataItr)->ChrCustomizationReqID))
637 if (!MeetsChrCustomizationReq(req, race, playerClass, true, customizations))
638 return false;
639 }
640
641 return true;
642}
643
645{
647 {
648 if (uint32 mask = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED))
649 {
650 bool disabled = false;
651
652 switch (Player::TeamIdForRace(charCreate.CreateInfo->Race))
653 {
654 case TEAM_ALLIANCE:
655 disabled = (mask & (1 << 0)) != 0;
656 break;
657 case TEAM_HORDE:
658 disabled = (mask & (1 << 1)) != 0;
659 break;
660 case TEAM_NEUTRAL:
661 disabled = (mask & (1 << 2)) != 0;
662 break;
663 }
664
665 if (disabled)
666 {
668 return;
669 }
670 }
671 }
672
673 ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(charCreate.CreateInfo->Class);
674 if (!classEntry)
675 {
676 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());
678 return;
679 }
680
681 ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(charCreate.CreateInfo->Race);
682 if (!raceEntry)
683 {
684 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());
686 return;
687 }
688
689 // prevent character creating Expansion race without Expansion account
690 RaceUnlockRequirement const* raceExpansionRequirement = sObjectMgr->GetRaceUnlockRequirement(charCreate.CreateInfo->Race);
691 if (!raceExpansionRequirement)
692 {
693 TC_LOG_ERROR("entities.player.cheat", "Account {} tried to create character with unavailable race {}", GetAccountId(), charCreate.CreateInfo->Race);
695 return;
696 }
697
698 if (raceExpansionRequirement->Expansion > GetAccountExpansion())
699 {
700 TC_LOG_ERROR("entities.player.cheat", "Expansion {} account:[{}] tried to Create character with expansion {} race ({})",
701 GetAccountExpansion(), GetAccountId(), raceExpansionRequirement->Expansion, charCreate.CreateInfo->Race);
703 return;
704 }
705
706 //if (raceExpansionRequirement->AchievementId && !)
707 //{
708 // TC_LOG_ERROR("entities.player.cheat", "Expansion {} account:[{}] tried to Create character without achievement {} race ({})",
709 // GetAccountExpansion(), GetAccountId(), raceExpansionRequirement->AchievementId, charCreate.CreateInfo->Race);
710 // SendCharCreate(CHAR_CREATE_ALLIED_RACE_ACHIEVEMENT);
711 // return;
712 //}
713
714 // prevent character creating Expansion class without Expansion account
715 if (ClassAvailability const* raceClassExpansionRequirement = sObjectMgr->GetClassExpansionRequirement(charCreate.CreateInfo->Race, charCreate.CreateInfo->Class))
716 {
717 if (raceClassExpansionRequirement->ActiveExpansionLevel > GetExpansion() || raceClassExpansionRequirement->AccountExpansionLevel > GetAccountExpansion())
718 {
719 TC_LOG_ERROR("entities.player.cheat", "Account:[{}] tried to create character with race/class {}/{} without required expansion (had {}/{}, required {}/{})",
720 GetAccountId(), uint32(charCreate.CreateInfo->Race), uint32(charCreate.CreateInfo->Class), GetExpansion(), GetAccountExpansion(),
721 raceClassExpansionRequirement->ActiveExpansionLevel, raceClassExpansionRequirement->AccountExpansionLevel);
723 return;
724 }
725 }
726 else if (ClassAvailability const* classExpansionRequirement = sObjectMgr->GetClassExpansionRequirementFallback(charCreate.CreateInfo->Class))
727 {
728 if (classExpansionRequirement->MinActiveExpansionLevel > GetExpansion() || classExpansionRequirement->AccountExpansionLevel > GetAccountExpansion())
729 {
730 TC_LOG_ERROR("entities.player.cheat", "Account:[{}] tried to create character with race/class {}/{} without required expansion (had {}/{}, required {}/{})",
731 GetAccountId(), uint32(charCreate.CreateInfo->Race), uint32(charCreate.CreateInfo->Class), GetExpansion(), GetAccountExpansion(),
732 classExpansionRequirement->ActiveExpansionLevel, classExpansionRequirement->AccountExpansionLevel);
734 return;
735 }
736 }
737 else
738 {
739 TC_LOG_ERROR("entities.player.cheat", "Expansion {} account:[{}] tried to Create character for race/class combination that is missing requirements in db ({}/{})",
740 GetAccountExpansion(), GetAccountId(), uint32(charCreate.CreateInfo->Race), uint32(charCreate.CreateInfo->Class));
742 return;
743 }
744
746 {
747 if (raceEntry->GetFlags().HasFlag(ChrRacesFlag::NPCOnly))
748 {
749 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());
751 return;
752 }
753
755 if (raceMaskDisabled.HasRace(charCreate.CreateInfo->Race))
756 {
758 return;
759 }
760 }
761
763 {
764 uint32 classMaskDisabled = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK);
765 if ((1 << (charCreate.CreateInfo->Class - 1)) & classMaskDisabled)
766 {
768 return;
769 }
770 }
771
772 // prevent character creating with invalid name
773 if (!normalizePlayerName(charCreate.CreateInfo->Name))
774 {
775 TC_LOG_ERROR("entities.player.cheat", "Account:[{}] but tried to Create character with empty [name] ", GetAccountId());
777 return;
778 }
779
780 // check name limitations
782 if (res != CHAR_NAME_SUCCESS)
783 {
784 SendCharCreate(res);
785 return;
786 }
787
789 {
791 return;
792 }
793
794 if (charCreate.CreateInfo->TimerunningSeasonID)
795 {
797 return;
798 }
799
800 std::shared_ptr<WorldPackets::Character::CharacterCreateInfo> createInfo = charCreate.CreateInfo;
802 stmt->setString(0, charCreate.CreateInfo->Name);
803
805 .WithChainingPreparedCallback([this](QueryCallback& queryCallback, PreparedQueryResult result)
806 {
807 if (result)
808 {
809 SendCharCreate(CHAR_CREATE_NAME_IN_USE);
810 return;
811 }
812
814 stmt->setUInt32(0, GetAccountId());
815 queryCallback.SetNextQuery(LoginDatabase.AsyncQuery(stmt));
816 })
817 .WithChainingPreparedCallback([this](QueryCallback& queryCallback, PreparedQueryResult result)
818 {
819 uint64 acctCharCount = 0;
820 if (result)
821 {
822 Field* fields = result->Fetch();
823 acctCharCount = uint64(fields[0].GetDouble());
824 }
825
826 if (acctCharCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_ACCOUNT))
827 {
828 SendCharCreate(CHAR_CREATE_ACCOUNT_LIMIT);
829 return;
830 }
831
833 stmt->setUInt32(0, GetAccountId());
834 queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt));
835 })
836 .WithChainingPreparedCallback([this, createInfo](QueryCallback& queryCallback, PreparedQueryResult result)
837 {
838 if (result)
839 {
840 Field* fields = result->Fetch();
841 createInfo->CharCount = uint8(fields[0].GetUInt64()); // SQL's COUNT() returns uint64 but it will always be less than uint8.Max
842
843 if (createInfo->CharCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM))
844 {
845 SendCharCreate(CHAR_CREATE_SERVER_LIMIT);
846 return;
847 }
848 }
849
850 bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || HasPermission(rbac::RBAC_PERM_TWO_SIDE_CHARACTER_CREATION);
851 uint32 skipCinematics = sWorld->getIntConfig(CONFIG_SKIP_CINEMATICS);
852
853 std::function<void(PreparedQueryResult)> finalizeCharacterCreation = [this, createInfo](PreparedQueryResult result)
854 {
855 bool haveSameRace = false;
856 uint32 demonHunterReqLevel = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_DEMON_HUNTER);
857 bool hasDemonHunterReqLevel = (demonHunterReqLevel == 0);
858 uint32 evokerReqLevel = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_EVOKER);
859 bool hasEvokerReqLevel = (evokerReqLevel == 0);
860 bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || HasPermission(rbac::RBAC_PERM_TWO_SIDE_CHARACTER_CREATION);
861 uint32 skipCinematics = sWorld->getIntConfig(CONFIG_SKIP_CINEMATICS);
862 bool checkClassLevelReqs = (createInfo->Class == CLASS_DEMON_HUNTER || createInfo->Class == CLASS_EVOKER)
864 int32 evokerLimit = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_EVOKERS_PER_REALM);
865 bool hasEvokerLimit = evokerLimit != 0;
866
867 if (result)
868 {
869 uint32 team = Player::TeamForRace(createInfo->Race);
870
871 Field* field = result->Fetch();
872 uint8 accRace = field[1].GetUInt8();
873 uint8 accClass = field[2].GetUInt8();
874
875 if (checkClassLevelReqs)
876 {
877 if (!hasDemonHunterReqLevel)
878 {
879 uint8 accLevel = field[0].GetUInt8();
880 if (accLevel >= demonHunterReqLevel)
881 hasDemonHunterReqLevel = true;
882 }
883 if (!hasEvokerReqLevel)
884 {
885 uint8 accLevel = field[0].GetUInt8();
886 if (accLevel >= evokerReqLevel)
887 hasEvokerReqLevel = true;
888 }
889 }
890
891 if (accClass == CLASS_EVOKER)
892 --evokerLimit;
893
894 // need to check team only for first character
896 if (!allowTwoSideAccounts)
897 {
898 uint32 accTeam = 0;
899 if (accRace > 0)
900 accTeam = Player::TeamForRace(accRace);
901
902 if (accTeam != team)
903 {
904 SendCharCreate(CHAR_CREATE_PVP_TEAMS_VIOLATION);
905 return;
906 }
907 }
908
909 // search same race for cinematic or same class if need
911 while ((skipCinematics == 1 && !haveSameRace) || createInfo->Class == CLASS_DEMON_HUNTER || createInfo->Class == CLASS_EVOKER)
912 {
913 if (!result->NextRow())
914 break;
915
916 field = result->Fetch();
917 accRace = field[1].GetUInt8();
918 accClass = field[2].GetUInt8();
919
920 if (!haveSameRace)
921 haveSameRace = createInfo->Race == accRace;
922
923 if (checkClassLevelReqs)
924 {
925 if (!hasDemonHunterReqLevel)
926 {
927 uint8 accLevel = field[0].GetUInt8();
928 if (accLevel >= demonHunterReqLevel)
929 hasDemonHunterReqLevel = true;
930 }
931 if (!hasEvokerReqLevel)
932 {
933 uint8 accLevel = field[0].GetUInt8();
934 if (accLevel >= evokerReqLevel)
935 hasEvokerReqLevel = true;
936 }
937 }
938
939 if (accClass == CLASS_EVOKER)
940 --evokerLimit;
941 }
942 }
943
944 if (checkClassLevelReqs)
945 {
946 if (!hasDemonHunterReqLevel)
947 {
948 SendCharCreate(CHAR_CREATE_NEW_PLAYER);
949 return;
950 }
951 if (!hasEvokerReqLevel)
952 {
954 return;
955 }
956 }
957
958 if (createInfo->Class == CLASS_EVOKER && hasEvokerLimit && evokerLimit < 1)
959 {
960 SendCharCreate(CHAR_CREATE_DRACTHYR_DUPLICATE);
961 return;
962 }
963
964 // Check name uniqueness in the same step as saving to database
965 if (sCharacterCache->GetCharacterCacheByName(createInfo->Name))
966 {
967 SendCharCreate(CHAR_CREATE_NAME_IN_USE);
968 return;
969 }
970
971 std::shared_ptr<Player> newChar(new Player(this), [](Player* ptr)
972 {
974 delete ptr;
975 });
976 newChar->GetMotionMaster()->Initialize();
977 if (!newChar->Create(sObjectMgr->GetGenerator<HighGuid::Player>().Generate(), createInfo.get()))
978 {
979 // Player not create (race/class/etc problem?)
980 SendCharCreate(CHAR_CREATE_ERROR);
981 return;
982 }
983
984 if ((haveSameRace && skipCinematics == 1) || skipCinematics == 2)
985 newChar->setCinematic(1); // not show intro
986
987 newChar->SetAtLoginFlag(AT_LOGIN_FIRST); // First login
988
989 CharacterDatabaseTransaction characterTransaction = CharacterDatabase.BeginTransaction();
990 LoginDatabaseTransaction trans = LoginDatabase.BeginTransaction();
991
992 // Player created, save it now
993 newChar->SaveToDB(trans, characterTransaction, true);
994 createInfo->CharCount += 1;
995
997 stmt->setUInt32(0, createInfo->CharCount);
998 stmt->setUInt32(1, GetAccountId());
999 stmt->setUInt32(2, sRealmList->GetCurrentRealmId().Realm);
1000 trans->Append(stmt);
1001
1002 AddTransactionCallback(CharacterDatabase.AsyncCommitTransaction(characterTransaction)).AfterComplete([this, newChar = std::move(newChar), trans](bool success)
1003 {
1004 if (success)
1005 {
1006 LoginDatabase.CommitTransaction(trans);
1007
1008 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Create Character: {} {}", GetAccountId(), GetRemoteAddress(), newChar->GetName(), newChar->GetGUID().ToString());
1009 sScriptMgr->OnPlayerCreate(newChar.get());
1010 sCharacterCache->AddCharacterCacheEntry(newChar->GetGUID(), GetAccountId(), newChar->GetName(), newChar->GetNativeGender(), newChar->GetRace(), newChar->GetClass(), newChar->GetLevel(), false);
1011
1012 SendCharCreate(CHAR_CREATE_SUCCESS, newChar->GetGUID());
1013 }
1014 else
1015 SendCharCreate(CHAR_CREATE_ERROR);
1016 });
1017 };
1018
1019 if (allowTwoSideAccounts && !skipCinematics && createInfo->Class != CLASS_DEMON_HUNTER)
1020 {
1021 finalizeCharacterCreation(PreparedQueryResult(nullptr));
1022 return;
1023 }
1024
1026 stmt->setUInt32(0, GetAccountId());
1027 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)
1028 queryCallback.WithPreparedCallback(std::move(finalizeCharacterCreation)).SetNextQuery(CharacterDatabase.AsyncQuery(stmt));
1029 }));
1030}
1031
1033{
1034 // Initiating
1035 uint32 initAccountId = GetAccountId();
1036
1037 // can't delete loaded character
1038 if (ObjectAccessor::FindPlayer(charDelete.Guid))
1039 {
1040 sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
1041 return;
1042 }
1043
1044 // is guild leader
1045 if (sGuildMgr->GetGuildByLeader(charDelete.Guid))
1046 {
1047 sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
1049 return;
1050 }
1051
1052 // is arena team captain
1053 if (sArenaTeamMgr->GetArenaTeamByCaptain(charDelete.Guid))
1054 {
1055 sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
1057 return;
1058 }
1059
1060 CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(charDelete.Guid);
1061 if (!characterInfo)
1062 {
1063 sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
1064 return;
1065 }
1066
1067 uint32 accountId = characterInfo->AccountId;
1068 std::string name = characterInfo->Name;
1069 uint8 level = characterInfo->Level;
1070
1071 // prevent deleting other players' characters using cheating tools
1072 if (accountId != initAccountId)
1073 {
1074 sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
1075 return;
1076 }
1077
1078 TC_LOG_INFO("entities.player.character", "Account: {}, IP: {} deleted character: {}, {}, Level: {}", accountId, GetRemoteAddress(), name, charDelete.Guid.ToString(), level);
1079
1080 // To prevent hook failure, place hook before removing reference from DB
1081 sScriptMgr->OnPlayerDelete(charDelete.Guid, initAccountId); // To prevent race conditioning, but as it also makes sense, we hand the accountId over for successful delete.
1082 // Shouldn't interfere with character deletion though
1083
1084 if (sLog->ShouldLog("entities.player.dump", LOG_LEVEL_INFO)) // optimize GetPlayerDump call
1085 {
1086 std::string dump;
1087 if (PlayerDumpWriter().GetDump(charDelete.Guid.GetCounter(), dump))
1088 sLog->OutCharDump(dump, accountId, charDelete.Guid.GetCounter(), name);
1089 }
1090
1091 sCalendarMgr->RemoveAllPlayerEventsAndInvites(charDelete.Guid);
1092 Player::DeleteFromDB(charDelete.Guid, accountId);
1093
1095}
1096
1098{
1099 if (PlayerLoading() || GetPlayer() != nullptr)
1100 {
1101 TC_LOG_ERROR("network", "Player tries to login again, AccountId = {}", GetAccountId());
1102 KickPlayer("WorldSession::HandlePlayerLoginOpcode Another client logging in");
1103 return;
1104 }
1105
1106 m_playerLoading = playerLogin.Guid;
1107
1108 TC_LOG_DEBUG("network", "Character {} logging in", playerLogin.Guid.ToString());
1109
1110 if (!IsLegitCharacterForAccount(playerLogin.Guid))
1111 {
1112 TC_LOG_ERROR("network", "Account ({}) can't login with that character ({}).", GetAccountId(), playerLogin.Guid.ToString());
1113 KickPlayer("WorldSession::HandlePlayerLoginOpcode Trying to login with a character of another account");
1114 return;
1115 }
1116
1118}
1119
1121{
1122 if (!PlayerLoading() || GetPlayer())
1123 {
1124 KickPlayer("WorldSession::HandleContinuePlayerLogin incorrect player state when logging in");
1125 return;
1126 }
1127
1128 std::shared_ptr<LoginQueryHolder> holder = std::make_shared<LoginQueryHolder>(GetAccountId(), m_playerLoading);
1129 if (!holder->Initialize())
1130 {
1132 return;
1133 }
1134
1136
1137 // client will respond to SMSG_RESUME_COMMS with CMSG_QUEUED_MESSAGES_END
1139
1140 AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder)).AfterComplete([this](SQLQueryHolderBase const& holder)
1141 {
1142 HandlePlayerLogin(static_cast<LoginQueryHolder const&>(holder));
1143 });
1144}
1145
1147{
1148 if (!PlayerLoading() || GetPlayer())
1149 {
1150 KickPlayer("WorldSession::AbortLogin incorrect player state when logging in");
1151 return;
1152 }
1153
1156}
1157
1159{
1160 // TODO: Do something with this packet
1161}
1162
1164{
1165 ObjectGuid playerGuid = holder.GetGuid();
1166
1167 Player* pCurrChar = new Player(this);
1168 // for send server info and strings (config)
1169 ChatHandler chH = ChatHandler(pCurrChar->GetSession());
1170
1171 // "GetAccountId() == db stored account id" checked in LoadFromDB (prevent login not own character using cheating tools)
1172 if (!pCurrChar->LoadFromDB(playerGuid, holder))
1173 {
1174 SetPlayer(nullptr);
1175 KickPlayer("WorldSession::HandlePlayerLogin Player::LoadFromDB failed"); // disconnect client, player no set to session and it will not deleted or saved at kick
1176 delete pCurrChar; // delete it manually
1178 return;
1179 }
1180
1181 if (!_timeSyncClockDeltaQueue->empty())
1182 {
1185 }
1186
1188
1191
1192 pCurrChar->GetMotionMaster()->Initialize();
1193 pCurrChar->SendDungeonDifficulty();
1194
1196 loginVerifyWorld.MapID = pCurrChar->GetMapId();
1197 loginVerifyWorld.Pos = pCurrChar->GetPosition();
1198 SendPacket(loginVerifyWorld.Write());
1199
1200 // load player specific part before send times
1203
1205
1206 // Send MOTD
1207 {
1209 motd.Text = &sWorld->GetMotd();
1210 SendPacket(motd.Write());
1211 }
1212
1214
1215 // Send PVPSeason
1216 {
1218 seasonInfo.PreviousArenaSeason = sWorld->getIntConfig(CONFIG_ARENA_SEASON_ID) - sWorld->getBoolConfig(CONFIG_ARENA_SEASON_IN_PROGRESS);
1219
1220 if (sWorld->getBoolConfig(CONFIG_ARENA_SEASON_IN_PROGRESS))
1221 seasonInfo.CurrentArenaSeason = sWorld->getIntConfig(CONFIG_ARENA_SEASON_ID);
1222
1223 SendPacket(seasonInfo.Write());
1224 }
1225
1226 // send server info
1227 {
1228 if (sWorld->getIntConfig(CONFIG_ENABLE_SINFO_LOGIN) == 1)
1230 }
1231
1232 //QueryResult* result = CharacterDatabase.PQuery("SELECT guildid, `rank` FROM guild_member WHERE guid = '{}'", pCurrChar->GetGUIDLow());
1234 {
1235 Field* fields = resultGuild->Fetch();
1236 pCurrChar->SetInGuild(fields[0].GetUInt64());
1237 pCurrChar->SetGuildRank(fields[1].GetUInt8());
1238 if (Guild* guild = sGuildMgr->GetGuildById(pCurrChar->GetGuildId()))
1239 pCurrChar->SetGuildLevel(guild->GetLevel());
1240 }
1241 else if (pCurrChar->GetGuildId()) // clear guild related fields in case wrong data about non existed membership
1242 {
1243 pCurrChar->SetInGuild(UI64LIT(0));
1244 pCurrChar->SetGuildRank(0);
1245 pCurrChar->SetGuildLevel(0);
1246 }
1247
1249
1251
1253
1254 //Show cinematic at the first time that player login
1255 if (!pCurrChar->getCinematic())
1256 {
1257 pCurrChar->setCinematic(1);
1258
1259 if (PlayerInfo const* playerInfo = sObjectMgr->GetPlayerInfo(pCurrChar->GetRace(), pCurrChar->GetClass()))
1260 {
1261 switch (pCurrChar->GetCreateMode())
1262 {
1264 if (playerInfo->introMovieId)
1265 pCurrChar->SendMovieStart(*playerInfo->introMovieId);
1266 else if (playerInfo->introSceneId)
1267 pCurrChar->GetSceneMgr().PlayScene(*playerInfo->introSceneId);
1268 else if (sChrClassesStore.AssertEntry(pCurrChar->GetClass())->CinematicSequenceID)
1269 pCurrChar->SendCinematicStart(sChrClassesStore.AssertEntry(pCurrChar->GetClass())->CinematicSequenceID);
1270 else if (sChrRacesStore.AssertEntry(pCurrChar->GetRace())->CinematicSequenceID)
1271 pCurrChar->SendCinematicStart(sChrRacesStore.AssertEntry(pCurrChar->GetRace())->CinematicSequenceID);
1272 break;
1274 if (playerInfo->introSceneIdNPE)
1275 pCurrChar->GetSceneMgr().PlayScene(*playerInfo->introSceneIdNPE);
1276 break;
1277 default:
1278 break;
1279 }
1280 }
1281
1282 // send new char string if not empty
1283 if (!sWorld->GetNewCharString().empty())
1284 chH.PSendSysMessage("%s", sWorld->GetNewCharString().c_str());
1285 }
1286
1287 if (!pCurrChar->GetMap()->AddPlayerToMap(pCurrChar))
1288 {
1289 if (AreaTriggerTeleport const* at = sObjectMgr->GetGoBackTrigger(pCurrChar->GetMapId()))
1290 pCurrChar->TeleportTo(at->Loc);
1291 else
1292 pCurrChar->TeleportTo(pCurrChar->m_homebind);
1293 }
1294
1295 ObjectAccessor::AddObject(pCurrChar);
1296 //TC_LOG_DEBUG("Player {} added to Map.", pCurrChar->GetName());
1297
1298 if (pCurrChar->GetGuildId())
1299 {
1300 if (Guild* guild = sGuildMgr->GetGuildById(pCurrChar->GetGuildId()))
1301 guild->SendLoginInfo(this);
1302 else
1303 {
1304 // remove wrong guild data
1305 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());
1306 pCurrChar->SetInGuild(UI64LIT(0));
1307 }
1308 }
1309
1311
1313
1315 stmt->setUInt64(0, pCurrChar->GetGUID().GetCounter());
1316 CharacterDatabase.Execute(stmt);
1317
1319 loginStmt->setUInt32(0, GetAccountId());
1320 LoginDatabase.Execute(loginStmt);
1321
1323
1324 // announce group about member online (must be after add to player list to receive announce to self)
1325 if (Group* group = pCurrChar->GetGroup())
1326 {
1327 //pCurrChar->groupInfo.group->SendInit(this); // useless
1328 group->SendUpdate();
1329 if (group->GetLeaderGUID() == pCurrChar->GetGUID())
1330 group->StopLeaderOfflineTimer();
1331 }
1332
1333 // friend status
1334 sSocialMgr->SendFriendStatus(pCurrChar, FRIEND_ONLINE, pCurrChar->GetGUID(), true);
1335
1336 // Place character in world (and load zone) before some object loading
1338
1339 // setting Ghost+speed if dead
1340 if (pCurrChar->m_deathState == DEAD)
1341 {
1342 // not blizz like, we must correctly save and load player instead...
1343 if (pCurrChar->GetRace() == RACE_NIGHTELF && !pCurrChar->HasAura(20584))
1344 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)
1345
1346 if (!pCurrChar->HasAura(8326))
1347 pCurrChar->CastSpell(pCurrChar, 8326, true); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?)
1348
1349 pCurrChar->SetWaterWalking(true);
1350
1351 int32 const delay = pCurrChar->CalculateCorpseReclaimDelay(true);
1352 if (delay > 0)
1353 pCurrChar->SendCorpseReclaimDelay(delay);
1354 }
1355
1356 pCurrChar->ContinueTaxiFlight();
1357
1358 // reset for all pets before pet loading
1360 {
1361 // Delete all of the player's pet spells
1363 stmtSpells->setUInt64(0, pCurrChar->GetGUID().GetCounter());
1364 CharacterDatabase.Execute(stmtSpells);
1365
1366 // Then reset all of the player's pet specualizations
1368 stmtSpec->setUInt64(0, pCurrChar->GetGUID().GetCounter());
1369 CharacterDatabase.Execute(stmtSpec);
1370 }
1371
1372 // Load pet if any (if player not alive and in taxi flight or another then pet will remember as temporary unsummoned)
1374
1375 // Set FFA PvP for non GM in non-rest mode
1376 if (sWorld->IsFFAPvPRealm() && !pCurrChar->IsGameMaster() && !pCurrChar->HasPlayerFlag(PLAYER_FLAGS_RESTING))
1378
1380 pCurrChar->SetContestedPvP();
1381
1382 // Apply at_login requests
1383 if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_SPELLS))
1384 {
1385 pCurrChar->ResetSpells();
1387 }
1388
1389 if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_TALENTS))
1390 {
1391 pCurrChar->ResetTalents(true);
1392 pCurrChar->ResetTalentSpecialization();
1393 pCurrChar->SendTalentsInfoData(); // original talents send already in to SendInitialPacketsBeforeAddToMap, resend reset state
1395 }
1396
1397 bool firstLogin = pCurrChar->HasAtLoginFlag(AT_LOGIN_FIRST);
1398 if (firstLogin)
1399 {
1401
1402 PlayerInfo const* info = sObjectMgr->GetPlayerInfo(pCurrChar->GetRace(), pCurrChar->GetClass());
1403 for (uint32 spellId : info->castSpells[AsUnderlyingType(pCurrChar->GetCreateMode())])
1404 pCurrChar->CastSpell(pCurrChar, spellId, true);
1405
1406 // start with every map explored
1407 if (sWorld->getBoolConfig(CONFIG_START_ALL_EXPLORED))
1408 {
1409 for (uint32 i = 0; i < PLAYER_EXPLORED_ZONES_SIZE; ++i)
1410 pCurrChar->AddExploredZones(i, UI64LIT(0xFFFFFFFFFFFFFFFF));
1411 }
1412
1413 // Max relevant reputations if "StartAllReputation" is enabled
1414 if (sWorld->getBoolConfig(CONFIG_START_ALL_REP))
1415 {
1416 ReputationMgr& repMgr = pCurrChar->GetReputationMgr();
1417 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 942), 42999, false); // Cenarion Expedition
1418 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 935), 42999, false); // The Sha'tar
1419 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 936), 42999, false); // Shattrath City
1420 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1011), 42999, false); // Lower City
1421 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 970), 42999, false); // Sporeggar
1422 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 967), 42999, false); // The Violet Eye
1423 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 989), 42999, false); // Keepers of Time
1424 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 932), 42999, false); // The Aldor
1425 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 934), 42999, false); // The Scryers
1426 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1038), 42999, false); // Ogri'la
1427 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1077), 42999, false); // Shattered Sun Offensive
1428 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1106), 42999, false); // Argent Crusade
1429 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1104), 42999, false); // Frenzyheart Tribe
1430 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1090), 42999, false); // Kirin Tor
1431 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1098), 42999, false); // Knights of the Ebon Blade
1432 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1156), 42999, false); // The Ashen Verdict
1433 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1073), 42999, false); // The Kalu'ak
1434 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1105), 42999, false); // The Oracles
1435 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1119), 42999, false); // The Sons of Hodir
1436 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1091), 42999, false); // The Wyrmrest Accord
1437
1438 // Factions depending on team, like cities and some more stuff
1439 switch (pCurrChar->GetTeam())
1440 {
1441 case ALLIANCE:
1442 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 72), 42999, false); // Stormwind
1443 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 47), 42999, false); // Ironforge
1444 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 69), 42999, false); // Darnassus
1445 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 930), 42999, false); // Exodar
1446 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 730), 42999, false); // Stormpike Guard
1447 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 978), 42999, false); // Kurenai
1448 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 54), 42999, false); // Gnomeregan Exiles
1449 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 946), 42999, false); // Honor Hold
1450 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1037), 42999, false); // Alliance Vanguard
1451 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1068), 42999, false); // Explorers' League
1452 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1126), 42999, false); // The Frostborn
1453 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1094), 42999, false); // The Silver Covenant
1454 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1050), 42999, false); // Valiance Expedition
1455 break;
1456 case HORDE:
1457 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 76), 42999, false); // Orgrimmar
1458 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 68), 42999, false); // Undercity
1459 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 81), 42999, false); // Thunder Bluff
1460 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 911), 42999, false); // Silvermoon City
1461 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 729), 42999, false); // Frostwolf Clan
1462 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 941), 42999, false); // The Mag'har
1463 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 530), 42999, false); // Darkspear Trolls
1464 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 947), 42999, false); // Thrallmar
1465 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1052), 42999, false); // Horde Expedition
1466 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1067), 42999, false); // The Hand of Vengeance
1467 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1124), 42999, false); // The Sunreavers
1468 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1064), 42999, false); // The Taunka
1469 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1085), 42999, false); // Warsong Offensive
1470 break;
1471 default:
1472 break;
1473 }
1474 repMgr.SendState(nullptr);
1475 }
1476 }
1477
1478 // show time before shutdown if shutdown planned.
1479 if (sWorld->IsShuttingDown())
1480 sWorld->ShutdownMsg(true, pCurrChar);
1481
1482 if (sWorld->getBoolConfig(CONFIG_ALL_TAXI_PATHS))
1483 pCurrChar->SetTaxiCheater(true);
1484
1485 if (pCurrChar->IsGameMaster())
1487
1488 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Login Character: [{}] {} Level: {}, XP: {}/{} ({} left)",
1489 GetAccountId(), GetRemoteAddress(), pCurrChar->GetName(), pCurrChar->GetGUID().ToString(), pCurrChar->GetLevel(),
1491
1492 if (!pCurrChar->IsStandState() && !pCurrChar->HasUnitState(UNIT_STATE_STUNNED))
1494
1495 pCurrChar->UpdateAverageItemLevelTotal();
1496 pCurrChar->UpdateAverageItemLevelEquipped();
1497
1499
1501
1502 // Handle Login-Achievements (should be handled after loading)
1504
1505 sScriptMgr->OnPlayerLogin(pCurrChar, firstLogin);
1506
1507 TC_METRIC_EVENT("player_events", "Login", pCurrChar->GetName());
1508}
1509
1511{
1513
1516 features.CfgRealmID = 2;
1517 features.CfgRealmRecID = sRealmList->GetCurrentRealmId().Realm;
1518 features.CommercePricePollTimeSeconds = 300;
1519 features.VoiceEnabled = false;
1520
1521 // Enable guilds only.
1522 // This is required to restore old guild channel behavior for GMs.
1523 // The new club streams do not support sending messages through the guild channel when you are not in a guild.
1524 features.CommunitiesEnabled = true;
1525 features.BnetGroupsEnabled = false;
1526 features.CharacterCommunitiesEnabled = false;
1527 features.ClubPresenceAllowSubscribeAll = true;
1528 features.ClubPresenceUnsubscribeDelay = 60000;
1529
1530 features.EuropaTicketSystemStatus.emplace();
1531 features.EuropaTicketSystemStatus->ThrottleState.MaxTries = 10;
1532 features.EuropaTicketSystemStatus->ThrottleState.PerMilliseconds = 60000;
1533 features.EuropaTicketSystemStatus->ThrottleState.TryCount = 1;
1534 features.EuropaTicketSystemStatus->ThrottleState.LastResetTimeBeforeNow = 111111;
1535 features.TutorialEnabled = true;
1536 features.NPETutorialsEnabled = true;
1538
1539 features.EuropaTicketSystemStatus->TicketsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_TICKETS_ENABLED);
1540 features.EuropaTicketSystemStatus->BugsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_BUGS_ENABLED);
1541 features.EuropaTicketSystemStatus->ComplaintsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_COMPLAINTS_ENABLED);
1542 features.EuropaTicketSystemStatus->SuggestionsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_SUGGESTIONS_ENABLED);
1543
1545 features.IsChatMuted = !CanSpeak();
1546
1547 features.SpeakForMeAllowed = false;
1548
1549 for (World::GameRule const& gameRule : sWorld->GetGameRules())
1550 {
1551 WorldPackets::System::GameRuleValuePair& rule = features.GameRules.emplace_back();
1552 rule.Rule = AsUnderlyingType(gameRule.Rule);
1553 std::visit([&]<typename T>(T value)
1554 {
1555 if constexpr (std::is_same_v<T, float>)
1556 rule.ValueF = value;
1557 else
1558 rule.Value = value;
1559 }, gameRule.Value);
1560 }
1561
1562 features.AddonChatThrottle.MaxTries = 10;
1569
1570 SendPacket(features.Write());
1571}
1572
1577
1582
1584{
1585 switch (packet.Action)
1586 {
1588 {
1589 uint8 index = uint8(packet.TutorialBit >> 5);
1590 if (index >= MAX_ACCOUNT_TUTORIAL_VALUES)
1591 {
1592 TC_LOG_ERROR("network", "CMSG_TUTORIAL_FLAG received bad TutorialBit {}.", packet.TutorialBit);
1593 return;
1594 }
1595 uint32 flag = GetTutorialInt(index);
1596 flag |= (1 << (packet.TutorialBit & 0x1F));
1597 SetTutorialInt(index, flag);
1598 break;
1599 }
1601 for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i)
1602 SetTutorialInt(i, 0xFFFFFFFF);
1603 break;
1605 for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i)
1606 SetTutorialInt(i, 0x00000000);
1607 break;
1608 default:
1609 TC_LOG_ERROR("network", "CMSG_TUTORIAL_FLAG received unknown TutorialAction {}.", packet.Action);
1610 return;
1611 }
1612}
1613
1618
1623
1625{
1626 // prevent character rename to invalid name
1627 if (!normalizePlayerName(checkCharacterNameAvailability.Name))
1628 {
1630 return;
1631 }
1632
1633 ResponseCodes res = ObjectMgr::CheckPlayerName(checkCharacterNameAvailability.Name, GetSessionDbcLocale(), true);
1634 if (res != CHAR_NAME_SUCCESS)
1635 {
1637 return;
1638 }
1639
1640 // check name limitations
1641 if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(checkCharacterNameAvailability.Name))
1642 {
1644 return;
1645 }
1646
1647 // Ensure that there is no character with the desired new name
1649 stmt->setString(0, checkCharacterNameAvailability.Name);
1650
1652 .WithPreparedCallback([this, sequenceIndex = checkCharacterNameAvailability.SequenceIndex](PreparedQueryResult result)
1653 {
1654 SendPacket(WorldPackets::Character::CheckCharacterNameAvailabilityResult(sequenceIndex, result ? CHAR_CREATE_NAME_IN_USE : RESPONSE_SUCCESS).Write());
1655 }));
1656}
1657
1659{
1660 if (!IsLegitCharacterForAccount(request.RenameInfo->Guid))
1661 {
1662 TC_LOG_ERROR("network", "Account {}, IP: {} tried to rename character {}, but it does not belong to their account!",
1663 GetAccountId(), GetRemoteAddress(), request.RenameInfo->Guid.ToString());
1664 KickPlayer("WorldSession::HandleCharRenameOpcode rename character from a different account");
1665 return;
1666 }
1667
1668 // prevent character rename to invalid name
1669 if (!normalizePlayerName(request.RenameInfo->NewName))
1670 {
1672 return;
1673 }
1674
1676 if (res != CHAR_NAME_SUCCESS)
1677 {
1678 SendCharRename(res, request.RenameInfo.get());
1679 return;
1680 }
1681
1682 // check name limitations
1684 {
1686 return;
1687 }
1688
1689 // Ensure that there is no character with the desired new name
1691 stmt->setUInt64(0, request.RenameInfo->Guid.GetCounter());
1692 stmt->setString(1, request.RenameInfo->NewName);
1693
1695 .WithPreparedCallback([this, renameInfo = std::move(request.RenameInfo)](PreparedQueryResult result) mutable
1696 {
1697 HandleCharRenameCallBack(std::move(renameInfo), std::move(result));
1698 }));
1699}
1700
1701void WorldSession::HandleCharRenameCallBack(std::shared_ptr<WorldPackets::Character::CharacterRenameInfo> renameInfo, PreparedQueryResult result)
1702{
1703 if (!result)
1704 {
1705 SendCharRename(CHAR_CREATE_ERROR, renameInfo.get());
1706 return;
1707 }
1708
1709 Field* fields = result->Fetch();
1710
1711 std::string oldName = fields[0].GetString();
1712 uint16 atLoginFlags = fields[1].GetUInt16();
1713
1714 if (!(atLoginFlags & AT_LOGIN_RENAME))
1715 {
1716 SendCharRename(CHAR_CREATE_ERROR, renameInfo.get());
1717 return;
1718 }
1719
1720 atLoginFlags &= ~AT_LOGIN_RENAME;
1721
1722 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1723 ObjectGuid::LowType lowGuid = renameInfo->Guid.GetCounter();
1724
1725 // Update name and at_login flag in the db
1727 stmt->setString(0, renameInfo->NewName);
1728 stmt->setUInt16(1, atLoginFlags);
1729 stmt->setUInt64(2, lowGuid);
1730
1731 trans->Append(stmt);
1732
1733 // Removed declined name from db
1734 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_DECLINED_NAME);
1735 stmt->setUInt64(0, lowGuid);
1736
1737 trans->Append(stmt);
1738
1739 CharacterDatabase.CommitTransaction(trans);
1740
1741 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Character:[{}] ({}) Changed name to: {}",
1742 GetAccountId(), GetRemoteAddress(), oldName, renameInfo->Guid.ToString(), renameInfo->NewName);
1743
1744 SendCharRename(RESPONSE_SUCCESS, renameInfo.get());
1745
1746 sCharacterCache->UpdateCharacterData(renameInfo->Guid, renameInfo->NewName);
1747}
1748
1750{
1751 // not accept declined names for unsupported languages
1752 std::string name;
1753 if (!sCharacterCache->GetCharacterNameByGuid(packet.Player, name))
1754 {
1756 return;
1757 }
1758
1759 std::wstring wname;
1760 if (!Utf8toWStr(name, wname))
1761 {
1763 return;
1764 }
1765
1766 if (!isCyrillicCharacter(wname[0])) // name already stored as only single alphabet using
1767 {
1769 return;
1770 }
1771
1772 for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
1773 {
1774 if (!normalizePlayerName(packet.DeclinedNames.name[i]))
1775 {
1777 return;
1778 }
1779 }
1780
1781 if (!ObjectMgr::CheckDeclinedNames(wname, packet.DeclinedNames))
1782 {
1784 return;
1785 }
1786
1787 for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
1788 CharacterDatabase.EscapeString(packet.DeclinedNames.name[i]);
1789
1790 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1791
1793 stmt->setUInt64(0, packet.Player.GetCounter());
1794 trans->Append(stmt);
1795
1796 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_DECLINED_NAME);
1797 stmt->setUInt64(0, packet.Player.GetCounter());
1798
1799 for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; i++)
1800 stmt->setString(i + 1, packet.DeclinedNames.name[i]);
1801
1802 trans->Append(stmt);
1803
1804 CharacterDatabase.CommitTransaction(trans);
1805
1807}
1808
1810{
1812 if (packet.CustomizedChrModelID)
1813 {
1815 if (!conditionalChrModel)
1816 return;
1817
1818 if (ChrCustomizationReqEntry const* req = sChrCustomizationReqStore.LookupEntry(conditionalChrModel->ChrCustomizationReqID))
1819 if (!MeetsChrCustomizationReq(req, Races(packet.CustomizedRace), Classes(_player->GetClass()), false, customizations))
1820 return;
1821
1823 return;
1824 }
1825
1826 if (!ValidateAppearance(Races(_player->GetRace()), Classes(_player->GetClass()), Gender(packet.NewSex), customizations))
1827 return;
1828
1830 if (!go)
1831 {
1833 return;
1834 }
1835
1837 {
1839 return;
1840 }
1841
1842 int64 cost = _player->GetBarberShopCost(customizations);
1843
1844 // 0 - ok
1845 // 1, 3 - not enough money
1846 // 2 - you have to sit on barber chair
1847 if (!_player->HasEnoughMoney(cost))
1848 {
1850 return;
1851 }
1852
1854
1855 _player->ModifyMoney(-cost); // it isn't free
1857
1858 if (_player->GetNativeGender() != packet.NewSex)
1859 {
1862 _player->RestoreDisplayId(false);
1863 }
1864
1866
1868
1870
1871 sCharacterCache->UpdateCharacterGender(_player->GetGUID(), packet.NewSex);
1872}
1873
1875{
1876 if (!IsLegitCharacterForAccount(packet.CustomizeInfo->CharGUID))
1877 {
1878 TC_LOG_ERROR("entities.player.cheat", "Account {}, IP: {} tried to customise {}, but it does not belong to their account!",
1879 GetAccountId(), GetRemoteAddress(), packet.CustomizeInfo->CharGUID.ToString());
1880 KickPlayer("WorldSession::HandleCharCustomize Trying to customise character of another account");
1881 return;
1882 }
1883
1885 stmt->setUInt64(0, packet.CustomizeInfo->CharGUID.GetCounter());
1886
1888 .WithPreparedCallback([this, customizeInfo = std::move(packet.CustomizeInfo)](PreparedQueryResult result) mutable
1889 {
1890 HandleCharCustomizeCallback(std::move(customizeInfo), std::move(result));
1891 }));
1892}
1893
1894void WorldSession::HandleCharCustomizeCallback(std::shared_ptr<WorldPackets::Character::CharCustomizeInfo> customizeInfo, PreparedQueryResult result)
1895{
1896 if (!result)
1897 {
1898 SendCharCustomize(CHAR_CREATE_ERROR, customizeInfo.get());
1899 return;
1900 }
1901
1902 Field* fields = result->Fetch();
1903
1904 std::string oldName = fields[0].GetString();
1905 Races plrRace = Races(fields[1].GetUInt8());
1906 Classes plrClass = Classes(fields[2].GetUInt8());
1907 Gender plrGender = Gender(fields[3].GetUInt8());
1908 uint16 atLoginFlags = fields[4].GetUInt16();
1909
1910 if (!ValidateAppearance(plrRace, plrClass, plrGender, MakeChrCustomizationChoiceRange(customizeInfo->Customizations)))
1911 {
1912 SendCharCustomize(CHAR_CREATE_ERROR, customizeInfo.get());
1913 return;
1914 }
1915
1916 if (!(atLoginFlags & AT_LOGIN_CUSTOMIZE))
1917 {
1918 SendCharCustomize(CHAR_CREATE_ERROR, customizeInfo.get());
1919 return;
1920 }
1921
1922 // prevent character rename
1923 if (sWorld->getBoolConfig(CONFIG_PREVENT_RENAME_CUSTOMIZATION) && (customizeInfo->CharName != oldName))
1924 {
1925 SendCharCustomize(CHAR_NAME_FAILURE, customizeInfo.get());
1926 return;
1927 }
1928
1929 atLoginFlags &= ~AT_LOGIN_CUSTOMIZE;
1930
1931 // prevent character rename to invalid name
1932 if (!normalizePlayerName(customizeInfo->CharName))
1933 {
1934 SendCharCustomize(CHAR_NAME_NO_NAME, customizeInfo.get());
1935 return;
1936 }
1937
1938 ResponseCodes res = ObjectMgr::CheckPlayerName(customizeInfo->CharName, GetSessionDbcLocale(), true);
1939 if (res != CHAR_NAME_SUCCESS)
1940 {
1941 SendCharCustomize(res, customizeInfo.get());
1942 return;
1943 }
1944
1945 // check name limitations
1946 if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(customizeInfo->CharName))
1947 {
1948 SendCharCustomize(CHAR_NAME_RESERVED, customizeInfo.get());
1949 return;
1950 }
1951
1952 // character with this name already exist
1954 ObjectGuid newGuid = sCharacterCache->GetCharacterGuidByName(customizeInfo->CharName);
1955 if (!newGuid.IsEmpty())
1956 {
1957 if (newGuid != customizeInfo->CharGUID)
1958 {
1959 SendCharCustomize(CHAR_CREATE_NAME_IN_USE, customizeInfo.get());
1960 return;
1961 }
1962 }
1963
1964 CharacterDatabasePreparedStatement* stmt = nullptr;
1965 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1966
1967 ObjectGuid::LowType lowGuid = customizeInfo->CharGUID.GetCounter();
1968
1970 Player::SaveCustomizations(trans, lowGuid, MakeChrCustomizationChoiceRange(customizeInfo->Customizations));
1971
1973 {
1974 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_NAME_AT_LOGIN);
1975 stmt->setString(0, customizeInfo->CharName);
1976 stmt->setUInt16(1, atLoginFlags);
1977 stmt->setUInt64(2, lowGuid);
1978
1979 trans->Append(stmt);
1980
1981 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_DECLINED_NAME);
1982 stmt->setUInt64(0, lowGuid);
1983
1984 trans->Append(stmt);
1985 }
1986
1987 CharacterDatabase.CommitTransaction(trans);
1988
1989 sCharacterCache->UpdateCharacterData(customizeInfo->CharGUID, customizeInfo->CharName, customizeInfo->SexID);
1990
1991 SendCharCustomize(RESPONSE_SUCCESS, customizeInfo.get());
1992
1993 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}), Character[{}] ({}) Customized to: {}",
1994 GetAccountId(), GetRemoteAddress(), oldName, customizeInfo->CharGUID.ToString(), customizeInfo->CharName);
1995}
1996
1998{
1999 if (saveEquipmentSet.Set.SetID >= MAX_EQUIPMENT_SET_INDEX) // client set slots amount
2000 return;
2001
2002 if (saveEquipmentSet.Set.Type > EquipmentSetInfo::TRANSMOG)
2003 return;
2004
2005 for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i)
2006 {
2007 if (!(saveEquipmentSet.Set.IgnoreMask & (1 << i)))
2008 {
2009 if (saveEquipmentSet.Set.Type == EquipmentSetInfo::EQUIPMENT)
2010 {
2011 saveEquipmentSet.Set.Appearances[i] = 0;
2012
2013 ObjectGuid const& itemGuid = saveEquipmentSet.Set.Pieces[i];
2014 if (!itemGuid.IsEmpty())
2015 {
2017
2019 if (!item)
2020 return;
2021
2023 if (item->GetGUID() != itemGuid)
2024 return;
2025 }
2026 else
2027 saveEquipmentSet.Set.IgnoreMask |= 1 << i;
2028 }
2029 else
2030 {
2031 saveEquipmentSet.Set.Pieces[i].Clear();
2032 if (saveEquipmentSet.Set.Appearances[i])
2033 {
2034 if (!sItemModifiedAppearanceStore.LookupEntry(saveEquipmentSet.Set.Appearances[i]))
2035 return;
2036
2037 auto [hasAppearance, isTemporary] = GetCollectionMgr()->HasItemAppearance(saveEquipmentSet.Set.Appearances[i]);
2038 if (!hasAppearance)
2039 return;
2040 }
2041 else
2042 saveEquipmentSet.Set.IgnoreMask |= 1 << i;
2043 }
2044 }
2045 else
2046 {
2047 saveEquipmentSet.Set.Pieces[i].Clear();
2048 saveEquipmentSet.Set.Appearances[i] = 0;
2049 }
2050 }
2051
2052 saveEquipmentSet.Set.IgnoreMask &= 0x7FFFF;
2053 if (saveEquipmentSet.Set.Type == EquipmentSetInfo::EQUIPMENT)
2054 {
2055 saveEquipmentSet.Set.Enchants[0] = 0;
2056 saveEquipmentSet.Set.Enchants[1] = 0;
2057 }
2058 else
2059 {
2060 auto validateIllusion = [this](uint32 enchantId) -> bool
2061 {
2062 SpellItemEnchantmentEntry const* illusion = sSpellItemEnchantmentStore.LookupEntry(enchantId);
2064 return false;
2065
2067 return false;
2068
2069 if (illusion->ScalingClassRestricted > 0 && uint8(illusion->ScalingClassRestricted) != _player->GetClass())
2070 return false;
2071
2072 return true;
2073 };
2074
2075 if (saveEquipmentSet.Set.Enchants[0] && !validateIllusion(saveEquipmentSet.Set.Enchants[0]))
2076 return;
2077
2078 if (saveEquipmentSet.Set.Enchants[1] && !validateIllusion(saveEquipmentSet.Set.Enchants[1]))
2079 return;
2080 }
2081
2082 _player->SetEquipmentSet(saveEquipmentSet.Set);
2083}
2084
2089
2091{
2092 ObjectGuid ignoredItemGuid;
2093 ignoredItemGuid.SetRawValue(0x0C00040000000000, 0xFFFFFFFFFFFFFFFF);
2094
2095 for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i)
2096 {
2097 TC_LOG_DEBUG("entities.player.items", "{}: ContainerSlot: {}, Slot: {}", useEquipmentSet.Items[i].Item.ToString(), useEquipmentSet.Items[i].ContainerSlot, useEquipmentSet.Items[i].Slot);
2098
2099 // check if item slot is set to "ignored" (raw value == 1), must not be unequipped then
2100 if (useEquipmentSet.Items[i].Item == ignoredItemGuid)
2101 continue;
2102
2103 // Only equip weapons in combat
2105 continue;
2106
2107 Item* item = _player->GetItemByGuid(useEquipmentSet.Items[i].Item);
2108
2109 uint16 dstPos = i | (INVENTORY_SLOT_BAG_0 << 8);
2110
2111 if (!item)
2112 {
2114 if (!uItem)
2115 continue;
2116
2117 ItemPosCountVec itemPosCountVec;
2118 InventoryResult inventoryResult = _player->CanStoreItem(NULL_BAG, NULL_SLOT, itemPosCountVec, uItem, false);
2119 if (inventoryResult == EQUIP_ERR_OK)
2120 {
2121 if (_player->CanUnequipItem(dstPos, true) != EQUIP_ERR_OK)
2122 continue;
2123
2125 _player->StoreItem(itemPosCountVec, uItem, true);
2126 }
2127 else
2128 _player->SendEquipError(inventoryResult, uItem, nullptr);
2129 continue;
2130 }
2131
2132 if (item->GetPos() == dstPos)
2133 continue;
2134
2135 if (_player->CanEquipItem(i, dstPos, item, true) != EQUIP_ERR_OK)
2136 continue;
2137
2138 _player->SwapItem(item->GetPos(), dstPos);
2139 }
2140
2142 result.GUID = useEquipmentSet.GUID;
2143 result.Reason = 0; // 4 - equipment swap failed - inventory is full
2144 SendPacket(result.Write());
2145}
2146
2148{
2150 {
2151 TC_LOG_ERROR("entities.player.cheat", "Account {}, IP: {} tried to factionchange character {}, but it does not belong to their account!",
2152 GetAccountId(), GetRemoteAddress(), packet.RaceOrFactionChangeInfo->Guid.ToString());
2153 KickPlayer("WorldSession::HandleCharFactionOrRaceChange Trying to change faction of character of another account");
2154 return;
2155 }
2156
2158 stmt->setUInt64(0, packet.RaceOrFactionChangeInfo->Guid.GetCounter());
2159
2161 .WithPreparedCallback([this, factionChangeInfo = std::move(packet.RaceOrFactionChangeInfo)](PreparedQueryResult result) mutable
2162 {
2163 HandleCharRaceOrFactionChangeCallback(std::move(factionChangeInfo), std::move(result));
2164 }));
2165}
2166
2167void WorldSession::HandleCharRaceOrFactionChangeCallback(std::shared_ptr<WorldPackets::Character::CharRaceOrFactionChangeInfo> factionChangeInfo, PreparedQueryResult result)
2168{
2169 if (!result)
2170 {
2171 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2172 return;
2173 }
2174
2175 // get the players old (at this moment current) race
2176 CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(factionChangeInfo->Guid);
2177 if (!characterInfo)
2178 {
2179 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2180 return;
2181 }
2182
2183 std::string oldName = characterInfo->Name;
2184 uint8 oldRace = characterInfo->Race;
2185 uint8 playerClass = characterInfo->Class;
2186 uint8 level = characterInfo->Level;
2187
2188 if (!sObjectMgr->GetPlayerInfo(factionChangeInfo->RaceID, playerClass))
2189 {
2190 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2191 return;
2192 }
2193
2194 Field* fields = result->Fetch();
2195 uint16 atLoginFlags = fields[0].GetUInt16();
2196 std::string knownTitlesStr = fields[1].GetString();
2197 uint32 groupId = fields[2].GetUInt32();
2198
2199 uint16 usedLoginFlag = (factionChangeInfo->FactionChange ? AT_LOGIN_CHANGE_FACTION : AT_LOGIN_CHANGE_RACE);
2200 if (!(atLoginFlags & usedLoginFlag))
2201 {
2202 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2203 return;
2204 }
2205
2206 TeamId newTeamId = Player::TeamIdForRace(factionChangeInfo->RaceID);
2207 if (newTeamId == TEAM_NEUTRAL)
2208 {
2210 return;
2211 }
2212
2213 if (factionChangeInfo->FactionChange == (Player::TeamIdForRace(oldRace) == newTeamId))
2214 {
2215 SendCharFactionChange(factionChangeInfo->FactionChange ? CHAR_CREATE_CHARACTER_SWAP_FACTION : CHAR_CREATE_CHARACTER_RACE_ONLY, factionChangeInfo.get());
2216 return;
2217 }
2218
2220 {
2222 if (raceMaskDisabled.HasRace(factionChangeInfo->RaceID))
2223 {
2224 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2225 return;
2226 }
2227 }
2228
2229 // prevent character rename
2230 if (sWorld->getBoolConfig(CONFIG_PREVENT_RENAME_CUSTOMIZATION) && (factionChangeInfo->Name != oldName))
2231 {
2232 SendCharFactionChange(CHAR_NAME_FAILURE, factionChangeInfo.get());
2233 return;
2234 }
2235
2236 // prevent character rename to invalid name
2237 if (!normalizePlayerName(factionChangeInfo->Name))
2238 {
2239 SendCharFactionChange(CHAR_NAME_NO_NAME, factionChangeInfo.get());
2240 return;
2241 }
2242
2243 ResponseCodes res = ObjectMgr::CheckPlayerName(factionChangeInfo->Name, GetSessionDbcLocale(), true);
2244 if (res != CHAR_NAME_SUCCESS)
2245 {
2246 SendCharFactionChange(res, factionChangeInfo.get());
2247 return;
2248 }
2249
2250 // check name limitations
2251 if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(factionChangeInfo->Name))
2252 {
2253 SendCharFactionChange(CHAR_NAME_RESERVED, factionChangeInfo.get());
2254 return;
2255 }
2256
2257 // character with this name already exist
2258 ObjectGuid newGuid = sCharacterCache->GetCharacterGuidByName(factionChangeInfo->Name);
2259 if (!newGuid.IsEmpty())
2260 {
2261 if (newGuid != factionChangeInfo->Guid)
2262 {
2263 SendCharFactionChange(CHAR_CREATE_NAME_IN_USE, factionChangeInfo.get());
2264 return;
2265 }
2266 }
2267
2268 if (sArenaTeamMgr->GetArenaTeamByCaptain(factionChangeInfo->Guid))
2269 {
2271 return;
2272 }
2273
2274 // All checks are fine, deal with race change now
2275 ObjectGuid::LowType lowGuid = factionChangeInfo->Guid.GetCounter();
2276
2277 CharacterDatabasePreparedStatement* stmt = nullptr;
2278 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
2279
2280 // resurrect the character in case he's dead
2281 Player::OfflineResurrect(factionChangeInfo->Guid, trans);
2282
2283 // Name Change and update atLogin flags
2284 {
2285 CharacterDatabase.EscapeString(factionChangeInfo->Name);
2286
2287 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_NAME_AT_LOGIN);
2288 stmt->setString(0, factionChangeInfo->Name);
2289 stmt->setUInt16(1, uint16((atLoginFlags | AT_LOGIN_RESURRECT) & ~usedLoginFlag));
2290 stmt->setUInt64(2, lowGuid);
2291
2292 trans->Append(stmt);
2293
2294 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_DECLINED_NAME);
2295 stmt->setUInt64(0, lowGuid);
2296
2297 trans->Append(stmt);
2298 }
2299
2300 // Customize
2301 Player::SaveCustomizations(trans, lowGuid, MakeChrCustomizationChoiceRange(factionChangeInfo->Customizations));
2302
2303 // Race Change
2304 {
2305 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_RACE);
2306 stmt->setUInt8(0, factionChangeInfo->RaceID);
2308 stmt->setUInt64(2, lowGuid);
2309
2310 trans->Append(stmt);
2311 }
2312
2313 sCharacterCache->UpdateCharacterData(factionChangeInfo->Guid, factionChangeInfo->Name, factionChangeInfo->SexID, factionChangeInfo->RaceID);
2314
2315 if (oldRace != factionChangeInfo->RaceID)
2316 {
2317 // Switch Languages
2318 // delete all languages first
2319 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SKILL_LANGUAGES);
2320 stmt->setUInt64(0, lowGuid);
2321 trans->Append(stmt);
2322
2323 // Now add them back
2324 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_SKILL_LANGUAGE);
2325 stmt->setUInt64(0, lowGuid);
2326
2327 // Faction specific languages
2328 if (newTeamId == TEAM_HORDE)
2329 stmt->setUInt16(1, 109);
2330 else
2331 stmt->setUInt16(1, 98);
2332
2333 trans->Append(stmt);
2334
2335 // Race specific languages
2336 constexpr std::array<uint8, 4> racesWithoutSpecificLanguages = { RACE_ORC, RACE_HUMAN, RACE_MAGHAR_ORC, RACE_KUL_TIRAN };
2337 if (!advstd::ranges::contains(racesWithoutSpecificLanguages, factionChangeInfo->RaceID))
2338 {
2339 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_SKILL_LANGUAGE);
2340 stmt->setUInt64(0, lowGuid);
2341
2342 switch (factionChangeInfo->RaceID)
2343 {
2344 case RACE_DWARF:
2346 stmt->setUInt16(1, 111);
2347 break;
2348 case RACE_DRAENEI:
2350 stmt->setUInt16(1, 759);
2351 break;
2352 case RACE_GNOME:
2353 case RACE_MECHAGNOME:
2354 stmt->setUInt16(1, 313);
2355 break;
2356 case RACE_NIGHTELF:
2357 stmt->setUInt16(1, 113);
2358 break;
2359 case RACE_WORGEN:
2360 stmt->setUInt16(1, 791);
2361 break;
2362 case RACE_UNDEAD_PLAYER:
2363 stmt->setUInt16(1, 673);
2364 break;
2365 case RACE_TAUREN:
2367 stmt->setUInt16(1, 115);
2368 break;
2369 case RACE_TROLL:
2371 stmt->setUInt16(1, 315);
2372 break;
2373 case RACE_BLOODELF:
2374 case RACE_VOID_ELF:
2375 stmt->setUInt16(1, 137);
2376 break;
2377 case RACE_GOBLIN:
2378 stmt->setUInt16(1, 792);
2379 break;
2380 case RACE_NIGHTBORNE:
2381 stmt->setUInt16(1, 2464);
2382 break;
2383 case RACE_VULPERA:
2384 stmt->setUInt16(1, 2776);
2385 break;
2389 stmt->setUInt16(1, 905);
2390 break;
2393 stmt->setUInt16(1, 138);
2394 break;
2397 stmt->setUInt16(1, 140);
2398 break;
2400 case RACE_HARANIR_HORDE:
2401 stmt->setUInt16(1, 2987);
2402 break;
2403 default:
2404 TC_LOG_ERROR("entities.player", "Could not find language data for race ({}).", factionChangeInfo->RaceID);
2405 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2406 return;
2407 }
2408
2409 trans->Append(stmt);
2410 }
2411
2412 // Team Conversion
2413 if (factionChangeInfo->FactionChange)
2414 {
2415 // Delete all Flypaths
2416 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TAXI_PATH);
2417 stmt->setUInt64(0, lowGuid);
2418 trans->Append(stmt);
2419
2420 if (level > 7)
2421 {
2422 // Update Taxi path
2423 // this doesn't seem to be 100% blizzlike... but it can't really be helped.
2424 std::ostringstream taximaskstream;
2425 TaxiMask const& factionMask = newTeamId == TEAM_HORDE ? sHordeTaxiNodesMask : sAllianceTaxiNodesMask;
2426 for (std::size_t i = 0; i < factionMask.size(); ++i)
2427 {
2428 // i = (315 - 1) / 8 = 39
2429 // m = 1 << ((315 - 1) % 8) = 4
2430 uint8 deathKnightExtraNode = playerClass != CLASS_DEATH_KNIGHT || i != 39 ? 0 : 4;
2431 taximaskstream << uint32(factionMask[i] | deathKnightExtraNode) << ' ';
2432 }
2433
2434 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TAXIMASK);
2435 stmt->setString(0, taximaskstream.str());
2436 stmt->setUInt64(1, lowGuid);
2437 trans->Append(stmt);
2438 }
2439
2441 {
2442 // Reset guild
2443 if (Guild* guild = sGuildMgr->GetGuildById(characterInfo->GuildId))
2444 guild->DeleteMember(trans, factionChangeInfo->Guid, false, false);
2445
2446 Player::LeaveAllArenaTeams(factionChangeInfo->Guid);
2447 }
2448
2449 if (groupId && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
2450 {
2451 if (Group* group = sGroupMgr->GetGroupByDbStoreId(groupId))
2452 group->RemoveMember(factionChangeInfo->Guid);
2453 }
2454
2456 {
2457 // Delete Friend List
2458 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SOCIAL_BY_GUID);
2459 stmt->setUInt64(0, lowGuid);
2460 trans->Append(stmt);
2461
2462 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SOCIAL_BY_FRIEND);
2463 stmt->setUInt64(0, lowGuid);
2464 trans->Append(stmt);
2465 }
2466
2467 // Reset homebind and position
2468 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_HOMEBIND);
2469 stmt->setUInt64(0, lowGuid);
2470 trans->Append(stmt);
2471
2472 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PLAYER_HOMEBIND);
2473 stmt->setUInt64(0, lowGuid);
2474
2475 WorldLocation loc;
2476 uint16 zoneId = 0;
2477 if (newTeamId == TEAM_ALLIANCE)
2478 {
2479 loc.WorldRelocate(0, -8867.68f, 673.373f, 97.9034f, 0.0f);
2480 zoneId = 1519;
2481 }
2482 else
2483 {
2484 loc.WorldRelocate(1, 1633.33f, -4439.11f, 15.7588f, 0.0f);
2485 zoneId = 1637;
2486 }
2487
2488 stmt->setUInt16(1, loc.GetMapId());
2489 stmt->setUInt16(2, zoneId);
2490 stmt->setFloat(3, loc.GetPositionX());
2491 stmt->setFloat(4, loc.GetPositionY());
2492 stmt->setFloat(5, loc.GetPositionZ());
2493 trans->Append(stmt);
2494
2495 Player::SavePositionInDB(loc, zoneId, factionChangeInfo->Guid, trans);
2496
2497 // Achievement conversion
2498 for (auto [achiev_alliance, achiev_horde] : sObjectMgr->FactionChangeAchievements)
2499 {
2501 stmt->setUInt16(0, uint16(newTeamId == TEAM_ALLIANCE ? achiev_alliance : achiev_horde));
2502 stmt->setUInt64(1, lowGuid);
2503 trans->Append(stmt);
2504
2505 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_ACHIEVEMENT);
2506 stmt->setUInt32(0, uint16(newTeamId == TEAM_ALLIANCE ? achiev_alliance : achiev_horde));
2507 stmt->setUInt32(1, uint16(newTeamId == TEAM_ALLIANCE ? achiev_horde : achiev_alliance));
2508 stmt->setUInt64(2, lowGuid);
2509 trans->Append(stmt);
2510 }
2511
2512 // Item conversion
2513 ObjectMgr::CharacterConversionMap const& itemConversionMap = newTeamId == TEAM_ALLIANCE
2514 ? sObjectMgr->FactionChangeItemsHordeToAlliance
2515 : sObjectMgr->FactionChangeItemsAllianceToHorde;
2516 for (auto [oldItemId, newItemId] : itemConversionMap)
2517 {
2518 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_INVENTORY_FACTION_CHANGE);
2519 stmt->setUInt32(0, newItemId);
2520 stmt->setUInt32(1, oldItemId);
2521 stmt->setUInt64(2, lowGuid);
2522 trans->Append(stmt);
2523 }
2524
2525 // Delete all current quests
2526 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS);
2527 stmt->setUInt64(0, lowGuid);
2528 trans->Append(stmt);
2529
2530 // Quest conversion
2531 for (auto [quest_alliance, quest_horde] : sObjectMgr->FactionChangeQuests)
2532 {
2534 stmt->setUInt64(0, lowGuid);
2535 stmt->setUInt32(1, (newTeamId == TEAM_ALLIANCE ? quest_alliance : quest_horde));
2536 trans->Append(stmt);
2537
2539 stmt->setUInt32(0, (newTeamId == TEAM_ALLIANCE ? quest_alliance : quest_horde));
2540 stmt->setUInt32(1, (newTeamId == TEAM_ALLIANCE ? quest_horde : quest_alliance));
2541 stmt->setUInt64(2, lowGuid);
2542 trans->Append(stmt);
2543 }
2544
2545 // Mark all rewarded quests as "active" (will count for completed quests achievements)
2547 stmt->setUInt64(0, lowGuid);
2548 trans->Append(stmt);
2549
2550 // Disable all old-faction specific quests
2551 {
2552 ObjectMgr::QuestContainer const& questTemplates = sObjectMgr->GetQuestTemplates();
2553 for (auto const& [questId, quest] : questTemplates)
2554 {
2555 Trinity::RaceMask<std::array<int32, 2>> newRaceMask = newTeamId == TEAM_ALLIANCE
2556 ? RACEMASK_ALLIANCE_v<std::array<int32, 2>>
2557 : RACEMASK_HORDE_v<std::array<int32, 2>>;
2558 if (quest->GetAllowableRaces() != RACEMASK_ALL_v<std::array<int32, 2>> && (quest->GetAllowableRaces() & newRaceMask).IsEmpty())
2559 {
2561 stmt->setUInt64(0, lowGuid);
2562 stmt->setUInt32(1, questId);
2563 trans->Append(stmt);
2564 }
2565 }
2566 }
2567
2568 // Spell conversion
2569 for (auto [spell_alliance, spell_horde] : sObjectMgr->FactionChangeSpells)
2570 {
2571 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_BY_SPELL);
2572 stmt->setUInt32(0, (newTeamId == TEAM_ALLIANCE ? spell_alliance : spell_horde));
2573 stmt->setUInt64(1, lowGuid);
2574 trans->Append(stmt);
2575
2576 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_SPELL_FACTION_CHANGE);
2577 stmt->setUInt32(0, (newTeamId == TEAM_ALLIANCE ? spell_alliance : spell_horde));
2578 stmt->setUInt32(1, (newTeamId == TEAM_ALLIANCE ? spell_horde : spell_alliance));
2579 stmt->setUInt64(2, lowGuid);
2580 trans->Append(stmt);
2581 }
2582
2583 // Reputation conversion
2584 for (auto [reputation_alliance, reputation_horde] : sObjectMgr->FactionChangeReputation)
2585 {
2586 uint32 newReputation = (newTeamId == TEAM_ALLIANCE) ? reputation_alliance : reputation_horde;
2587 uint32 oldReputation = (newTeamId == TEAM_ALLIANCE) ? reputation_horde : reputation_alliance;
2588
2589 // select old standing set in db
2590 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_REP_BY_FACTION);
2591 stmt->setUInt32(0, oldReputation);
2592 stmt->setUInt64(1, lowGuid);
2593
2594 if (PreparedQueryResult reputationResult = CharacterDatabase.Query(stmt))
2595 {
2596 fields = reputationResult->Fetch();
2597 int32 oldDBRep = fields[0].GetInt32();
2598 FactionEntry const* factionEntry = sFactionStore.LookupEntry(oldReputation);
2599
2600 // old base reputation
2601 int32 oldBaseRep = sObjectMgr->GetBaseReputationOf(factionEntry, oldRace, playerClass);
2602
2603 // new base reputation
2604 int32 newBaseRep = sObjectMgr->GetBaseReputationOf(sFactionStore.LookupEntry(newReputation), factionChangeInfo->RaceID, playerClass);
2605
2606 // final reputation shouldnt change
2607 int32 FinalRep = oldDBRep + oldBaseRep;
2608 int32 newDBRep = FinalRep - newBaseRep;
2609
2610 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_REP_BY_FACTION);
2611 stmt->setUInt32(0, newReputation);
2612 stmt->setUInt64(1, lowGuid);
2613 trans->Append(stmt);
2614
2615 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_REP_FACTION_CHANGE);
2616 stmt->setUInt16(0, uint16(newReputation));
2617 stmt->setInt32(1, newDBRep);
2618 stmt->setUInt16(2, uint16(oldReputation));
2619 stmt->setUInt64(3, lowGuid);
2620 trans->Append(stmt);
2621 }
2622 }
2623
2624 // Title conversion
2625 if (!knownTitlesStr.empty())
2626 {
2627 std::vector<std::string_view> tokens = Trinity::Tokenize(knownTitlesStr, ' ', false);
2628 std::vector<uint32> knownTitles;
2629
2630 for (std::string_view token : tokens)
2631 {
2632 if (Optional<uint32> thisMask = Trinity::StringTo<uint32>(token))
2633 knownTitles.push_back(*thisMask);
2634 else
2635 {
2636 TC_LOG_WARN("entities.player", "{} has invalid title data '{}' - skipped, this may result in titles being lost",
2637 GetPlayerInfo(), token);
2638 knownTitles.push_back(0);
2639 }
2640 }
2641
2642 for (auto [title_alliance, title_horde] : sObjectMgr->FactionChangeTitles)
2643 {
2644 CharTitlesEntry const* atitleInfo = sCharTitlesStore.AssertEntry(title_alliance);
2645 CharTitlesEntry const* htitleInfo = sCharTitlesStore.AssertEntry(title_horde);
2646 // new team
2647 if (newTeamId == TEAM_ALLIANCE)
2648 {
2649 uint32 bitIndex = htitleInfo->MaskID;
2650 uint32 index = bitIndex / 32;
2651 if (index >= knownTitles.size())
2652 continue;
2653
2654 uint32 old_flag = 1 << (bitIndex % 32);
2655 uint32 new_flag = 1 << (atitleInfo->MaskID % 32);
2656 if (knownTitles[index] & old_flag)
2657 {
2658 knownTitles[index] &= ~old_flag;
2659 // use index of the new title
2660 knownTitles[atitleInfo->MaskID / 32] |= new_flag;
2661 }
2662 }
2663 else
2664 {
2665 uint32 bitIndex = htitleInfo->MaskID;
2666 uint32 index = bitIndex / 32;
2667 if (index >= knownTitles.size())
2668 continue;
2669
2670 uint32 old_flag = 1 << (bitIndex % 32);
2671 uint32 new_flag = 1 << (htitleInfo->MaskID % 32);
2672 if (knownTitles[index] & old_flag)
2673 {
2674 knownTitles[index] &= ~old_flag;
2675 // use index of the new title
2676 knownTitles[htitleInfo->MaskID / 32] |= new_flag;
2677 }
2678 }
2679
2680 std::ostringstream ss;
2681 for (uint32 mask : knownTitles)
2682 ss << mask << ' ';
2683
2684 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TITLES_FACTION_CHANGE);
2685 stmt->setString(0, ss.str());
2686 stmt->setUInt64(1, lowGuid);
2687 trans->Append(stmt);
2688
2689 // unset any currently chosen title
2690 stmt = CharacterDatabase.GetPreparedStatement(CHAR_RES_CHAR_TITLES_FACTION_CHANGE);
2691 stmt->setUInt64(0, lowGuid);
2692 trans->Append(stmt);
2693 }
2694 }
2695 }
2696 }
2697
2698 CharacterDatabase.CommitTransaction(trans);
2699
2700 TC_LOG_DEBUG("entities.player", "{} (IP: {}) changed race from {} to {}", GetPlayerInfo(), GetRemoteAddress(), oldRace, factionChangeInfo->RaceID);
2701
2702 SendCharFactionChange(RESPONSE_SUCCESS, factionChangeInfo.get());
2703}
2704
2706{
2707 if (!Player::IsValidRace(packet.Race))
2708 {
2709 TC_LOG_ERROR("misc", "Invalid race ({}) sent by accountId: {}", packet.Race, GetAccountId());
2710 return;
2711 }
2712
2713 if (!Player::IsValidGender(packet.Sex))
2714 {
2715 TC_LOG_ERROR("misc", "Invalid gender ({}) sent by accountId: {}", packet.Sex, GetAccountId());
2716 return;
2717 }
2718
2720 result.Success = true;
2721 result.Name = sDB2Manager.GetNameGenEntry(packet.Race, packet.Sex);
2722
2723 SendPacket(result.Write());
2724}
2725
2727{
2728 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
2729
2730 for (WorldPackets::Character::ReorderCharacters::ReorderInfo const& reorderInfo : reorderChars.Entries)
2731 {
2733 stmt->setUInt8(0, reorderInfo.NewPosition);
2734 stmt->setUInt64(1, reorderInfo.PlayerGUID.GetCounter());
2735 stmt->setUInt32(2, GetAccountId());
2736 trans->Append(stmt);
2737 }
2738
2739 CharacterDatabase.CommitTransaction(trans);
2740}
2741
2743{
2744 // Only players that has not yet gained any experience can use this
2745 if (*_player->m_activePlayerData->XP)
2746 return;
2747
2748 if (ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(_player->GetClass()))
2749 {
2750 if (classEntry->CinematicSequenceID)
2751 _player->SendCinematicStart(classEntry->CinematicSequenceID);
2752 else if (ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(_player->GetRace()))
2753 _player->SendCinematicStart(raceEntry->CinematicSequenceID);
2754 }
2755}
2756
2758{
2760 stmt->setUInt32(0, GetBattlenetAccountId());
2761
2762 _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback([this](PreparedQueryResult result)
2763 {
2764 HandleUndeleteCooldownStatusCallback(std::move(result));
2765 }));
2766}
2767
2769{
2770 uint32 cooldown = 0;
2772 if (result)
2773 {
2774 uint32 lastUndelete = result->Fetch()[0].GetUInt32();
2776 if (lastUndelete + maxCooldown > now)
2777 cooldown = std::max<uint32>(0, lastUndelete + maxCooldown - now);
2778 }
2779
2780 SendUndeleteCooldownStatusResponse(cooldown, maxCooldown);
2781}
2782
2784{
2786 {
2788 return;
2789 }
2790
2792 stmt->setUInt32(0, GetBattlenetAccountId());
2793
2794 std::shared_ptr<WorldPackets::Character::CharacterUndeleteInfo> undeleteInfo = undeleteCharacter.UndeleteInfo;
2796 .WithChainingPreparedCallback([this, undeleteInfo](QueryCallback& queryCallback, PreparedQueryResult result)
2797 {
2798 if (result)
2799 {
2800 uint32 lastUndelete = result->Fetch()[0].GetUInt32();
2801 uint32 maxCooldown = sWorld->getIntConfig(CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_COOLDOWN);
2802 if (lastUndelete && (lastUndelete + maxCooldown > GameTime::GetGameTime()))
2803 {
2804 SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_COOLDOWN, undeleteInfo.get());
2805 return;
2806 }
2807 }
2808
2810 stmt->setUInt64(0, undeleteInfo->CharacterGuid.GetCounter());
2811 queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt));
2812 })
2813 .WithChainingPreparedCallback([this, undeleteInfo](QueryCallback& queryCallback, PreparedQueryResult result)
2814 {
2815 if (!result)
2816 {
2817 SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_CHAR_CREATE, undeleteInfo.get());
2818 return;
2819 }
2820
2821 Field* fields = result->Fetch();
2822 undeleteInfo->Name = fields[1].GetString();
2823 uint32 account = fields[2].GetUInt32();
2824
2825 if (account != GetAccountId())
2826 {
2827 SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_UNKNOWN, undeleteInfo.get());
2828 return;
2829 }
2830
2832 stmt->setString(0, undeleteInfo->Name);
2833 queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt));
2834 })
2835 .WithChainingPreparedCallback([this, undeleteInfo](QueryCallback& queryCallback, PreparedQueryResult result)
2836 {
2837 if (result)
2838 {
2839 SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_NAME_TAKEN_BY_THIS_ACCOUNT, undeleteInfo.get());
2840 return;
2841 }
2842
2848
2850 stmt->setUInt32(0, GetAccountId());
2851 queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt));
2852 })
2853 .WithPreparedCallback([this, undeleteInfo](PreparedQueryResult result)
2854 {
2855 if (result)
2856 {
2857 Field* fields = result->Fetch();
2858
2859 if (fields[0].GetUInt64() >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM)) // SQL's COUNT() returns uint64 but it will always be less than uint8.Max
2860 {
2861 SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_CHAR_CREATE, undeleteInfo.get());
2862 return;
2863 }
2864 }
2865
2867 stmt->setString(0, undeleteInfo->Name);
2868 stmt->setUInt32(1, GetAccountId());
2869 stmt->setUInt64(2, undeleteInfo->CharacterGuid.GetCounter());
2870 CharacterDatabase.Execute(stmt);
2871
2873 loginStmt->setUInt32(0, GetBattlenetAccountId());
2874 LoginDatabase.Execute(loginStmt);
2875
2876 sCharacterCache->UpdateCharacterInfoDeleted(undeleteInfo->CharacterGuid, false, undeleteInfo->Name);
2877
2878 SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_OK, undeleteInfo.get());
2879 }));
2880}
2881
2904
2905void WorldSession::SendCharCreate(ResponseCodes result, ObjectGuid const& guid /*= ObjectGuid::Empty*/)
2906{
2908 response.Code = result;
2909 response.Guid = guid;
2910
2911 SendPacket(response.Write());
2912}
2913
2915{
2917 response.Code = result;
2918
2919 SendPacket(response.Write());
2920}
2921
2923{
2925 packet.Result = result;
2926 packet.Name = renameInfo->NewName;
2927 if (result == RESPONSE_SUCCESS)
2928 packet.Guid = renameInfo->Guid;
2929
2930 SendPacket(packet.Write());
2931}
2932
2934{
2935 if (result == RESPONSE_SUCCESS)
2936 {
2937 WorldPackets::Character::CharCustomizeSuccess response(customizeInfo);
2938 SendPacket(response.Write());
2939 }
2940 else
2941 {
2943 failed.Result = uint8(result);
2944 failed.CharGUID = customizeInfo->CharGUID;
2945 SendPacket(failed.Write());
2946 }
2947}
2948
2950{
2952 packet.Result = result;
2953 packet.Guid = factionChangeInfo->Guid;
2954
2955 if (result == RESPONSE_SUCCESS)
2956 {
2957 packet.Display.emplace();
2958 packet.Display->Name = factionChangeInfo->Name;
2959 packet.Display->SexID = factionChangeInfo->SexID;
2960 packet.Display->Customizations = &factionChangeInfo->Customizations;
2961 packet.Display->RaceID = factionChangeInfo->RaceID;
2962 }
2963
2964 SendPacket(packet.Write());
2965}
2966
2968{
2970 packet.ResultCode = result;
2971 packet.Player = guid;
2972
2973 SendPacket(packet.Write());
2974}
2975
2977{
2979 response.OnCooldown = (currentCooldown > 0);
2980 response.MaxCooldown = maxCooldown;
2981 response.CurrentCooldown = currentCooldown;
2982
2983 SendPacket(response.Write());
2984}
2985
2987{
2989 response.UndeleteInfo = undeleteInfo;
2990 response.Result = result;
2991
2992 SendPacket(response.Write());
2993}
#define sArenaTeamMgr
#define sCalendarMgr
#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_SEL_CHARACTER_TRANSMOG_OUTFIT_SLOT
@ 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_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES_SPAWN_TRACKING
@ 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_INS_PLAYER_HOMEBIND
@ CHAR_INS_CHAR_SKILL_LANGUAGE
@ CHAR_SEL_CHARACTER_BANK_TAB_SETTINGS
@ CHAR_SEL_CHARACTER_BGDATA
@ CHAR_SEL_CHARACTER_SOCIALLIST
@ CHAR_SEL_PLAYER_DATA_ELEMENTS_CHARACTER
@ 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_PLAYER_DATA_FLAGS_CHARACTER
@ 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_CHARACTER_TRANSMOG_OUTFIT
@ 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_TRANSMOG_OUTFIT_SITUATION
@ 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
TaxiMask sAllianceTaxiNodesMask
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< ChrCustomizationReqEntry > sChrCustomizationReqStore("ChrCustomizationReq.db2", &ChrCustomizationReqLoadInfo::Instance)
DB2Storage< SpellItemEnchantmentEntry > sSpellItemEnchantmentStore("SpellItemEnchantment.db2", &SpellItemEnchantmentLoadInfo::Instance)
DB2Storage< FactionEntry > sFactionStore("Faction.db2", &FactionLoadInfo::Instance)
TaxiMask sHordeTaxiNodesMask
#define sDB2Manager
Definition DB2Stores.h:569
constexpr size_t PLAYER_EXPLORED_ZONES_SIZE
Definition DBCEnums.h:160
@ MoneySpentAtBarberShop
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
SQLTransaction< LoginDatabaseConnection > LoginDatabaseTransaction
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
uint8_t uint8
Definition Define.h:156
int64_t int64
Definition Define.h:149
int32_t int32
Definition Define.h:150
uint64_t uint64
Definition Define.h:153
#define UI64LIT(N)
Definition Define.h:139
uint16_t uint16
Definition Define.h:155
uint32_t uint32
Definition Define.h:154
#define MAX_EQUIPMENT_SET_INDEX
#define sGroupMgr
Definition GroupMgr.h:66
#define sGuildMgr
Definition GuildMgr.h:76
@ ERR_GUILDEMBLEM_INVALIDVENDOR
Definition Guild.h:226
@ ERR_GUILDEMBLEM_INVALID_TABARD_COLORS
Definition Guild.h:222
@ ERR_GUILDEMBLEM_SUCCESS
Definition Guild.h:221
InventoryResult
Definition ItemDefines.h:25
@ EQUIP_ERR_OK
Definition ItemDefines.h:26
@ LANG_RESET_SPELLS
Definition Language.h:260
@ LANG_RESET_TALENTS
Definition Language.h:261
@ LANG_GM_ON
Definition Language.h:387
@ LOG_LEVEL_INFO
Definition LogCommon.h:29
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:181
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:184
#define sLog
Definition Log.h:156
#define TC_LOG_WARN(filterType__, message__,...)
Definition Log.h:187
@ LOGIN_SEL_LAST_CHAR_UNDELETE
@ LOGIN_REP_REALM_CHARACTERS
@ LOGIN_UPD_LAST_CHAR_UNDELETE
@ LOGIN_SEL_SUM_REALM_CHARACTERS
@ LOGIN_UPD_ACCOUNT_ONLINE
#define TC_METRIC_EVENT(category, title, description)
Definition Metric.h:201
bool normalizePlayerName(std::string &name)
#define sObjectMgr
Definition ObjectMgr.h:1885
@ CONNECTION_TYPE_INSTANCE
Definition Opcodes.h:29
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
@ EQUIPMENT_SLOT_MAINHAND
Definition Player.h:744
@ EQUIPMENT_SLOT_END
Definition Player.h:748
@ EQUIPMENT_SLOT_OFFHAND
Definition Player.h:745
std::vector< ItemPosCount > ItemPosCountVec
Definition Player.h:841
@ PLAYER_EXTRA_HAS_RACE_CHANGED
Definition Player.h:627
@ PLAYER_FLAGS_CONTESTED_PVP
Definition Player.h:528
@ PLAYER_FLAGS_RESTING
Definition Player.h:525
@ PLAYER_LOCAL_FLAG_OVERRIDE_TRANSPORT_SERVER_TIME
Definition Player.h:585
@ AT_LOGIN_RESET_TALENTS
Definition Player.h:640
@ AT_LOGIN_RESET_SPELLS
Definition Player.h:639
@ AT_LOGIN_RESET_PET_TALENTS
Definition Player.h:642
@ AT_LOGIN_FIRST
Definition Player.h:643
@ AT_LOGIN_RESURRECT
Definition Player.h:646
@ AT_LOGIN_CUSTOMIZE
Definition Player.h:641
@ AT_LOGIN_RENAME
Definition Player.h:638
@ AT_LOGIN_CHANGE_RACE
Definition Player.h:645
@ AT_LOGIN_CHANGE_FACTION
Definition Player.h:644
#define INVENTORY_SLOT_BAG_0
Definition Player.h:723
Trinity::IteratorPair< UF::ChrCustomizationChoice const * > MakeChrCustomizationChoiceRange(Container const &container)
Definition Player.h:3449
@ PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS
Definition Player.h:988
@ PLAYER_LOGIN_QUERY_LOAD_CUSTOMIZATIONS
Definition Player.h:959
@ PLAYER_LOGIN_QUERY_LOAD_CURRENCY
Definition Player.h:1013
@ PLAYER_LOGIN_QUERY_LOAD_GLYPHS
Definition Player.h:1001
@ PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES
Definition Player.h:990
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_REW
Definition Player.h:1009
@ MAX_PLAYER_LOGIN_QUERY
Definition Player.h:1027
@ PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS
Definition Player.h:971
@ PLAYER_LOGIN_QUERY_LOAD_AURA_EFFECTS
Definition Player.h:962
@ PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES
Definition Player.h:1010
@ PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS
Definition Player.h:1011
@ PLAYER_LOGIN_QUERY_LOAD_SOCIAL_LIST
Definition Player.h:986
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWERS
Definition Player.h:1020
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA
Definition Player.h:968
@ PLAYER_LOGIN_QUERY_LOAD_TRAIT_CONFIGS
Definition Player.h:1023
@ PLAYER_LOGIN_QUERY_LOAD_SKILLS
Definition Player.h:1005
@ PLAYER_LOGIN_QUERY_LOAD_BG_DATA
Definition Player.h:1000
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA_PROGRESS
Definition Player.h:969
@ PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFITS
Definition Player.h:999
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWER_ABILITIES
Definition Player.h:1021
@ PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFIT_SLOT
Definition Player.h:998
@ PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA
Definition Player.h:1004
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS
Definition Player.h:980
@ PLAYER_LOGIN_QUERY_LOAD_PET_SLOTS
Definition Player.h:1016
@ PLAYER_LOGIN_QUERY_LOAD_ARTIFACTS
Definition Player.h:974
@ PLAYER_LOGIN_QUERY_LOAD_INVENTORY
Definition Player.h:973
@ PLAYER_LOGIN_QUERY_LOAD_REPUTATION
Definition Player.h:972
@ PLAYER_LOGIN_QUERY_LOAD_AZERITE_MILESTONE_POWERS
Definition Player.h:976
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON_BLUEPRINTS
Definition Player.h:1018
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_AZERITE
Definition Player.h:982
@ PLAYER_LOGIN_QUERY_LOAD_BANK_TAB_SETTINGS
Definition Player.h:1026
@ PLAYER_LOGIN_QUERY_LOAD_FROM
Definition Player.h:958
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS
Definition Player.h:966
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES
Definition Player.h:967
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_AZERITE_UNLOCKED_ESSENCE
Definition Player.h:984
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON_BUILDINGS
Definition Player.h:1019
@ PLAYER_LOGIN_QUERY_LOAD_DATA_FLAGS
Definition Player.h:1025
@ PLAYER_LOGIN_QUERY_LOAD_WEEKLY_QUEST_STATUS
Definition Player.h:1006
@ PLAYER_LOGIN_QUERY_LOAD_SPELL_CHARGES
Definition Player.h:989
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_AZERITE_MILESTONE_POWER
Definition Player.h:983
@ PLAYER_LOGIN_QUERY_LOAD_AZERITE
Definition Player.h:975
@ PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS
Definition Player.h:1012
@ PLAYER_LOGIN_QUERY_LOAD_GUILD
Definition Player.h:991
@ PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS
Definition Player.h:995
@ PLAYER_LOGIN_QUERY_LOAD_MAILS
Definition Player.h:979
@ PLAYER_LOGIN_QUERY_LOAD_AURAS
Definition Player.h:961
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_AZERITE_EMPOWERED
Definition Player.h:985
@ PLAYER_LOGIN_QUERY_LOAD_TALENTS
Definition Player.h:1002
@ PLAYER_LOGIN_QUERY_LOAD_AZERITE_UNLOCKED_ESSENCES
Definition Player.h:977
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON
Definition Player.h:1017
@ PLAYER_LOGIN_QUERY_LOAD_BANNED
Definition Player.h:1008
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_ARTIFACT
Definition Player.h:981
@ PLAYER_LOGIN_QUERY_LOAD_ARENA_INFO
Definition Player.h:992
@ PLAYER_LOGIN_QUERY_LOAD_GROUP
Definition Player.h:960
@ PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS
Definition Player.h:994
@ PLAYER_LOGIN_QUERY_LOAD_HOME_BIND
Definition Player.h:987
@ PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION
Definition Player.h:1015
@ PLAYER_LOGIN_QUERY_LOAD_SPELLS
Definition Player.h:964
@ PLAYER_LOGIN_QUERY_LOAD_SPELL_FAVORITES
Definition Player.h:965
@ PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFIT
Definition Player.h:996
@ PLAYER_LOGIN_QUERY_LOAD_DATA_ELEMENTS
Definition Player.h:1024
@ PLAYER_LOGIN_QUERY_LOAD_TRAIT_ENTRIES
Definition Player.h:1022
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_SPAWN_TRACKING
Definition Player.h:970
@ PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFIT_SITUATION
Definition Player.h:997
@ PLAYER_LOGIN_QUERY_LOAD_AZERITE_EMPOWERED
Definition Player.h:978
@ PLAYER_LOGIN_QUERY_LOAD_PVP_TALENTS
Definition Player.h:1003
@ PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES
Definition Player.h:1014
@ PLAYER_LOGIN_QUERY_LOAD_RANDOM_BG
Definition Player.h:1007
@ PLAYER_LOGIN_QUERY_LOAD_AURA_STORED_LOCATIONS
Definition Player.h:963
@ PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS
Definition Player.h:993
Races
Definition RaceMask.h:27
@ RACE_DARK_IRON_DWARF
Definition RaceMask.h:62
@ RACE_TROLL
Definition RaceMask.h:36
@ RACE_UNDEAD_PLAYER
Definition RaceMask.h:33
@ RACE_PANDAREN_NEUTRAL
Definition RaceMask.h:52
@ RACE_ORC
Definition RaceMask.h:30
@ RACE_LIGHTFORGED_DRAENEI
Definition RaceMask.h:58
@ RACE_NONE
Definition RaceMask.h:28
@ RACE_DRAENEI
Definition RaceMask.h:39
@ RACE_EARTHEN_DWARF_HORDE
Definition RaceMask.h:78
@ RACE_NIGHTBORNE
Definition RaceMask.h:55
@ RACE_HIGHMOUNTAIN_TAUREN
Definition RaceMask.h:56
@ RACE_HARANIR_HORDE
Definition RaceMask.h:83
@ RACE_EARTHEN_DWARF_ALLIANCE
Definition RaceMask.h:79
@ RACE_DRACTHYR_HORDE
Definition RaceMask.h:67
@ RACE_ZANDALARI_TROLL
Definition RaceMask.h:59
@ RACE_VOID_ELF
Definition RaceMask.h:57
@ RACE_NIGHTELF
Definition RaceMask.h:32
@ RACE_BLOODELF
Definition RaceMask.h:38
@ RACE_DWARF
Definition RaceMask.h:31
@ RACE_GNOME
Definition RaceMask.h:35
@ RACE_GOBLIN
Definition RaceMask.h:37
@ RACE_KUL_TIRAN
Definition RaceMask.h:60
@ RACE_HUMAN
Definition RaceMask.h:29
@ RACE_DRACTHYR_ALLIANCE
Definition RaceMask.h:66
@ RACE_WORGEN
Definition RaceMask.h:50
@ RACE_PANDAREN_ALLIANCE
Definition RaceMask.h:53
@ RACE_VULPERA
Definition RaceMask.h:63
@ RACE_MECHAGNOME
Definition RaceMask.h:65
@ RACE_HARANIR_ALLIANCE
Definition RaceMask.h:80
@ RACE_MAGHAR_ORC
Definition RaceMask.h:64
@ RACE_PANDAREN_HORDE
Definition RaceMask.h:54
@ RACE_TAUREN
Definition RaceMask.h:34
#define sRealmList
Definition RealmList.h:93
#define sScriptMgr
Definition ScriptMgr.h:1449
Classes
@ CLASS_DEATH_KNIGHT
@ CLASS_DEMON_HUNTER
@ CLASS_EVOKER
@ CHARACTER_FLAG_2_FACTION_CHANGE
@ CHARACTER_FLAG_2_RACE_CHANGE
@ CHARACTER_FLAG_2_CUSTOMIZE
@ GAMEOBJECT_TYPE_BARBER_CHAIR
Gender
ResponseCodes
@ CHAR_DELETE_SUCCESS
@ CHAR_CREATE_TIMERUNNING
@ 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
@ TEAM_NEUTRAL
@ TEAM_ALLIANCE
@ TEAM_HORDE
#define MAX_CHARACTERS_PER_REALM
@ TUTORIAL_ACTION_RESET
@ TUTORIAL_ACTION_CLEAR
@ TUTORIAL_ACTION_UPDATE
@ ALLIANCE
@ HORDE
@ COMPLAINT_ENABLED_WITH_AUTO_IGNORE
@ CHARACTER_FLAG_LOCKED_BY_BILLING
@ CHARACTER_FLAG_LOCKED_FOR_TRANSFER
#define MAX_ACCOUNT_TUTORIAL_VALUES
@ FRIEND_ONLINE
Definition SocialMgr.h:71
#define sSocialMgr
Definition SocialMgr.h:173
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
@ UNIT_NPC_FLAG_NONE
@ UNIT_NPC_FLAG_2_PERSONAL_TABARD_DESIGNER
@ UNIT_BYTE2_FLAG_FFA_PVP
Definition UnitDefines.h:95
@ DEAD
Definition Unit.h:255
@ UNIT_STATE_STUNNED
Definition Unit.h:264
@ NULL_BAG
Definition Unit.h:63
@ NULL_SLOT
Definition Unit.h:64
bool Utf8toWStr(char const *utf8str, size_t csize, wchar_t *wstr, size_t &wsize)
Definition Util.cpp:336
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:565
bool isCyrillicCharacter(wchar_t wchar)
Definition Util.h:172
#define PER_CHARACTER_CACHE_MASK
DeclinedNameResult
@ DECLINED_NAMES_RESULT_SUCCESS
@ DECLINED_NAMES_RESULT_ERROR
#define GLOBAL_CACHE_MASK
#define ALL_ACCOUNT_DATA_CACHE_MASK
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
void PSendSysMessage(char const *fmt, Args &&... args)
Definition Chat.h:62
std::pair< bool, bool > HasItemAppearance(uint32 itemModifiedAppearanceId) const
static bool IsPlayerMeetingCondition(Player const *player, uint32 conditionId)
static ConditionalChrModelEntry const * GetConditionalChrModel(int32 chrModelId)
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:94
uint64 GetUInt64() const noexcept
Definition Field.cpp:71
uint32 GetUInt32() const noexcept
Definition Field.cpp:57
uint16 GetUInt16() const noexcept
Definition Field.cpp:43
uint8 GetUInt8() const noexcept
Definition Field.cpp:29
int32 GetInt32() const noexcept
Definition Field.cpp:64
std::string GetString() const noexcept
Definition Field.cpp:113
GameObjectTemplate const * GetGOInfo() const
Definition GameObject.h:203
Definition Group.h:205
Definition Guild.h:329
Definition Item.h:179
uint16 GetPos() const
Definition Item.h:294
LoginQueryHolder(uint32 accountId, ObjectGuid guid)
ObjectGuid GetGuid() const
uint32 GetAccountId() const
virtual bool AddPlayerToMap(Player *player, bool initPlayer=true)
Definition Map.cpp:382
LowType GetCounter() const
Definition ObjectGuid.h:336
static ObjectGuid const Empty
Definition ObjectGuid.h:314
bool IsEmpty() const
Definition ObjectGuid.h:362
std::string ToString() const
void SetRawValue(std::span< uint8 const > rawBytes)
uint64 LowType
Definition ObjectGuid.h:321
void Clear()
Definition ObjectGuid.h:329
static bool CheckDeclinedNames(const std::wstring &w_ownname, DeclinedName const &names)
std::map< uint32, uint32 > CharacterConversionMap
Definition ObjectMgr.h:1028
static ResponseCodes CheckPlayerName(std::string_view name, LocaleConstant locale, bool create=false)
std::unordered_map< uint32, Trinity::unique_trackable_ptr< Quest > > QuestContainer
Definition ObjectMgr.h:979
void SendMovieStart(uint32 movieId)
Definition Player.cpp:6297
void SendEquipError(InventoryResult msg, Item const *item1=nullptr, Item const *item2=nullptr, uint32 itemId=0) const
Definition Player.cpp:13130
void SetWatchedFactionIndex(int32 index)
Definition Player.h:3015
void SendInitialPacketsAfterAddToMap()
Definition Player.cpp:25074
uint32 GetXP() const
Definition Player.h:1329
static Team TeamForRace(uint8 race)
Definition Player.cpp:6461
static TeamId TeamIdForRace(uint8 race)
Definition Player.cpp:6479
InventoryResult CanUnequipItem(uint16 src, bool swap) const
Definition Player.cpp:11019
void RemoveAtLoginFlag(AtLoginFlags flags, bool persist=false)
Definition Player.cpp:28431
void ResetSpells(bool myClassOnly=false)
Definition Player.cpp:25247
bool ModifyMoney(int64 amount, bool sendError=true)
Definition Player.cpp:24850
InventoryResult CanEquipItem(uint8 slot, uint16 &dest, Item *pItem, bool swap, bool not_loading=true) const
Definition Player.cpp:10788
void UpdateAverageItemLevelEquipped()
Definition Player.cpp:30997
void SetPlayerLocalFlag(PlayerLocalFlags flags)
Definition Player.h:3008
Creature * GetNPCIfCanInteractWith(ObjectGuid const &guid, NPCFlags npcFlags, NPCFlags2 npcFlags2) const
Definition Player.cpp:1903
void SetNativeGender(Gender gender) override
Definition Player.h:1351
Gender GetNativeGender() const override
Definition Player.h:1350
UF::UpdateField< UF::ActivePlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_ACTIVE_PLAYER > m_activePlayerData
Definition Player.h:3062
void SetEquipmentSet(EquipmentSetInfo::EquipmentSetData const &newEqSet)
Definition Player.cpp:28201
InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap=false) const
Definition Player.cpp:10055
void CleanupsBeforeDelete(bool finalCleanup=true) override
Definition Player.cpp:378
void SendTalentsInfoData()
Definition Player.cpp:28107
static void OfflineResurrect(ObjectGuid const &guid, CharacterDatabaseTransaction trans)
Definition Player.cpp:4494
void SendDungeonDifficulty(int32 forcedDifficulty=-1) const
Definition Player.cpp:21866
SceneMgr & GetSceneMgr()
Definition Player.h:2888
void ContinueTaxiFlight()
Definition Player.cpp:23372
void SendInitialPacketsBeforeAddToMap()
Definition Player.cpp:24955
static void SavePositionInDB(WorldLocation const &loc, uint16 zoneId, ObjectGuid guid, CharacterDatabaseTransaction trans)
Definition Player.cpp:21826
void SendCorpseReclaimDelay(uint32 delay) const
Definition Player.cpp:26648
int64 GetBarberShopCost(Trinity::IteratorPair< UF::ChrCustomizationChoice const * > newCustomizations) const
Definition Player.cpp:27013
static void SaveCustomizations(CharacterDatabaseTransaction trans, ObjectGuid::LowType guid, Trinity::IteratorPair< UF::ChrCustomizationChoice const * > customizations)
Definition Player.cpp:20871
WorldLocation m_homebind
Definition Player.h:2693
void SwapItem(uint16 src, uint16 dst)
Definition Player.cpp:12649
void InitDisplayIds()
Definition Player.cpp:23458
Item * StoreItem(ItemPosCountVec const &pos, Item *pItem, bool update)
Definition Player.cpp:11447
WorldSession * GetSession() const
Definition Player.h:2272
Item * GetItemByPos(uint16 pos) const
Definition Player.cpp:9630
void ResetTalentSpecialization()
Definition Player.cpp:27705
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition Player.cpp:27588
void AddExploredZones(uint32 pos, uint64 mask)
Definition Player.cpp:6379
void SetInGuild(ObjectGuid::LowType guildId)
Definition Player.cpp:7472
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, TeleportToOptions options=TELE_TO_NONE, Optional< uint32 > instanceId={}, uint32 teleportSpellId=0)
Definition Player.cpp:1226
void SetPersonalTabard(uint32 style, uint32 color, uint32 borderStyle, uint32 borderColor, uint32 backgroundColor)
Definition Player.cpp:23112
ObjectGuid::LowType GetGuildId() const
Definition Player.h:2164
bool IsGameMaster() const
Definition Player.h:1309
void SetGuildRank(uint8 rankId)
Definition Player.h:2159
void LoadCorpse(PreparedQueryResult result)
Definition Player.cpp:19155
static void DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRealmChars=true, bool deleteFinally=false)
Definition Player.cpp:3767
void SendCinematicStart(uint32 CinematicSequenceId) const
Definition Player.cpp:6288
uint8 getCinematic() const
Definition Player.h:2110
uint32 GetXPForNextLevel() const
Definition Player.h:1330
void SetTransportServerTime(int32 transportServerTime)
Definition Player.h:3020
void DeleteEquipmentSet(uint64 id)
Definition Player.cpp:28415
bool LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const &holder)
Definition Player.cpp:17963
static bool IsValidGender(uint8 Gender)
Definition Player.h:1874
void UpdateAverageItemLevelTotal()
Definition Player.cpp:30940
bool HasAtLoginFlag(AtLoginFlags f) const
Definition Player.h:2722
static void LeaveAllArenaTeams(ObjectGuid guid)
Definition Player.cpp:23122
void RemoveItem(uint8 bag, uint8 slot, bool update)
Definition Player.cpp:11989
static bool IsValidRace(uint8 Race)
Definition Player.h:1876
int32 CalculateCorpseReclaimDelay(bool load=false) const
Definition Player.cpp:26607
Group * GetGroup(Optional< uint8 > partyIndex)
Definition Player.h:2796
bool HasPlayerFlag(PlayerFlags flags) const
Definition Player.h:2910
void SetGuildLevel(uint32 level)
Definition Player.h:2161
void SetTaxiCheater(bool on)
Definition Player.h:1316
void SetVirtualPlayerRealm(uint32 virtualRealmAddress)
Definition Player.h:2952
void SetContestedPvP(Player *attackedPlayer=nullptr)
Definition Player.cpp:21986
Item * GetItemByGuid(ObjectGuid guid) const
Definition Player.cpp:9614
void ResummonPetTemporaryUnSummonedIfAny()
Definition Player.cpp:28000
PlayerCreateMode GetCreateMode() const
Definition Player.h:2108
bool ResetTalents(bool noCost=false)
Definition Player.cpp:3508
void SetInGameTime(uint32 time)
Definition Player.h:1840
void setCinematic(uint8 cine)
Definition Player.h:2111
ReputationMgr & GetReputationMgr()
Definition Player.h:2439
bool IsQuestRewarded(uint32 quest_id) const
Definition Player.cpp:24889
void SetCustomizations(Trinity::IteratorPair< Iter > customizations, bool markChanged=true)
Definition Player.h:2936
Team GetTeam() const
Definition Player.h:2423
bool HasEnoughMoney(uint64 amount) const
Definition Player.h:1907
void setUInt16(uint8 index, uint16 value)
void setString(uint8 index, std::string &&value)
void setUInt32(uint8 index, uint32 value)
void setFloat(uint8 index, float value)
void setUInt64(uint8 index, uint64 value)
void setInt32(uint8 index, int32 value)
void setUInt8(uint8 index, uint8 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 SetInactive(RepListID repListID, bool on)
void SetSize(size_t size)
PreparedQueryResult GetPreparedResult(size_t index) const
void AfterComplete(std::function< void(SQLQueryHolderBase const &)> callback) &
Definition QueryHolder.h:70
bool SetPreparedQuery(size_t index, PreparedStatement< T > *stmt)
Definition QueryHolder.h:48
uint32 PlayScene(uint32 sceneId, Position const *position=nullptr)
Definition SceneMgr.cpp:36
size_t size() const
Definition DBCEnums.h:2513
Utility class to enable range for loop syntax for multimap.equal_range uses.
constexpr end_iterator end() const
constexpr iterator begin() const
void RestoreDisplayId(bool ignorePositiveAurasPreventingMounting=false)
Definition Unit.cpp:10803
void SetStandState(UnitStandStateType state, uint32 animKitID=0)
Definition Unit.cpp:10731
uint8 GetClass() const
Definition Unit.h:764
MotionMaster * GetMotionMaster()
Definition Unit.h:1723
DeathState m_deathState
Definition Unit.h:1905
bool IsStandState() const
Definition Unit.cpp:10725
void UpdateMountCapability()
Definition Unit.cpp:8459
void SetPvpFlag(UnitPVPStateFlags flags)
Definition Unit.h:881
void RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const *source=nullptr)
Definition Unit.cpp:4241
bool HasUnitState(const uint32 f) const
Definition Unit.h:743
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4804
UnitStandStateType GetStandState() const
Definition Unit.h:900
bool SetWaterWalking(bool enable)
Definition Unit.cpp:13502
uint8 GetLevel() const
Definition Unit.h:757
uint8 GetRace() const
Definition Unit.h:761
bool IsInCombat() const
Definition Unit.h:1058
constexpr void WorldRelocate(WorldLocation const &loc)
Definition Position.h:202
constexpr uint32 GetMapId() const
Definition Position.h:216
Map * GetMap() const
Definition Object.h:411
GameObject * FindNearestGameObjectOfType(GameobjectTypes type, float range) const
Definition Object.cpp:1570
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2217
std::string const & GetName() const
Definition Object.h:342
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
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]
uint32 ClubPresenceUnsubscribeDelay
Timer for updating club presence when communities ui frame is hidden.
Optional< EuropaTicketConfig > EuropaTicketSystemStatus
std::vector< GameRuleValuePair > GameRules
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< std::string > const * Text
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)
int64 _timeSyncClockDelta
void LoadAccountData(PreparedQueryResult result, uint32 mask)
void HandleSetWatchedFactionOpcode(WorldPackets::Character::SetWatchedFaction &packet)
void SendCharDelete(ResponseCodes result)
LocaleConstant GetSessionDbcLocale() const
std::string GetPlayerInfo() const
void HandleCharRaceOrFactionChangeOpcode(WorldPackets::Character::CharRaceOrFactionChange &packet)
static constexpr uint32 SPECIAL_RESUME_COMMS_TIME_SYNC_COUNTER
void HandleCharUndeleteEnumOpcode(WorldPackets::Character::EnumCharacters &)
Player * GetPlayer() const
std::unique_ptr< CollectionMgr > _collectionMgr
bool PlayerLoading() const
void HandleCharRenameOpcode(WorldPackets::Character::CharacterRenameRequest &request)
void SendUndeleteCharacterResponse(CharacterUndeleteResult result, WorldPackets::Character::CharacterUndeleteInfo const *undeleteInfo)
void SendSetTimeZoneInformation()
void RegisterTimeSync(uint32 counter)
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)
uint8 GetExpansion() const
void SendAccountDataTimes(ObjectGuid playerGuid, uint32 mask)
void HandleSetFactionNotAtWar(WorldPackets::Character::SetFactionNotAtWar &packet)
void HandleContinuePlayerLogin()
std::unique_ptr< boost::circular_buffer< std::pair< int64, uint32 > > > _timeSyncClockDeltaQueue
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 KickPlayer(std::string_view reason)
Kick a player out of the World.
void HandleCharCustomizeCallback(std::shared_ptr< WorldPackets::Character::CharCustomizeInfo > customizeInfo, PreparedQueryResult result)
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 sWorld
Definition World.h:916
uint32 GetVirtualRealmAddress()
Definition World.cpp:3526
@ CONFIG_ARENA_SEASON_ID
Definition World.h:344
@ CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK
Definition World.h:255
@ CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_EVOKER
Definition World.h:260
@ CONFIG_CHARACTER_CREATING_DISABLED
Definition World.h:254
@ CONFIG_ENABLE_SINFO_LOGIN
Definition World.h:353
@ CONFIG_CHARACTERS_PER_ACCOUNT
Definition World.h:256
@ CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_COOLDOWN
Definition World.h:407
@ CONFIG_CHARACTER_CREATING_EVOKERS_PER_REALM
Definition World.h:258
@ CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_DEMON_HUNTER
Definition World.h:259
@ CONFIG_SKIP_CINEMATICS
Definition World.h:261
@ CONFIG_CHARACTERS_PER_REALM
Definition World.h:257
@ CONFIG_SUPPORT_COMPLAINTS_ENABLED
Definition World.h:159
@ CONFIG_ALL_TAXI_PATHS
Definition World.h:116
@ CONFIG_SUPPORT_BUGS_ENABLED
Definition World.h:158
@ CONFIG_DECLINED_NAMES_USED
Definition World.h:136
@ CONFIG_START_ALL_REP
Definition World.h:149
@ CONFIG_CHARACTER_CREATING_DISABLE_ALLIED_RACE_ACHIEVEMENT_REQUIREMENT
Definition World.h:197
@ CONFIG_ARENA_SEASON_IN_PROGRESS
Definition World.h:143
@ CONFIG_PREVENT_RENAME_CUSTOMIZATION
Definition World.h:189
@ CONFIG_SUPPORT_SUGGESTIONS_ENABLED
Definition World.h:160
@ CONFIG_SUPPORT_TICKETS_ENABLED
Definition World.h:157
@ CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP
Definition World.h:112
@ CONFIG_START_ALL_EXPLORED
Definition World.h:148
@ CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD
Definition World.h:113
@ CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_ENABLED
Definition World.h:177
@ CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK
Definition World.h:439
time_t GetGameTime()
Definition GameTime.cpp:52
uint32 GetGameTimeMS()
Definition GameTime.cpp:57
TC_COMMON_API char const * GetFullVersion()
void AddObject(T *object)
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
TransmogIllusionEntry const * GetTransmogIllusionForSpellItemEnchantment(uint32 spellItemEnchantmentId)
constexpr IteratorPair< iterator, end_iterator > MakeIteratorPair(iterator first, end_iterator second)
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition MapUtils.h:37
TC_COMMON_API std::vector< std::string_view > Tokenize(std::string_view str, char sep, bool keepEmpty)
Definition Util.cpp:57
struct advstd::ranges::Contains contains
@ 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
ObjectGuid::LowType GuildId
Trinity::RaceMask< int64 > RaceMask
EnumFlag< ChrCustomizationReqFlag > GetFlags() const
EnumFlag< ChrRacesFlag > GetFlags() const
std::string name[MAX_DECLINED_NAME_CASES]
std::array< ObjectGuid, EQUIPMENT_SET_SLOTS > Pieces
uint32 IgnoreMask
Mask of EquipmentSlot.
std::array< int32, 2 > Enchants
SpellItemEnchantmentID.
std::array< int32, EQUIPMENT_SET_SLOTS > Appearances
ItemModifiedAppearanceID.
struct GameObjectTemplate::@197::@231 barberChair
PlayerCreateInfoSpells castSpells[size_t(PlayerCreateMode::Max)]
Definition ObjectMgr.h:665
constexpr float GetPositionX() const
Definition Position.h:87
constexpr float GetPositionY() const
Definition Position.h:88
constexpr void GetPosition(float &x, float &y) const
Definition Position.h:92
constexpr float GetPositionZ() const
Definition Position.h:89
constexpr bool IsEmpty() const
Definition RaceMask.h:161
constexpr bool HasRace(uint32 raceId) const
Definition RaceMask.h:96
Array< ChrCustomizationChoice, 250 > Customizations