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_PLAYER_CURRENCY);
314 stmt->setUInt64(0, lowGuid);
316
317 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CORPSE_LOCATION);
318 stmt->setUInt64(0, lowGuid);
320
321 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_PETS);
322 stmt->setUInt64(0, lowGuid);
324
325 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON);
326 stmt->setUInt64(0, lowGuid);
328
330 stmt->setUInt64(0, lowGuid);
332
333 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON_BUILDINGS);
334 stmt->setUInt64(0, lowGuid);
336
337 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWERS);
338 stmt->setUInt64(0, lowGuid);
340
342 stmt->setUInt64(0, lowGuid);
344
345 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_TRAIT_ENTRIES);
346 stmt->setUInt64(0, lowGuid);
348
349 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_TRAIT_CONFIGS);
350 stmt->setUInt64(0, lowGuid);
352
354 stmt->setUInt64(0, lowGuid);
356
357 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PLAYER_DATA_FLAGS_CHARACTER);
358 stmt->setUInt64(0, lowGuid);
360
361 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_BANK_TAB_SETTINGS);
362 stmt->setUInt64(0, lowGuid);
364
365 return res;
366}
367
369{
370public:
371 enum
372 {
375
376 MAX
377 };
378
383
384 bool Initialize(uint32 accountId, bool withDeclinedNames, bool isDeletedCharacters)
385 {
386 _isDeletedCharacters = isDeletedCharacters;
387
388 constexpr CharacterDatabaseStatements statements[2][3] =
389 {
392 };
393
394 bool result = true;
395 CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(statements[isDeletedCharacters ? 1 : 0][withDeclinedNames ? 1 : 0]);
396 stmt->setUInt32(0, accountId);
397 result &= SetPreparedQuery(CHARACTERS, stmt);
398
399 stmt = CharacterDatabase.GetPreparedStatement(statements[isDeletedCharacters ? 1 : 0][2]);
400 stmt->setUInt32(0, accountId);
401 result &= SetPreparedQuery(CUSTOMIZATIONS, stmt);
402
403 return result;
404 }
405
407
408private:
410};
411
413{
415 charEnum.Success = true;
416 charEnum.IsDeletedCharacters = static_cast<EnumCharactersQueryHolder const&>(holder).IsDeletedCharacters();
418
419 if (!charEnum.IsDeletedCharacters)
420 _legitCharacters.clear();
421
422 std::unordered_map<ObjectGuid::LowType, std::vector<UF::ChrCustomizationChoice>> customizations;
424 {
425 do
426 {
427 Field* fields = customizationsResult->Fetch();
428 UF::ChrCustomizationChoice& choice = customizations[fields[0].GetUInt64()].emplace_back();
429 choice.ChrCustomizationOptionID = fields[1].GetUInt32();
430 choice.ChrCustomizationChoiceID = fields[2].GetUInt32();
431
432 } while (customizationsResult->NextRow());
433 }
434
436 {
437 do
438 {
439 charEnum.Characters.emplace_back(result->Fetch());
440
442
443 if (std::vector<UF::ChrCustomizationChoice>* customizationsForChar = Trinity::Containers::MapGetValuePtr(customizations, charInfo.Guid.GetCounter()))
444 charInfo.Customizations = std::move(*customizationsForChar);
445
446 TC_LOG_INFO("network", "Loading char guid {} from account {}.", charInfo.Guid.ToString(), GetAccountId());
447
448 if (!charEnum.IsDeletedCharacters)
449 {
451 {
452 TC_LOG_ERROR("entities.player.loading", "Player {} has wrong Appearance values (Hair/Skin/Color), forcing recustomize", charInfo.Guid.ToString());
453
454 charInfo.Customizations.clear();
455
457 {
460 stmt->setUInt64(1, charInfo.Guid.GetCounter());
461 CharacterDatabase.Execute(stmt);
463 }
464 }
465
466 // Do not allow locked characters to login
468 _legitCharacters.insert(charInfo.Guid);
469 }
470
471 if (!sCharacterCache->HasCharacterCacheEntry(charInfo.Guid)) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet.
472 sCharacterCache->AddCharacterCacheEntry(charInfo.Guid, GetAccountId(), charInfo.Name, charInfo.SexID, charInfo.RaceID, charInfo.ClassID, charInfo.ExperienceLevel, false);
473
474 charEnum.MaxCharacterLevel = std::max<int32>(charEnum.MaxCharacterLevel, charInfo.ExperienceLevel);
475 }
476 while (result->NextRow() && charEnum.Characters.size() < MAX_CHARACTERS_PER_REALM);
477 }
478
479 for (RaceClassAvailability const& requirement : sObjectMgr->GetRaceClassRequirements())
480 {
482 raceUnlock.RaceID = requirement.RaceID;
483 raceUnlock.HasUnlockedLicense = GetAccountExpansion() >= requirement.UnlockRequirement.Expansion;
484 raceUnlock.HasUnlockedAchievement = requirement.UnlockRequirement.AchievementId != 0
486 /* || HasAccountAchievement(requirement.UnlockRequirement.AchievementId)*/);
487 raceUnlock.HasEntitlement = true;
488
489 for (ClassAvailability const& classRequirement : requirement.Classes)
490 {
491 WorldPackets::Character::EnumCharactersResult::ClassUnlock& classUnlock = raceUnlock.ClassUnlocks.emplace_back();
492 classUnlock.ClassID = classRequirement.ClassID;
493 //classUnlock.AchievementID = classRequirement.AchievementId;
494 classUnlock.HasExpansion = GetAccountExpansion() >= classRequirement.AccountExpansionLevel && GetExpansion() >= classRequirement.ActiveExpansionLevel;
495 classUnlock.HasUnlockedAchievement = true/*classRequirement.AchievementId == 0 || HasAccountAchievement(classRequirement.AchievementId)*/;
496 classUnlock.HasEntitlement = true;
497 }
498
499 raceUnlock.DoesNotHaveAvailableClasses = std::ranges::none_of(raceUnlock.ClassUnlocks, [](WorldPackets::Character::EnumCharactersResult::ClassUnlock const& classUnlock)
500 {
501 return classUnlock.HasExpansion && classUnlock.HasUnlockedAchievement && classUnlock.HasEntitlement;
502 });
503 }
504
505 SendPacket(charEnum.Write());
506
507 if (!charEnum.IsDeletedCharacters)
508 _collectionMgr->SendWarbandSceneCollectionData();
509}
510
512{
513 // remove expired bans
515 CharacterDatabase.Execute(stmt);
516
518 std::shared_ptr<EnumCharactersQueryHolder> holder = std::make_shared<EnumCharactersQueryHolder>();
519 if (!holder->Initialize(GetAccountId(), sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED), false))
520 {
521 HandleCharEnum(*holder);
522 return;
523 }
524
525 AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder)).AfterComplete([this](SQLQueryHolderBase const& result)
526 {
527 HandleCharEnum(static_cast<EnumCharactersQueryHolder const&>(result));
528 });
529}
530
532{
534 std::shared_ptr<EnumCharactersQueryHolder> holder = std::make_shared<EnumCharactersQueryHolder>();
535 if (!holder->Initialize(GetAccountId(), sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED), true))
536 {
537 HandleCharEnum(*holder);
538 return;
539 }
540
541 AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder)).AfterComplete([this](SQLQueryHolderBase const& result)
542 {
543 HandleCharEnum(static_cast<EnumCharactersQueryHolder const&>(result));
544 });
545}
546
548 bool checkRequiredDependentChoices, Trinity::IteratorPair<UF::ChrCustomizationChoice const*> selectedChoices) const
549{
551 return true;
552
553 if (req->ClassMask && !(req->ClassMask & (1 << (playerClass - 1))))
554 return false;
555
556 if (race != RACE_NONE && !req->RaceMask.IsEmpty() && req->RaceMask != RACEMASK_ALL_v<int32, 2> && !req->RaceMask.HasRace(race))
557 return false;
558
559 if (req->AchievementID /*&& !HasAchieved(req->AchievementID)*/)
560 return false;
561
562 if (req->ItemModifiedAppearanceID && !GetCollectionMgr()->HasItemAppearance(req->ItemModifiedAppearanceID).first)
563 return false;
564
565 if (req->QuestID)
566 {
567 if (!_player)
568 return false;
569
570 if (!_player->IsQuestRewarded(req->QuestID))
571 return false;
572 }
573
574 if (checkRequiredDependentChoices)
575 {
576 if (std::vector<std::pair<uint32, std::vector<uint32>>> const* requiredChoices = sDB2Manager.GetRequiredCustomizationChoices(req->ID))
577 {
578 for (auto const& [chrCustomizationOptionId, requiredChoicesForOption] : *requiredChoices)
579 {
580 bool hasRequiredChoiceForOption = false;
581 for (uint32 requiredChoice : requiredChoicesForOption)
582 {
583 auto choiceItr = std::find_if(selectedChoices.begin(), selectedChoices.end(), [requiredChoice](UF::ChrCustomizationChoice const& choice)
584 {
585 return choice.ChrCustomizationChoiceID == requiredChoice;
586 });
587
588 if (choiceItr != selectedChoices.end())
589 {
590 hasRequiredChoiceForOption = true;
591 break;
592 }
593 }
594
595 if (!hasRequiredChoiceForOption)
596 return false;
597 }
598 }
599 }
600
601 return true;
602}
603
605{
606 std::vector<ChrCustomizationOptionEntry const*> const* options = sDB2Manager.GetCustomiztionOptions(race, gender);
607 if (!options)
608 return false;
609
610 uint32 previousOption = 0;
611
612 for (UF::ChrCustomizationChoice playerChoice : customizations)
613 {
614 // check uniqueness of options
615 if (playerChoice.ChrCustomizationOptionID == previousOption)
616 return false;
617
618 previousOption = playerChoice.ChrCustomizationOptionID;
619
620 // check if we can use this option
621 auto customizationOptionDataItr = std::find_if(options->begin(), options->end(), [&](ChrCustomizationOptionEntry const* option)
622 {
623 return option->ID == playerChoice.ChrCustomizationOptionID;
624 });
625
626 // option not found for race/gender combination
627 if (customizationOptionDataItr == options->end())
628 return false;
629
630 if (ChrCustomizationReqEntry const* req = sChrCustomizationReqStore.LookupEntry((*customizationOptionDataItr)->ChrCustomizationReqID))
631 if (!MeetsChrCustomizationReq(req, race, playerClass, false, customizations))
632 return false;
633
634 std::vector<ChrCustomizationChoiceEntry const*> const* choicesForOption = sDB2Manager.GetCustomiztionChoices(playerChoice.ChrCustomizationOptionID);
635 if (!choicesForOption)
636 return false;
637
638 auto customizationChoiceDataItr = std::find_if(choicesForOption->begin(), choicesForOption->end(), [&](ChrCustomizationChoiceEntry const* choice)
639 {
640 return choice->ID == playerChoice.ChrCustomizationChoiceID;
641 });
642
643 // choice not found for option
644 if (customizationChoiceDataItr == choicesForOption->end())
645 return false;
646
647 if (ChrCustomizationReqEntry const* req = sChrCustomizationReqStore.LookupEntry((*customizationChoiceDataItr)->ChrCustomizationReqID))
648 if (!MeetsChrCustomizationReq(req, race, playerClass, true, customizations))
649 return false;
650 }
651
652 return true;
653}
654
656{
658 {
659 if (uint32 mask = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED))
660 {
661 bool disabled = false;
662
663 switch (Player::TeamIdForRace(charCreate.CreateInfo->Race))
664 {
665 case TEAM_ALLIANCE:
666 disabled = (mask & (1 << 0)) != 0;
667 break;
668 case TEAM_HORDE:
669 disabled = (mask & (1 << 1)) != 0;
670 break;
671 case TEAM_NEUTRAL:
672 disabled = (mask & (1 << 2)) != 0;
673 break;
674 }
675
676 if (disabled)
677 {
679 return;
680 }
681 }
682 }
683
684 ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(charCreate.CreateInfo->Class);
685 if (!classEntry)
686 {
687 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());
689 return;
690 }
691
692 ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(charCreate.CreateInfo->Race);
693 if (!raceEntry)
694 {
695 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());
697 return;
698 }
699
700 // prevent character creating Expansion race without Expansion account
701 RaceUnlockRequirement const* raceExpansionRequirement = sObjectMgr->GetRaceUnlockRequirement(charCreate.CreateInfo->Race);
702 if (!raceExpansionRequirement)
703 {
704 TC_LOG_ERROR("entities.player.cheat", "Account {} tried to create character with unavailable race {}", GetAccountId(), charCreate.CreateInfo->Race);
706 return;
707 }
708
709 if (raceExpansionRequirement->Expansion > GetAccountExpansion())
710 {
711 TC_LOG_ERROR("entities.player.cheat", "Expansion {} account:[{}] tried to Create character with expansion {} race ({})",
712 GetAccountExpansion(), GetAccountId(), raceExpansionRequirement->Expansion, charCreate.CreateInfo->Race);
714 return;
715 }
716
717 //if (raceExpansionRequirement->AchievementId && !)
718 //{
719 // TC_LOG_ERROR("entities.player.cheat", "Expansion {} account:[{}] tried to Create character without achievement {} race ({})",
720 // GetAccountExpansion(), GetAccountId(), raceExpansionRequirement->AchievementId, charCreate.CreateInfo->Race);
721 // SendCharCreate(CHAR_CREATE_ALLIED_RACE_ACHIEVEMENT);
722 // return;
723 //}
724
725 // prevent character creating Expansion class without Expansion account
726 if (ClassAvailability const* raceClassExpansionRequirement = sObjectMgr->GetClassExpansionRequirement(charCreate.CreateInfo->Race, charCreate.CreateInfo->Class))
727 {
728 if (raceClassExpansionRequirement->ActiveExpansionLevel > GetExpansion() || raceClassExpansionRequirement->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 raceClassExpansionRequirement->ActiveExpansionLevel, raceClassExpansionRequirement->AccountExpansionLevel);
734 return;
735 }
736 }
737 else if (ClassAvailability const* classExpansionRequirement = sObjectMgr->GetClassExpansionRequirementFallback(charCreate.CreateInfo->Class))
738 {
739 if (classExpansionRequirement->MinActiveExpansionLevel > GetExpansion() || classExpansionRequirement->AccountExpansionLevel > GetAccountExpansion())
740 {
741 TC_LOG_ERROR("entities.player.cheat", "Account:[{}] tried to create character with race/class {}/{} without required expansion (had {}/{}, required {}/{})",
742 GetAccountId(), uint32(charCreate.CreateInfo->Race), uint32(charCreate.CreateInfo->Class), GetExpansion(), GetAccountExpansion(),
743 classExpansionRequirement->ActiveExpansionLevel, classExpansionRequirement->AccountExpansionLevel);
745 return;
746 }
747 }
748 else
749 {
750 TC_LOG_ERROR("entities.player.cheat", "Expansion {} account:[{}] tried to Create character for race/class combination that is missing requirements in db ({}/{})",
751 GetAccountExpansion(), GetAccountId(), uint32(charCreate.CreateInfo->Race), uint32(charCreate.CreateInfo->Class));
753 return;
754 }
755
757 {
758 if (raceEntry->GetFlags().HasFlag(ChrRacesFlag::NPCOnly))
759 {
760 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());
762 return;
763 }
764
766 if (raceMaskDisabled.HasRace(charCreate.CreateInfo->Race))
767 {
769 return;
770 }
771 }
772
774 {
775 uint32 classMaskDisabled = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK);
776 if ((1 << (charCreate.CreateInfo->Class - 1)) & classMaskDisabled)
777 {
779 return;
780 }
781 }
782
783 // prevent character creating with invalid name
784 if (!normalizePlayerName(charCreate.CreateInfo->Name))
785 {
786 TC_LOG_ERROR("entities.player.cheat", "Account:[{}] but tried to Create character with empty [name] ", GetAccountId());
788 return;
789 }
790
791 // check name limitations
793 if (res != CHAR_NAME_SUCCESS)
794 {
795 SendCharCreate(res);
796 return;
797 }
798
800 {
802 return;
803 }
804
805 if (charCreate.CreateInfo->TimerunningSeasonID)
806 {
808 return;
809 }
810
811 std::shared_ptr<WorldPackets::Character::CharacterCreateInfo> createInfo = charCreate.CreateInfo;
813 stmt->setString(0, charCreate.CreateInfo->Name);
814
816 .WithChainingPreparedCallback([this](QueryCallback& queryCallback, PreparedQueryResult result)
817 {
818 if (result)
819 {
820 SendCharCreate(CHAR_CREATE_NAME_IN_USE);
821 return;
822 }
823
825 stmt->setUInt32(0, GetAccountId());
826 queryCallback.SetNextQuery(LoginDatabase.AsyncQuery(stmt));
827 })
828 .WithChainingPreparedCallback([this](QueryCallback& queryCallback, PreparedQueryResult result)
829 {
830 uint64 acctCharCount = 0;
831 if (result)
832 {
833 Field* fields = result->Fetch();
834 acctCharCount = uint64(fields[0].GetDouble());
835 }
836
837 if (acctCharCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_ACCOUNT))
838 {
839 SendCharCreate(CHAR_CREATE_ACCOUNT_LIMIT);
840 return;
841 }
842
844 stmt->setUInt32(0, GetAccountId());
845 queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt));
846 })
847 .WithChainingPreparedCallback([this, createInfo](QueryCallback& queryCallback, PreparedQueryResult result)
848 {
849 if (result)
850 {
851 Field* fields = result->Fetch();
852 createInfo->CharCount = uint8(fields[0].GetUInt64()); // SQL's COUNT() returns uint64 but it will always be less than uint8.Max
853
854 if (createInfo->CharCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM))
855 {
856 SendCharCreate(CHAR_CREATE_SERVER_LIMIT);
857 return;
858 }
859 }
860
861 bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || HasPermission(rbac::RBAC_PERM_TWO_SIDE_CHARACTER_CREATION);
862 uint32 skipCinematics = sWorld->getIntConfig(CONFIG_SKIP_CINEMATICS);
863
864 std::function<void(PreparedQueryResult)> finalizeCharacterCreation = [this, createInfo](PreparedQueryResult result)
865 {
866 bool haveSameRace = false;
867 uint32 demonHunterReqLevel = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_DEMON_HUNTER);
868 bool hasDemonHunterReqLevel = (demonHunterReqLevel == 0);
869 uint32 evokerReqLevel = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_EVOKER);
870 bool hasEvokerReqLevel = (evokerReqLevel == 0);
871 bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || HasPermission(rbac::RBAC_PERM_TWO_SIDE_CHARACTER_CREATION);
872 uint32 skipCinematics = sWorld->getIntConfig(CONFIG_SKIP_CINEMATICS);
873 bool checkClassLevelReqs = (createInfo->Class == CLASS_DEMON_HUNTER || createInfo->Class == CLASS_EVOKER)
875 int32 evokerLimit = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_EVOKERS_PER_REALM);
876 bool hasEvokerLimit = evokerLimit != 0;
877
878 if (result)
879 {
880 uint32 team = Player::TeamForRace(createInfo->Race);
881
882 Field* field = result->Fetch();
883 uint8 accRace = field[1].GetUInt8();
884 uint8 accClass = field[2].GetUInt8();
885
886 if (checkClassLevelReqs)
887 {
888 if (!hasDemonHunterReqLevel)
889 {
890 uint8 accLevel = field[0].GetUInt8();
891 if (accLevel >= demonHunterReqLevel)
892 hasDemonHunterReqLevel = true;
893 }
894 if (!hasEvokerReqLevel)
895 {
896 uint8 accLevel = field[0].GetUInt8();
897 if (accLevel >= evokerReqLevel)
898 hasEvokerReqLevel = true;
899 }
900 }
901
902 if (accClass == CLASS_EVOKER)
903 --evokerLimit;
904
905 // need to check team only for first character
907 if (!allowTwoSideAccounts)
908 {
909 uint32 accTeam = 0;
910 if (accRace > 0)
911 accTeam = Player::TeamForRace(accRace);
912
913 if (accTeam != team)
914 {
915 SendCharCreate(CHAR_CREATE_PVP_TEAMS_VIOLATION);
916 return;
917 }
918 }
919
920 // search same race for cinematic or same class if need
922 while ((skipCinematics == 1 && !haveSameRace) || createInfo->Class == CLASS_DEMON_HUNTER || createInfo->Class == CLASS_EVOKER)
923 {
924 if (!result->NextRow())
925 break;
926
927 field = result->Fetch();
928 accRace = field[1].GetUInt8();
929 accClass = field[2].GetUInt8();
930
931 if (!haveSameRace)
932 haveSameRace = createInfo->Race == accRace;
933
934 if (checkClassLevelReqs)
935 {
936 if (!hasDemonHunterReqLevel)
937 {
938 uint8 accLevel = field[0].GetUInt8();
939 if (accLevel >= demonHunterReqLevel)
940 hasDemonHunterReqLevel = true;
941 }
942 if (!hasEvokerReqLevel)
943 {
944 uint8 accLevel = field[0].GetUInt8();
945 if (accLevel >= evokerReqLevel)
946 hasEvokerReqLevel = true;
947 }
948 }
949
950 if (accClass == CLASS_EVOKER)
951 --evokerLimit;
952 }
953 }
954
955 if (checkClassLevelReqs)
956 {
957 if (!hasDemonHunterReqLevel)
958 {
959 SendCharCreate(CHAR_CREATE_NEW_PLAYER);
960 return;
961 }
962 if (!hasEvokerReqLevel)
963 {
965 return;
966 }
967 }
968
969 if (createInfo->Class == CLASS_EVOKER && hasEvokerLimit && evokerLimit < 1)
970 {
971 SendCharCreate(CHAR_CREATE_DRACTHYR_DUPLICATE);
972 return;
973 }
974
975 // Check name uniqueness in the same step as saving to database
976 if (sCharacterCache->GetCharacterCacheByName(createInfo->Name))
977 {
978 SendCharCreate(CHAR_CREATE_NAME_IN_USE);
979 return;
980 }
981
982 std::shared_ptr<Player> newChar(new Player(this), [](Player* ptr)
983 {
985 delete ptr;
986 });
987 newChar->GetMotionMaster()->Initialize();
988 if (!newChar->Create(sObjectMgr->GetGenerator<HighGuid::Player>().Generate(), createInfo.get()))
989 {
990 // Player not create (race/class/etc problem?)
991 SendCharCreate(CHAR_CREATE_ERROR);
992 return;
993 }
994
995 if ((haveSameRace && skipCinematics == 1) || skipCinematics == 2)
996 newChar->setCinematic(1); // not show intro
997
998 newChar->SetAtLoginFlag(AT_LOGIN_FIRST); // First login
999
1000 CharacterDatabaseTransaction characterTransaction = CharacterDatabase.BeginTransaction();
1001 LoginDatabaseTransaction trans = LoginDatabase.BeginTransaction();
1002
1003 // Player created, save it now
1004 newChar->SaveToDB(trans, characterTransaction, true);
1005 createInfo->CharCount += 1;
1006
1008 stmt->setUInt32(0, createInfo->CharCount);
1009 stmt->setUInt32(1, GetAccountId());
1010 stmt->setUInt32(2, sRealmList->GetCurrentRealmId().Realm);
1011 trans->Append(stmt);
1012
1013 AddTransactionCallback(CharacterDatabase.AsyncCommitTransaction(characterTransaction)).AfterComplete([this, newChar = std::move(newChar), trans](bool success)
1014 {
1015 if (success)
1016 {
1017 LoginDatabase.CommitTransaction(trans);
1018
1019 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Create Character: {} {}", GetAccountId(), GetRemoteAddress(), newChar->GetName(), newChar->GetGUID().ToString());
1020 sScriptMgr->OnPlayerCreate(newChar.get());
1021 sCharacterCache->AddCharacterCacheEntry(newChar->GetGUID(), GetAccountId(), newChar->GetName(), newChar->GetNativeGender(), newChar->GetRace(), newChar->GetClass(), newChar->GetLevel(), false);
1022
1023 SendCharCreate(CHAR_CREATE_SUCCESS, newChar->GetGUID());
1024 }
1025 else
1026 SendCharCreate(CHAR_CREATE_ERROR);
1027 });
1028 };
1029
1030 if (allowTwoSideAccounts && !skipCinematics && createInfo->Class != CLASS_DEMON_HUNTER)
1031 {
1032 finalizeCharacterCreation(PreparedQueryResult(nullptr));
1033 return;
1034 }
1035
1037 stmt->setUInt32(0, GetAccountId());
1038 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)
1039 queryCallback.WithPreparedCallback(std::move(finalizeCharacterCreation)).SetNextQuery(CharacterDatabase.AsyncQuery(stmt));
1040 }));
1041}
1042
1044{
1045 // Initiating
1046 uint32 initAccountId = GetAccountId();
1047
1048 // can't delete loaded character
1049 if (ObjectAccessor::FindPlayer(charDelete.Guid))
1050 {
1051 sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
1052 return;
1053 }
1054
1055 // is guild leader
1056 if (sGuildMgr->GetGuildByLeader(charDelete.Guid))
1057 {
1058 sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
1060 return;
1061 }
1062
1063 // is arena team captain
1064 if (sArenaTeamMgr->GetArenaTeamByCaptain(charDelete.Guid))
1065 {
1066 sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
1068 return;
1069 }
1070
1071 CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(charDelete.Guid);
1072 if (!characterInfo)
1073 {
1074 sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
1075 return;
1076 }
1077
1078 uint32 accountId = characterInfo->AccountId;
1079 std::string name = characterInfo->Name;
1080 uint8 level = characterInfo->Level;
1081
1082 // prevent deleting other players' characters using cheating tools
1083 if (accountId != initAccountId)
1084 {
1085 sScriptMgr->OnPlayerFailedDelete(charDelete.Guid, initAccountId);
1086 return;
1087 }
1088
1089 TC_LOG_INFO("entities.player.character", "Account: {}, IP: {} deleted character: {}, {}, Level: {}", accountId, GetRemoteAddress(), name, charDelete.Guid.ToString(), level);
1090
1091 // To prevent hook failure, place hook before removing reference from DB
1092 sScriptMgr->OnPlayerDelete(charDelete.Guid, initAccountId); // To prevent race conditioning, but as it also makes sense, we hand the accountId over for successful delete.
1093 // Shouldn't interfere with character deletion though
1094
1095 if (sLog->ShouldLog("entities.player.dump", LOG_LEVEL_INFO)) // optimize GetPlayerDump call
1096 {
1097 std::string dump;
1098 if (PlayerDumpWriter().GetDump(charDelete.Guid.GetCounter(), dump))
1099 sLog->OutCharDump(dump, accountId, charDelete.Guid.GetCounter(), name);
1100 }
1101
1102 sCalendarMgr->RemoveAllPlayerEventsAndInvites(charDelete.Guid);
1103 Player::DeleteFromDB(charDelete.Guid, accountId);
1104
1106}
1107
1109{
1110 if (PlayerLoading() || GetPlayer() != nullptr)
1111 {
1112 TC_LOG_ERROR("network", "Player tries to login again, AccountId = {}", GetAccountId());
1113 KickPlayer("WorldSession::HandlePlayerLoginOpcode Another client logging in");
1114 return;
1115 }
1116
1117 m_playerLoading = playerLogin.Guid;
1118
1119 TC_LOG_DEBUG("network", "Character {} logging in", playerLogin.Guid.ToString());
1120
1121 if (!IsLegitCharacterForAccount(playerLogin.Guid))
1122 {
1123 TC_LOG_ERROR("network", "Account ({}) can't login with that character ({}).", GetAccountId(), playerLogin.Guid.ToString());
1124 KickPlayer("WorldSession::HandlePlayerLoginOpcode Trying to login with a character of another account");
1125 return;
1126 }
1127
1129}
1130
1132{
1133 if (!PlayerLoading() || GetPlayer())
1134 {
1135 KickPlayer("WorldSession::HandleContinuePlayerLogin incorrect player state when logging in");
1136 return;
1137 }
1138
1139 std::shared_ptr<LoginQueryHolder> holder = std::make_shared<LoginQueryHolder>(GetAccountId(), m_playerLoading);
1140 if (!holder->Initialize())
1141 {
1143 return;
1144 }
1145
1147
1148 // client will respond to SMSG_RESUME_COMMS with CMSG_QUEUED_MESSAGES_END
1150
1151 AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder)).AfterComplete([this](SQLQueryHolderBase const& holder)
1152 {
1153 HandlePlayerLogin(static_cast<LoginQueryHolder const&>(holder));
1154 });
1155}
1156
1158{
1159 if (!PlayerLoading() || GetPlayer())
1160 {
1161 KickPlayer("WorldSession::AbortLogin incorrect player state when logging in");
1162 return;
1163 }
1164
1167}
1168
1170{
1171 // TODO: Do something with this packet
1172}
1173
1175{
1176 ObjectGuid playerGuid = holder.GetGuid();
1177
1178 Player* pCurrChar = new Player(this);
1179 // for send server info and strings (config)
1180 ChatHandler chH = ChatHandler(pCurrChar->GetSession());
1181
1182 // "GetAccountId() == db stored account id" checked in LoadFromDB (prevent login not own character using cheating tools)
1183 if (!pCurrChar->LoadFromDB(playerGuid, holder))
1184 {
1185 SetPlayer(nullptr);
1186 KickPlayer("WorldSession::HandlePlayerLogin Player::LoadFromDB failed"); // disconnect client, player no set to session and it will not deleted or saved at kick
1187 delete pCurrChar; // delete it manually
1189 return;
1190 }
1191
1192 if (!_timeSyncClockDeltaQueue->empty())
1193 {
1196 }
1197
1199
1202
1203 pCurrChar->GetMotionMaster()->Initialize();
1204 pCurrChar->SendDungeonDifficulty();
1205 pCurrChar->SendRaidDifficulty(false);
1206 pCurrChar->SendRaidDifficulty(true);
1207
1209 loginVerifyWorld.MapID = pCurrChar->GetMapId();
1210 loginVerifyWorld.Pos = pCurrChar->GetPosition();
1211 SendPacket(loginVerifyWorld.Write());
1212
1213 // load player specific part before send times
1216
1218
1219 // Send MOTD
1220 {
1222 motd.Text = &sWorld->GetMotd();
1223 SendPacket(motd.Write());
1224 }
1225
1227
1228 // Send PVPSeason
1229 {
1231 seasonInfo.PreviousArenaSeason = sWorld->getIntConfig(CONFIG_ARENA_SEASON_ID) - sWorld->getBoolConfig(CONFIG_ARENA_SEASON_IN_PROGRESS);
1232
1233 if (sWorld->getBoolConfig(CONFIG_ARENA_SEASON_IN_PROGRESS))
1234 seasonInfo.CurrentArenaSeason = sWorld->getIntConfig(CONFIG_ARENA_SEASON_ID);
1235
1236 SendPacket(seasonInfo.Write());
1237 }
1238
1239 // send server info
1240 {
1241 if (sWorld->getIntConfig(CONFIG_ENABLE_SINFO_LOGIN) == 1)
1243 }
1244
1245 //QueryResult* result = CharacterDatabase.PQuery("SELECT guildid, `rank` FROM guild_member WHERE guid = '{}'", pCurrChar->GetGUIDLow());
1247 {
1248 Field* fields = resultGuild->Fetch();
1249 pCurrChar->SetInGuild(fields[0].GetUInt64());
1250 pCurrChar->SetGuildRank(fields[1].GetUInt8());
1251 if (Guild* guild = sGuildMgr->GetGuildById(pCurrChar->GetGuildId()))
1252 pCurrChar->SetGuildLevel(guild->GetLevel());
1253 }
1254 else if (pCurrChar->GetGuildId()) // clear guild related fields in case wrong data about non existed membership
1255 {
1256 pCurrChar->SetInGuild(UI64LIT(0));
1257 pCurrChar->SetGuildRank(0);
1258 pCurrChar->SetGuildLevel(0);
1259 }
1260
1262
1264
1266
1267 //Show cinematic at the first time that player login
1268 if (!pCurrChar->getCinematic())
1269 {
1270 pCurrChar->setCinematic(1);
1271
1272 if (PlayerInfo const* playerInfo = sObjectMgr->GetPlayerInfo(pCurrChar->GetRace(), pCurrChar->GetClass()))
1273 {
1274 switch (pCurrChar->GetCreateMode())
1275 {
1277 if (playerInfo->introMovieId)
1278 pCurrChar->SendMovieStart(*playerInfo->introMovieId);
1279 else if (playerInfo->introSceneId)
1280 pCurrChar->GetSceneMgr().PlayScene(*playerInfo->introSceneId);
1281 else if (sChrClassesStore.AssertEntry(pCurrChar->GetClass())->CinematicSequenceID)
1282 pCurrChar->SendCinematicStart(sChrClassesStore.AssertEntry(pCurrChar->GetClass())->CinematicSequenceID);
1283 else if (sChrRacesStore.AssertEntry(pCurrChar->GetRace())->CinematicSequenceID)
1284 pCurrChar->SendCinematicStart(sChrRacesStore.AssertEntry(pCurrChar->GetRace())->CinematicSequenceID);
1285 break;
1287 if (playerInfo->introSceneIdNPE)
1288 pCurrChar->GetSceneMgr().PlayScene(*playerInfo->introSceneIdNPE);
1289 break;
1290 default:
1291 break;
1292 }
1293 }
1294
1295 // send new char string if not empty
1296 if (!sWorld->GetNewCharString().empty())
1297 chH.PSendSysMessage("%s", sWorld->GetNewCharString().c_str());
1298 }
1299
1300 if (!pCurrChar->GetMap()->AddPlayerToMap(pCurrChar))
1301 {
1302 if (AreaTriggerTeleport const* at = sObjectMgr->GetGoBackTrigger(pCurrChar->GetMapId()))
1303 pCurrChar->TeleportTo(at->Loc);
1304 else
1305 pCurrChar->TeleportTo(pCurrChar->m_homebind);
1306 }
1307
1308 ObjectAccessor::AddObject(pCurrChar);
1309 //TC_LOG_DEBUG("Player {} added to Map.", pCurrChar->GetName());
1310
1311 if (pCurrChar->GetGuildId())
1312 {
1313 if (Guild* guild = sGuildMgr->GetGuildById(pCurrChar->GetGuildId()))
1314 guild->SendLoginInfo(this);
1315 else
1316 {
1317 // remove wrong guild data
1318 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());
1319 pCurrChar->SetInGuild(UI64LIT(0));
1320 }
1321 }
1322
1324
1326
1328 stmt->setUInt64(0, pCurrChar->GetGUID().GetCounter());
1329 CharacterDatabase.Execute(stmt);
1330
1332 loginStmt->setUInt32(0, GetAccountId());
1333 LoginDatabase.Execute(loginStmt);
1334
1336
1337 // announce group about member online (must be after add to player list to receive announce to self)
1338 if (Group* group = pCurrChar->GetGroup())
1339 {
1340 //pCurrChar->groupInfo.group->SendInit(this); // useless
1341 group->SendUpdate();
1342 if (group->GetLeaderGUID() == pCurrChar->GetGUID())
1343 group->StopLeaderOfflineTimer();
1344 }
1345
1346 // friend status
1347 sSocialMgr->SendFriendStatus(pCurrChar, FRIEND_ONLINE, pCurrChar->GetGUID(), true);
1348
1349 // Place character in world (and load zone) before some object loading
1351
1352 // setting Ghost+speed if dead
1353 if (pCurrChar->m_deathState == DEAD)
1354 {
1355 // not blizz like, we must correctly save and load player instead...
1356 if (pCurrChar->GetRace() == RACE_NIGHTELF && !pCurrChar->HasAura(20584))
1357 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)
1358
1359 if (!pCurrChar->HasAura(8326))
1360 pCurrChar->CastSpell(pCurrChar, 8326, true); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?)
1361
1362 pCurrChar->SetWaterWalking(true);
1363
1364 int32 const delay = pCurrChar->CalculateCorpseReclaimDelay(true);
1365 if (delay > 0)
1366 pCurrChar->SendCorpseReclaimDelay(delay);
1367 }
1368
1369 pCurrChar->ContinueTaxiFlight();
1370
1371 // reset for all pets before pet loading
1373 {
1374 // Delete all of the player's pet spells
1376 stmtSpells->setUInt64(0, pCurrChar->GetGUID().GetCounter());
1377 CharacterDatabase.Execute(stmtSpells);
1378
1379 // Then reset all of the player's pet specualizations
1381 stmtSpec->setUInt64(0, pCurrChar->GetGUID().GetCounter());
1382 CharacterDatabase.Execute(stmtSpec);
1383 }
1384
1385 // Load pet if any (if player not alive and in taxi flight or another then pet will remember as temporary unsummoned)
1387
1388 // Set FFA PvP for non GM in non-rest mode
1389 if (sWorld->IsFFAPvPRealm() && !pCurrChar->IsGameMaster() && !pCurrChar->HasPlayerFlag(PLAYER_FLAGS_RESTING))
1391
1393 pCurrChar->SetContestedPvP();
1394
1395 // Apply at_login requests
1396 if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_SPELLS))
1397 {
1398 pCurrChar->ResetSpells();
1400 }
1401
1402 if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_TALENTS))
1403 {
1404 pCurrChar->ResetTalents(true);
1405 pCurrChar->ResetTalentSpecialization();
1406 pCurrChar->SendTalentsInfoData(); // original talents send already in to SendInitialPacketsBeforeAddToMap, resend reset state
1407 }
1408
1409 bool firstLogin = pCurrChar->HasAtLoginFlag(AT_LOGIN_FIRST);
1410 if (firstLogin)
1411 {
1413
1414 PlayerInfo const* info = sObjectMgr->GetPlayerInfo(pCurrChar->GetRace(), pCurrChar->GetClass());
1415 for (uint32 spellId : info->castSpells[AsUnderlyingType(pCurrChar->GetCreateMode())])
1416 pCurrChar->CastSpell(pCurrChar, spellId, true);
1417
1418 // start with every map explored
1419 if (sWorld->getBoolConfig(CONFIG_START_ALL_EXPLORED))
1420 {
1421 for (uint32 i = 0; i < PLAYER_EXPLORED_ZONES_SIZE; ++i)
1422 pCurrChar->AddExploredZones(i, UI64LIT(0xFFFFFFFFFFFFFFFF));
1423 }
1424
1425 // Max relevant reputations if "StartAllReputation" is enabled
1426 if (sWorld->getBoolConfig(CONFIG_START_ALL_REP))
1427 {
1428 ReputationMgr& repMgr = pCurrChar->GetReputationMgr();
1429 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 942), 42999, false); // Cenarion Expedition
1430 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 935), 42999, false); // The Sha'tar
1431 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 936), 42999, false); // Shattrath City
1432 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1011), 42999, false); // Lower City
1433 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 970), 42999, false); // Sporeggar
1434 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 967), 42999, false); // The Violet Eye
1435 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 989), 42999, false); // Keepers of Time
1436 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 932), 42999, false); // The Aldor
1437 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 934), 42999, false); // The Scryers
1438 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1038), 42999, false); // Ogri'la
1439 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1077), 42999, false); // Shattered Sun Offensive
1440 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1106), 42999, false); // Argent Crusade
1441 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1104), 42999, false); // Frenzyheart Tribe
1442 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1090), 42999, false); // Kirin Tor
1443 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1098), 42999, false); // Knights of the Ebon Blade
1444 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1156), 42999, false); // The Ashen Verdict
1445 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1073), 42999, false); // The Kalu'ak
1446 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1105), 42999, false); // The Oracles
1447 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1119), 42999, false); // The Sons of Hodir
1448 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1091), 42999, false); // The Wyrmrest Accord
1449
1450 // Factions depending on team, like cities and some more stuff
1451 switch (pCurrChar->GetTeam())
1452 {
1453 case ALLIANCE:
1454 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 72), 42999, false); // Stormwind
1455 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 47), 42999, false); // Ironforge
1456 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 69), 42999, false); // Darnassus
1457 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 930), 42999, false); // Exodar
1458 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 730), 42999, false); // Stormpike Guard
1459 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 978), 42999, false); // Kurenai
1460 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 54), 42999, false); // Gnomeregan Exiles
1461 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 946), 42999, false); // Honor Hold
1462 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1037), 42999, false); // Alliance Vanguard
1463 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1068), 42999, false); // Explorers' League
1464 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1126), 42999, false); // The Frostborn
1465 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1094), 42999, false); // The Silver Covenant
1466 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1050), 42999, false); // Valiance Expedition
1467 break;
1468 case HORDE:
1469 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 76), 42999, false); // Orgrimmar
1470 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 68), 42999, false); // Undercity
1471 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 81), 42999, false); // Thunder Bluff
1472 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 911), 42999, false); // Silvermoon City
1473 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 729), 42999, false); // Frostwolf Clan
1474 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 941), 42999, false); // The Mag'har
1475 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 530), 42999, false); // Darkspear Trolls
1476 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry( 947), 42999, false); // Thrallmar
1477 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1052), 42999, false); // Horde Expedition
1478 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1067), 42999, false); // The Hand of Vengeance
1479 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1124), 42999, false); // The Sunreavers
1480 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1064), 42999, false); // The Taunka
1481 repMgr.SetOneFactionReputation(sFactionStore.LookupEntry(1085), 42999, false); // Warsong Offensive
1482 break;
1483 default:
1484 break;
1485 }
1486 repMgr.SendState(nullptr);
1487 }
1488 }
1489
1490 // show time before shutdown if shutdown planned.
1491 if (sWorld->IsShuttingDown())
1492 sWorld->ShutdownMsg(true, pCurrChar);
1493
1494 if (sWorld->getBoolConfig(CONFIG_ALL_TAXI_PATHS))
1495 pCurrChar->SetTaxiCheater(true);
1496
1497 if (pCurrChar->IsGameMaster())
1499
1500 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Login Character: [{}] {} Level: {}, XP: {}/{} ({} left)",
1501 GetAccountId(), GetRemoteAddress(), pCurrChar->GetName(), pCurrChar->GetGUID().ToString(), pCurrChar->GetLevel(),
1503
1504 if (!pCurrChar->IsStandState() && !pCurrChar->HasUnitState(UNIT_STATE_STUNNED))
1506
1507 pCurrChar->UpdateAverageItemLevelTotal();
1508 pCurrChar->UpdateAverageItemLevelEquipped();
1509
1511
1513
1514 // Handle Login-Achievements (should be handled after loading)
1516
1517 sScriptMgr->OnPlayerLogin(pCurrChar, firstLogin);
1518
1519 TC_METRIC_EVENT("player_events", "Login", pCurrChar->GetName());
1520}
1521
1523{
1525
1528 features.CfgRealmID = 2;
1529 features.CfgRealmRecID = sRealmList->GetCurrentRealmId().Realm;
1530 features.CommercePricePollTimeSeconds = 300;
1531 features.VoiceEnabled = false;
1532
1533 // Enable guilds only.
1534 // This is required to restore old guild channel behavior for GMs.
1535 // The new club streams do not support sending messages through the guild channel when you are not in a guild.
1536 features.CommunitiesEnabled = true;
1537 features.BnetGroupsEnabled = false;
1538 features.CharacterCommunitiesEnabled = false;
1539 features.ClubPresenceAllowSubscribeAll = true;
1540 features.ClubPresenceUnsubscribeDelay = 60000;
1541
1542 features.EuropaTicketSystemStatus.emplace();
1543 features.EuropaTicketSystemStatus->ThrottleState.MaxTries = 10;
1544 features.EuropaTicketSystemStatus->ThrottleState.PerMilliseconds = 60000;
1545 features.EuropaTicketSystemStatus->ThrottleState.TryCount = 1;
1546 features.EuropaTicketSystemStatus->ThrottleState.LastResetTimeBeforeNow = 111111;
1547 features.TutorialEnabled = true;
1548 features.NPETutorialsEnabled = true;
1550
1551 features.EuropaTicketSystemStatus->TicketsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_TICKETS_ENABLED);
1552 features.EuropaTicketSystemStatus->BugsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_BUGS_ENABLED);
1553 features.EuropaTicketSystemStatus->ComplaintsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_COMPLAINTS_ENABLED);
1554 features.EuropaTicketSystemStatus->SuggestionsEnabled = sWorld->getBoolConfig(CONFIG_SUPPORT_SUGGESTIONS_ENABLED);
1555
1557 features.IsChatMuted = !CanSpeak();
1558
1559 features.SpeakForMeAllowed = false;
1560
1561 for (World::GameRule const& gameRule : sWorld->GetGameRules())
1562 {
1563 WorldPackets::System::GameRuleValuePair& rule = features.GameRules.emplace_back();
1564 rule.Rule = AsUnderlyingType(gameRule.Rule);
1565 std::visit([&]<typename T>(T value)
1566 {
1567 if constexpr (std::is_same_v<T, float>)
1568 rule.ValueF = value;
1569 else
1570 rule.Value = value;
1571 }, gameRule.Value);
1572 }
1573
1574 features.AddonChatThrottle.MaxTries = 10;
1581
1582 SendPacket(features.Write());
1583}
1584
1589
1594
1596{
1597 switch (packet.Action)
1598 {
1600 {
1601 uint8 index = uint8(packet.TutorialBit >> 5);
1602 if (index >= MAX_ACCOUNT_TUTORIAL_VALUES)
1603 {
1604 TC_LOG_ERROR("network", "CMSG_TUTORIAL_FLAG received bad TutorialBit {}.", packet.TutorialBit);
1605 return;
1606 }
1607 uint32 flag = GetTutorialInt(index);
1608 flag |= (1 << (packet.TutorialBit & 0x1F));
1609 SetTutorialInt(index, flag);
1610 break;
1611 }
1613 for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i)
1614 SetTutorialInt(i, 0xFFFFFFFF);
1615 break;
1617 for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i)
1618 SetTutorialInt(i, 0x00000000);
1619 break;
1620 default:
1621 TC_LOG_ERROR("network", "CMSG_TUTORIAL_FLAG received unknown TutorialAction {}.", packet.Action);
1622 return;
1623 }
1624}
1625
1630
1635
1637{
1638 // prevent character rename to invalid name
1639 if (!normalizePlayerName(checkCharacterNameAvailability.Name))
1640 {
1642 return;
1643 }
1644
1645 ResponseCodes res = ObjectMgr::CheckPlayerName(checkCharacterNameAvailability.Name, GetSessionDbcLocale(), true);
1646 if (res != CHAR_NAME_SUCCESS)
1647 {
1649 return;
1650 }
1651
1652 // check name limitations
1653 if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(checkCharacterNameAvailability.Name))
1654 {
1656 return;
1657 }
1658
1659 // Ensure that there is no character with the desired new name
1661 stmt->setString(0, checkCharacterNameAvailability.Name);
1662
1664 .WithPreparedCallback([this, sequenceIndex = checkCharacterNameAvailability.SequenceIndex](PreparedQueryResult result)
1665 {
1666 SendPacket(WorldPackets::Character::CheckCharacterNameAvailabilityResult(sequenceIndex, result ? CHAR_CREATE_NAME_IN_USE : RESPONSE_SUCCESS).Write());
1667 }));
1668}
1669
1671{
1672 if (!IsLegitCharacterForAccount(request.RenameInfo->Guid))
1673 {
1674 TC_LOG_ERROR("network", "Account {}, IP: {} tried to rename character {}, but it does not belong to their account!",
1675 GetAccountId(), GetRemoteAddress(), request.RenameInfo->Guid.ToString());
1676 KickPlayer("WorldSession::HandleCharRenameOpcode rename character from a different account");
1677 return;
1678 }
1679
1680 // prevent character rename to invalid name
1681 if (!normalizePlayerName(request.RenameInfo->NewName))
1682 {
1684 return;
1685 }
1686
1688 if (res != CHAR_NAME_SUCCESS)
1689 {
1690 SendCharRename(res, request.RenameInfo.get());
1691 return;
1692 }
1693
1694 // check name limitations
1696 {
1698 return;
1699 }
1700
1701 // Ensure that there is no character with the desired new name
1703 stmt->setUInt64(0, request.RenameInfo->Guid.GetCounter());
1704 stmt->setString(1, request.RenameInfo->NewName);
1705
1707 .WithPreparedCallback([this, renameInfo = std::move(request.RenameInfo)](PreparedQueryResult result) mutable
1708 {
1709 HandleCharRenameCallBack(std::move(renameInfo), std::move(result));
1710 }));
1711}
1712
1713void WorldSession::HandleCharRenameCallBack(std::shared_ptr<WorldPackets::Character::CharacterRenameInfo> renameInfo, PreparedQueryResult result)
1714{
1715 if (!result)
1716 {
1717 SendCharRename(CHAR_CREATE_ERROR, renameInfo.get());
1718 return;
1719 }
1720
1721 Field* fields = result->Fetch();
1722
1723 std::string oldName = fields[0].GetString();
1724 uint16 atLoginFlags = fields[1].GetUInt16();
1725
1726 if (!(atLoginFlags & AT_LOGIN_RENAME))
1727 {
1728 SendCharRename(CHAR_CREATE_ERROR, renameInfo.get());
1729 return;
1730 }
1731
1732 atLoginFlags &= ~AT_LOGIN_RENAME;
1733
1734 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1735 ObjectGuid::LowType lowGuid = renameInfo->Guid.GetCounter();
1736
1737 // Update name and at_login flag in the db
1739 stmt->setString(0, renameInfo->NewName);
1740 stmt->setUInt16(1, atLoginFlags);
1741 stmt->setUInt64(2, lowGuid);
1742
1743 trans->Append(stmt);
1744
1745 // Removed declined name from db
1746 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_DECLINED_NAME);
1747 stmt->setUInt64(0, lowGuid);
1748
1749 trans->Append(stmt);
1750
1751 CharacterDatabase.CommitTransaction(trans);
1752
1753 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}) Character:[{}] ({}) Changed name to: {}",
1754 GetAccountId(), GetRemoteAddress(), oldName, renameInfo->Guid.ToString(), renameInfo->NewName);
1755
1756 SendCharRename(RESPONSE_SUCCESS, renameInfo.get());
1757
1758 sCharacterCache->UpdateCharacterData(renameInfo->Guid, renameInfo->NewName);
1759}
1760
1762{
1763 // not accept declined names for unsupported languages
1764 std::string name;
1765 if (!sCharacterCache->GetCharacterNameByGuid(packet.Player, name))
1766 {
1768 return;
1769 }
1770
1771 std::wstring wname;
1772 if (!Utf8toWStr(name, wname))
1773 {
1775 return;
1776 }
1777
1778 if (!isCyrillicCharacter(wname[0])) // name already stored as only single alphabet using
1779 {
1781 return;
1782 }
1783
1784 for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
1785 {
1786 if (!normalizePlayerName(packet.DeclinedNames.name[i]))
1787 {
1789 return;
1790 }
1791 }
1792
1793 if (!ObjectMgr::CheckDeclinedNames(wname, packet.DeclinedNames))
1794 {
1796 return;
1797 }
1798
1799 for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
1800 CharacterDatabase.EscapeString(packet.DeclinedNames.name[i]);
1801
1802 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1803
1805 stmt->setUInt64(0, packet.Player.GetCounter());
1806 trans->Append(stmt);
1807
1808 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_DECLINED_NAME);
1809 stmt->setUInt64(0, packet.Player.GetCounter());
1810
1811 for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; i++)
1812 stmt->setString(i + 1, packet.DeclinedNames.name[i]);
1813
1814 trans->Append(stmt);
1815
1816 CharacterDatabase.CommitTransaction(trans);
1817
1819}
1820
1822{
1824 if (packet.CustomizedChrModelID)
1825 {
1827 if (!conditionalChrModel)
1828 return;
1829
1830 if (ChrCustomizationReqEntry const* req = sChrCustomizationReqStore.LookupEntry(conditionalChrModel->ChrCustomizationReqID))
1831 if (!MeetsChrCustomizationReq(req, Races(packet.CustomizedRace), Classes(_player->GetClass()), false, customizations))
1832 return;
1833
1835 return;
1836 }
1837
1838 if (!ValidateAppearance(Races(_player->GetRace()), Classes(_player->GetClass()), Gender(packet.NewSex), customizations))
1839 return;
1840
1842 if (!go)
1843 {
1845 return;
1846 }
1847
1849 {
1851 return;
1852 }
1853
1854 int64 cost = _player->GetBarberShopCost(customizations);
1855
1856 // 0 - ok
1857 // 1, 3 - not enough money
1858 // 2 - you have to sit on barber chair
1859 if (!_player->HasEnoughMoney(cost))
1860 {
1862 return;
1863 }
1864
1866
1867 _player->ModifyMoney(-cost); // it isn't free
1869
1870 if (_player->GetNativeGender() != packet.NewSex)
1871 {
1874 _player->RestoreDisplayId(false);
1875 }
1876
1878
1880
1882
1883 sCharacterCache->UpdateCharacterGender(_player->GetGUID(), packet.NewSex);
1884}
1885
1887{
1888 if (!IsLegitCharacterForAccount(packet.CustomizeInfo->CharGUID))
1889 {
1890 TC_LOG_ERROR("entities.player.cheat", "Account {}, IP: {} tried to customise {}, but it does not belong to their account!",
1891 GetAccountId(), GetRemoteAddress(), packet.CustomizeInfo->CharGUID.ToString());
1892 KickPlayer("WorldSession::HandleCharCustomize Trying to customise character of another account");
1893 return;
1894 }
1895
1897 stmt->setUInt64(0, packet.CustomizeInfo->CharGUID.GetCounter());
1898
1900 .WithPreparedCallback([this, customizeInfo = std::move(packet.CustomizeInfo)](PreparedQueryResult result) mutable
1901 {
1902 HandleCharCustomizeCallback(std::move(customizeInfo), std::move(result));
1903 }));
1904}
1905
1906void WorldSession::HandleCharCustomizeCallback(std::shared_ptr<WorldPackets::Character::CharCustomizeInfo> customizeInfo, PreparedQueryResult result)
1907{
1908 if (!result)
1909 {
1910 SendCharCustomize(CHAR_CREATE_ERROR, customizeInfo.get());
1911 return;
1912 }
1913
1914 Field* fields = result->Fetch();
1915
1916 std::string oldName = fields[0].GetString();
1917 Races plrRace = Races(fields[1].GetUInt8());
1918 Classes plrClass = Classes(fields[2].GetUInt8());
1919 Gender plrGender = Gender(fields[3].GetUInt8());
1920 uint16 atLoginFlags = fields[4].GetUInt16();
1921
1922 if (!ValidateAppearance(plrRace, plrClass, plrGender, MakeChrCustomizationChoiceRange(customizeInfo->Customizations)))
1923 {
1924 SendCharCustomize(CHAR_CREATE_ERROR, customizeInfo.get());
1925 return;
1926 }
1927
1928 if (!(atLoginFlags & AT_LOGIN_CUSTOMIZE))
1929 {
1930 SendCharCustomize(CHAR_CREATE_ERROR, customizeInfo.get());
1931 return;
1932 }
1933
1934 // prevent character rename
1935 if (sWorld->getBoolConfig(CONFIG_PREVENT_RENAME_CUSTOMIZATION) && (customizeInfo->CharName != oldName))
1936 {
1937 SendCharCustomize(CHAR_NAME_FAILURE, customizeInfo.get());
1938 return;
1939 }
1940
1941 atLoginFlags &= ~AT_LOGIN_CUSTOMIZE;
1942
1943 // prevent character rename to invalid name
1944 if (!normalizePlayerName(customizeInfo->CharName))
1945 {
1946 SendCharCustomize(CHAR_NAME_NO_NAME, customizeInfo.get());
1947 return;
1948 }
1949
1950 ResponseCodes res = ObjectMgr::CheckPlayerName(customizeInfo->CharName, GetSessionDbcLocale(), true);
1951 if (res != CHAR_NAME_SUCCESS)
1952 {
1953 SendCharCustomize(res, customizeInfo.get());
1954 return;
1955 }
1956
1957 // check name limitations
1958 if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(customizeInfo->CharName))
1959 {
1960 SendCharCustomize(CHAR_NAME_RESERVED, customizeInfo.get());
1961 return;
1962 }
1963
1964 // character with this name already exist
1966 ObjectGuid newGuid = sCharacterCache->GetCharacterGuidByName(customizeInfo->CharName);
1967 if (!newGuid.IsEmpty())
1968 {
1969 if (newGuid != customizeInfo->CharGUID)
1970 {
1971 SendCharCustomize(CHAR_CREATE_NAME_IN_USE, customizeInfo.get());
1972 return;
1973 }
1974 }
1975
1976 CharacterDatabasePreparedStatement* stmt = nullptr;
1977 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1978
1979 ObjectGuid::LowType lowGuid = customizeInfo->CharGUID.GetCounter();
1980
1982 Player::SaveCustomizations(trans, lowGuid, MakeChrCustomizationChoiceRange(customizeInfo->Customizations));
1983
1985 {
1986 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_NAME_AT_LOGIN);
1987 stmt->setString(0, customizeInfo->CharName);
1988 stmt->setUInt16(1, atLoginFlags);
1989 stmt->setUInt64(2, lowGuid);
1990
1991 trans->Append(stmt);
1992
1993 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_DECLINED_NAME);
1994 stmt->setUInt64(0, lowGuid);
1995
1996 trans->Append(stmt);
1997 }
1998
1999 CharacterDatabase.CommitTransaction(trans);
2000
2001 sCharacterCache->UpdateCharacterData(customizeInfo->CharGUID, customizeInfo->CharName, customizeInfo->SexID);
2002
2003 SendCharCustomize(RESPONSE_SUCCESS, customizeInfo.get());
2004
2005 TC_LOG_INFO("entities.player.character", "Account: {} (IP: {}), Character[{}] ({}) Customized to: {}",
2006 GetAccountId(), GetRemoteAddress(), oldName, customizeInfo->CharGUID.ToString(), customizeInfo->CharName);
2007}
2008
2010{
2011 if (saveEquipmentSet.Set.SetID >= MAX_EQUIPMENT_SET_INDEX) // client set slots amount
2012 return;
2013
2014 if (saveEquipmentSet.Set.Type > EquipmentSetInfo::TRANSMOG)
2015 return;
2016
2017 for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i)
2018 {
2019 if (!(saveEquipmentSet.Set.IgnoreMask & (1 << i)))
2020 {
2021 if (saveEquipmentSet.Set.Type == EquipmentSetInfo::EQUIPMENT)
2022 {
2023 saveEquipmentSet.Set.Appearances[i] = 0;
2024
2025 ObjectGuid const& itemGuid = saveEquipmentSet.Set.Pieces[i];
2026 if (!itemGuid.IsEmpty())
2027 {
2029
2031 if (!item)
2032 return;
2033
2035 if (item->GetGUID() != itemGuid)
2036 return;
2037 }
2038 else
2039 saveEquipmentSet.Set.IgnoreMask |= 1 << i;
2040 }
2041 else
2042 {
2043 saveEquipmentSet.Set.Pieces[i].Clear();
2044 if (saveEquipmentSet.Set.Appearances[i])
2045 {
2046 if (!sItemModifiedAppearanceStore.LookupEntry(saveEquipmentSet.Set.Appearances[i]))
2047 return;
2048
2049 auto [hasAppearance, isTemporary] = GetCollectionMgr()->HasItemAppearance(saveEquipmentSet.Set.Appearances[i]);
2050 if (!hasAppearance)
2051 return;
2052 }
2053 else
2054 saveEquipmentSet.Set.IgnoreMask |= 1 << i;
2055 }
2056 }
2057 else
2058 {
2059 saveEquipmentSet.Set.Pieces[i].Clear();
2060 saveEquipmentSet.Set.Appearances[i] = 0;
2061 }
2062 }
2063
2064 saveEquipmentSet.Set.IgnoreMask &= 0x7FFFF;
2065 if (saveEquipmentSet.Set.Type == EquipmentSetInfo::EQUIPMENT)
2066 {
2067 saveEquipmentSet.Set.Enchants[0] = 0;
2068 saveEquipmentSet.Set.Enchants[1] = 0;
2069 }
2070 else
2071 {
2072 auto validateIllusion = [this](uint32 enchantId) -> bool
2073 {
2074 SpellItemEnchantmentEntry const* illusion = sSpellItemEnchantmentStore.LookupEntry(enchantId);
2076 return false;
2077
2079 return false;
2080
2081 if (illusion->ScalingClassRestricted > 0 && uint8(illusion->ScalingClassRestricted) != _player->GetClass())
2082 return false;
2083
2084 return true;
2085 };
2086
2087 if (saveEquipmentSet.Set.Enchants[0] && !validateIllusion(saveEquipmentSet.Set.Enchants[0]))
2088 return;
2089
2090 if (saveEquipmentSet.Set.Enchants[1] && !validateIllusion(saveEquipmentSet.Set.Enchants[1]))
2091 return;
2092 }
2093
2094 _player->SetEquipmentSet(saveEquipmentSet.Set);
2095}
2096
2101
2103{
2104 ObjectGuid ignoredItemGuid;
2105 ignoredItemGuid.SetRawValue(0x0C00040000000000, 0xFFFFFFFFFFFFFFFF);
2106
2107 for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i)
2108 {
2109 TC_LOG_DEBUG("entities.player.items", "{}: ContainerSlot: {}, Slot: {}", useEquipmentSet.Items[i].Item.ToString(), useEquipmentSet.Items[i].ContainerSlot, useEquipmentSet.Items[i].Slot);
2110
2111 // check if item slot is set to "ignored" (raw value == 1), must not be unequipped then
2112 if (useEquipmentSet.Items[i].Item == ignoredItemGuid)
2113 continue;
2114
2115 // Only equip weapons in combat
2117 continue;
2118
2119 Item* item = _player->GetItemByGuid(useEquipmentSet.Items[i].Item);
2120
2121 uint16 dstPos = i | (INVENTORY_SLOT_BAG_0 << 8);
2122
2123 if (!item)
2124 {
2126 if (!uItem)
2127 continue;
2128
2129 ItemPosCountVec itemPosCountVec;
2130 InventoryResult inventoryResult = _player->CanStoreItem(NULL_BAG, NULL_SLOT, itemPosCountVec, uItem, false);
2131 if (inventoryResult == EQUIP_ERR_OK)
2132 {
2133 if (_player->CanUnequipItem(dstPos, true) != EQUIP_ERR_OK)
2134 continue;
2135
2137 _player->StoreItem(itemPosCountVec, uItem, true);
2138 }
2139 else
2140 _player->SendEquipError(inventoryResult, uItem, nullptr);
2141 continue;
2142 }
2143
2144 if (item->GetPos() == dstPos)
2145 continue;
2146
2147 if (_player->CanEquipItem(i, dstPos, item, true) != EQUIP_ERR_OK)
2148 continue;
2149
2150 _player->SwapItem(item->GetPos(), dstPos);
2151 }
2152
2154 result.GUID = useEquipmentSet.GUID;
2155 result.Reason = 0; // 4 - equipment swap failed - inventory is full
2156 SendPacket(result.Write());
2157}
2158
2160{
2162 {
2163 TC_LOG_ERROR("entities.player.cheat", "Account {}, IP: {} tried to factionchange character {}, but it does not belong to their account!",
2164 GetAccountId(), GetRemoteAddress(), packet.RaceOrFactionChangeInfo->Guid.ToString());
2165 KickPlayer("WorldSession::HandleCharFactionOrRaceChange Trying to change faction of character of another account");
2166 return;
2167 }
2168
2170 stmt->setUInt64(0, packet.RaceOrFactionChangeInfo->Guid.GetCounter());
2171
2173 .WithPreparedCallback([this, factionChangeInfo = std::move(packet.RaceOrFactionChangeInfo)](PreparedQueryResult result) mutable
2174 {
2175 HandleCharRaceOrFactionChangeCallback(std::move(factionChangeInfo), std::move(result));
2176 }));
2177}
2178
2179void WorldSession::HandleCharRaceOrFactionChangeCallback(std::shared_ptr<WorldPackets::Character::CharRaceOrFactionChangeInfo> factionChangeInfo, PreparedQueryResult result)
2180{
2181 if (!result)
2182 {
2183 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2184 return;
2185 }
2186
2187 // get the players old (at this moment current) race
2188 CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(factionChangeInfo->Guid);
2189 if (!characterInfo)
2190 {
2191 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2192 return;
2193 }
2194
2195 std::string oldName = characterInfo->Name;
2196 uint8 oldRace = characterInfo->Race;
2197 uint8 playerClass = characterInfo->Class;
2198 uint8 level = characterInfo->Level;
2199
2200 if (!sObjectMgr->GetPlayerInfo(factionChangeInfo->RaceID, playerClass))
2201 {
2202 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2203 return;
2204 }
2205
2206 Field* fields = result->Fetch();
2207 uint16 atLoginFlags = fields[0].GetUInt16();
2208 std::string knownTitlesStr = fields[1].GetString();
2209 uint32 groupId = fields[2].GetUInt32();
2210 uint32 mapId = fields[3].GetUInt16();
2211
2212 uint16 usedLoginFlag = (factionChangeInfo->FactionChange ? AT_LOGIN_CHANGE_FACTION : AT_LOGIN_CHANGE_RACE);
2213 if (!(atLoginFlags & usedLoginFlag))
2214 {
2215 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2216 return;
2217 }
2218
2219 if (level < 10)
2220 {
2221 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2222 return;
2223 }
2224
2225 if (playerClass == CLASS_DEATH_KNIGHT && (level < 60 || mapId == 609))
2226 {
2228 return;
2229 }
2230
2231 if (MapEntry const* mapEntry = sMapStore.LookupEntry(mapId); mapEntry && mapEntry->GetFlags().HasFlag(MapFlags::NoRaceChangeOnThisMap))
2232 {
2234 return;
2235 }
2236
2237 TeamId newTeamId = Player::TeamIdForRace(factionChangeInfo->RaceID);
2238 if (newTeamId == TEAM_NEUTRAL)
2239 {
2241 return;
2242 }
2243
2244 if (factionChangeInfo->FactionChange == (Player::TeamIdForRace(oldRace) == newTeamId))
2245 {
2246 SendCharFactionChange(factionChangeInfo->FactionChange ? CHAR_CREATE_CHARACTER_SWAP_FACTION : CHAR_CREATE_CHARACTER_RACE_ONLY, factionChangeInfo.get());
2247 return;
2248 }
2249
2251 {
2253 if (raceMaskDisabled.HasRace(factionChangeInfo->RaceID))
2254 {
2255 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2256 return;
2257 }
2258 }
2259
2260 // prevent character rename
2261 if (sWorld->getBoolConfig(CONFIG_PREVENT_RENAME_CUSTOMIZATION) && (factionChangeInfo->Name != oldName))
2262 {
2263 SendCharFactionChange(CHAR_NAME_FAILURE, factionChangeInfo.get());
2264 return;
2265 }
2266
2267 // prevent character rename to invalid name
2268 if (!normalizePlayerName(factionChangeInfo->Name))
2269 {
2270 SendCharFactionChange(CHAR_NAME_NO_NAME, factionChangeInfo.get());
2271 return;
2272 }
2273
2274 ResponseCodes res = ObjectMgr::CheckPlayerName(factionChangeInfo->Name, GetSessionDbcLocale(), true);
2275 if (res != CHAR_NAME_SUCCESS)
2276 {
2277 SendCharFactionChange(res, factionChangeInfo.get());
2278 return;
2279 }
2280
2281 // check name limitations
2282 if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(factionChangeInfo->Name))
2283 {
2284 SendCharFactionChange(CHAR_NAME_RESERVED, factionChangeInfo.get());
2285 return;
2286 }
2287
2288 // character with this name already exist
2289 ObjectGuid newGuid = sCharacterCache->GetCharacterGuidByName(factionChangeInfo->Name);
2290 if (!newGuid.IsEmpty())
2291 {
2292 if (newGuid != factionChangeInfo->Guid)
2293 {
2294 SendCharFactionChange(CHAR_CREATE_NAME_IN_USE, factionChangeInfo.get());
2295 return;
2296 }
2297 }
2298
2299 if (sArenaTeamMgr->GetArenaTeamByCaptain(factionChangeInfo->Guid))
2300 {
2302 return;
2303 }
2304
2305 // All checks are fine, deal with race change now
2306 ObjectGuid::LowType lowGuid = factionChangeInfo->Guid.GetCounter();
2307
2308 CharacterDatabasePreparedStatement* stmt = nullptr;
2309 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
2310
2311 // resurrect the character in case he's dead
2312 Player::OfflineResurrect(factionChangeInfo->Guid, trans);
2313
2314 // Name Change and update atLogin flags
2315 {
2316 CharacterDatabase.EscapeString(factionChangeInfo->Name);
2317
2318 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_NAME_AT_LOGIN);
2319 stmt->setString(0, factionChangeInfo->Name);
2320 stmt->setUInt16(1, uint16((atLoginFlags | AT_LOGIN_RESURRECT) & ~usedLoginFlag));
2321 stmt->setUInt64(2, lowGuid);
2322
2323 trans->Append(stmt);
2324
2325 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_DECLINED_NAME);
2326 stmt->setUInt64(0, lowGuid);
2327
2328 trans->Append(stmt);
2329 }
2330
2331 // Customize
2332 Player::SaveCustomizations(trans, lowGuid, MakeChrCustomizationChoiceRange(factionChangeInfo->Customizations));
2333
2334 // Race Change
2335 {
2336 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_RACE);
2337 stmt->setUInt8(0, factionChangeInfo->RaceID);
2339 stmt->setUInt64(2, lowGuid);
2340
2341 trans->Append(stmt);
2342 }
2343
2344 sCharacterCache->UpdateCharacterData(factionChangeInfo->Guid, factionChangeInfo->Name, factionChangeInfo->SexID, factionChangeInfo->RaceID);
2345
2346 if (oldRace != factionChangeInfo->RaceID)
2347 {
2348 // Switch Languages
2349 // delete all languages first
2350 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SKILL_LANGUAGES);
2351 stmt->setUInt64(0, lowGuid);
2352 trans->Append(stmt);
2353
2354 // Now add them back
2355 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_SKILL_LANGUAGE);
2356 stmt->setUInt64(0, lowGuid);
2357
2358 // Faction specific languages
2359 if (newTeamId == TEAM_HORDE)
2360 stmt->setUInt16(1, 109);
2361 else
2362 stmt->setUInt16(1, 98);
2363
2364 trans->Append(stmt);
2365
2366 // Race specific languages
2367 constexpr std::array<uint8, 4> racesWithoutSpecificLanguages = { RACE_ORC, RACE_HUMAN, RACE_MAGHAR_ORC, RACE_KUL_TIRAN };
2368 if (!advstd::ranges::contains(racesWithoutSpecificLanguages, factionChangeInfo->RaceID))
2369 {
2370 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_SKILL_LANGUAGE);
2371 stmt->setUInt64(0, lowGuid);
2372
2373 switch (factionChangeInfo->RaceID)
2374 {
2375 case RACE_DWARF:
2377 stmt->setUInt16(1, 111);
2378 break;
2379 case RACE_DRAENEI:
2381 stmt->setUInt16(1, 759);
2382 break;
2383 case RACE_GNOME:
2384 case RACE_MECHAGNOME:
2385 stmt->setUInt16(1, 313);
2386 break;
2387 case RACE_NIGHTELF:
2388 stmt->setUInt16(1, 113);
2389 break;
2390 case RACE_WORGEN:
2391 stmt->setUInt16(1, 791);
2392 break;
2393 case RACE_UNDEAD_PLAYER:
2394 stmt->setUInt16(1, 673);
2395 break;
2396 case RACE_TAUREN:
2398 stmt->setUInt16(1, 115);
2399 break;
2400 case RACE_TROLL:
2402 stmt->setUInt16(1, 315);
2403 break;
2404 case RACE_BLOODELF:
2405 case RACE_VOID_ELF:
2406 stmt->setUInt16(1, 137);
2407 break;
2408 case RACE_GOBLIN:
2409 stmt->setUInt16(1, 792);
2410 break;
2411 case RACE_NIGHTBORNE:
2412 stmt->setUInt16(1, 2464);
2413 break;
2414 case RACE_VULPERA:
2415 stmt->setUInt16(1, 2776);
2416 break;
2420 stmt->setUInt16(1, 905);
2421 break;
2424 stmt->setUInt16(1, 138);
2425 break;
2428 stmt->setUInt16(1, 140);
2429 break;
2431 case RACE_HARANIR_HORDE:
2432 stmt->setUInt16(1, 2987);
2433 break;
2434 default:
2435 TC_LOG_ERROR("entities.player", "Could not find language data for race ({}).", factionChangeInfo->RaceID);
2436 SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get());
2437 return;
2438 }
2439
2440 trans->Append(stmt);
2441 }
2442
2443 // Team Conversion
2444 if (factionChangeInfo->FactionChange)
2445 {
2446 // Delete all Flypaths
2447 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TAXI_PATH);
2448 stmt->setUInt64(0, lowGuid);
2449 trans->Append(stmt);
2450
2451 if (level > 7)
2452 {
2453 // Update Taxi path
2454 // this doesn't seem to be 100% blizzlike... but it can't really be helped.
2455 std::ostringstream taximaskstream;
2456 TaxiMask const& factionMask = newTeamId == TEAM_HORDE ? sHordeTaxiNodesMask : sAllianceTaxiNodesMask;
2457 for (std::size_t i = 0; i < factionMask.size(); ++i)
2458 {
2459 // i = (315 - 1) / 8 = 39
2460 // m = 1 << ((315 - 1) % 8) = 4
2461 uint8 deathKnightExtraNode = playerClass != CLASS_DEATH_KNIGHT || i != 39 ? 0 : 4;
2462 taximaskstream << uint32(factionMask[i] | deathKnightExtraNode) << ' ';
2463 }
2464
2465 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TAXIMASK);
2466 stmt->setString(0, taximaskstream.str());
2467 stmt->setUInt64(1, lowGuid);
2468 trans->Append(stmt);
2469 }
2470
2472 {
2473 // Reset guild
2474 if (Guild* guild = sGuildMgr->GetGuildById(characterInfo->GuildId))
2475 guild->DeleteMember(trans, factionChangeInfo->Guid, false, false);
2476
2477 Player::LeaveAllArenaTeams(factionChangeInfo->Guid);
2478 }
2479
2480 if (groupId && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
2481 {
2482 if (Group* group = sGroupMgr->GetGroupByDbStoreId(groupId))
2483 group->RemoveMember(factionChangeInfo->Guid);
2484 }
2485
2487 {
2488 // Delete Friend List
2489 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SOCIAL_BY_GUID);
2490 stmt->setUInt64(0, lowGuid);
2491 trans->Append(stmt);
2492
2493 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SOCIAL_BY_FRIEND);
2494 stmt->setUInt64(0, lowGuid);
2495 trans->Append(stmt);
2496 }
2497
2498 // Reset homebind and position
2499 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_HOMEBIND);
2500 stmt->setUInt64(0, lowGuid);
2501 trans->Append(stmt);
2502
2503 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PLAYER_HOMEBIND);
2504 stmt->setUInt64(0, lowGuid);
2505
2506 WorldLocation loc;
2507 uint16 zoneId = 0;
2508 if (newTeamId == TEAM_ALLIANCE)
2509 {
2510 loc.WorldRelocate(0, -8867.68f, 673.373f, 97.9034f, 0.0f);
2511 zoneId = 1519;
2512 }
2513 else
2514 {
2515 loc.WorldRelocate(1, 1633.33f, -4439.11f, 15.7588f, 0.0f);
2516 zoneId = 1637;
2517 }
2518
2519 stmt->setUInt16(1, loc.GetMapId());
2520 stmt->setUInt16(2, zoneId);
2521 stmt->setFloat(3, loc.GetPositionX());
2522 stmt->setFloat(4, loc.GetPositionY());
2523 stmt->setFloat(5, loc.GetPositionZ());
2524 trans->Append(stmt);
2525
2526 Player::SavePositionInDB(loc, zoneId, factionChangeInfo->Guid, trans);
2527
2528 // Achievement conversion
2529 for (auto [achiev_alliance, achiev_horde] : sObjectMgr->FactionChangeAchievements)
2530 {
2532 stmt->setUInt16(0, uint16(newTeamId == TEAM_ALLIANCE ? achiev_alliance : achiev_horde));
2533 stmt->setUInt64(1, lowGuid);
2534 trans->Append(stmt);
2535
2536 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_ACHIEVEMENT);
2537 stmt->setUInt32(0, uint16(newTeamId == TEAM_ALLIANCE ? achiev_alliance : achiev_horde));
2538 stmt->setUInt32(1, uint16(newTeamId == TEAM_ALLIANCE ? achiev_horde : achiev_alliance));
2539 stmt->setUInt64(2, lowGuid);
2540 trans->Append(stmt);
2541 }
2542
2543 // Item conversion
2544 ObjectMgr::CharacterConversionMap const& itemConversionMap = newTeamId == TEAM_ALLIANCE
2545 ? sObjectMgr->FactionChangeItemsHordeToAlliance
2546 : sObjectMgr->FactionChangeItemsAllianceToHorde;
2547 for (auto [oldItemId, newItemId] : itemConversionMap)
2548 {
2549 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_INVENTORY_FACTION_CHANGE);
2550 stmt->setUInt32(0, newItemId);
2551 stmt->setUInt32(1, oldItemId);
2552 stmt->setUInt64(2, lowGuid);
2553 trans->Append(stmt);
2554 }
2555
2556 // Delete all current quests
2557 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS);
2558 stmt->setUInt64(0, lowGuid);
2559 trans->Append(stmt);
2560
2561 // Quest conversion
2562 for (auto [quest_alliance, quest_horde] : sObjectMgr->FactionChangeQuests)
2563 {
2565 stmt->setUInt64(0, lowGuid);
2566 stmt->setUInt32(1, (newTeamId == TEAM_ALLIANCE ? quest_alliance : quest_horde));
2567 trans->Append(stmt);
2568
2570 stmt->setUInt32(0, (newTeamId == TEAM_ALLIANCE ? quest_alliance : quest_horde));
2571 stmt->setUInt32(1, (newTeamId == TEAM_ALLIANCE ? quest_horde : quest_alliance));
2572 stmt->setUInt64(2, lowGuid);
2573 trans->Append(stmt);
2574 }
2575
2576 // Mark all rewarded quests as "active" (will count for completed quests achievements)
2578 stmt->setUInt64(0, lowGuid);
2579 trans->Append(stmt);
2580
2581 // Disable all old-faction specific quests
2582 {
2583 ObjectMgr::QuestContainer const& questTemplates = sObjectMgr->GetQuestTemplates();
2584 for (auto const& [questId, quest] : questTemplates)
2585 {
2586 Trinity::RaceMask<int32, 2> newRaceMask = newTeamId == TEAM_ALLIANCE
2587 ? RACEMASK_ALLIANCE_v<int32, 2>
2588 : RACEMASK_HORDE_v<int32, 2>;
2589 if (quest->GetAllowableRaces() != RACEMASK_ALL_v<int32, 2> && (quest->GetAllowableRaces() & newRaceMask).IsEmpty())
2590 {
2592 stmt->setUInt64(0, lowGuid);
2593 stmt->setUInt32(1, questId);
2594 trans->Append(stmt);
2595 }
2596 }
2597 }
2598
2599 // Spell conversion
2600 for (auto [spell_alliance, spell_horde] : sObjectMgr->FactionChangeSpells)
2601 {
2602 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_BY_SPELL);
2603 stmt->setUInt32(0, (newTeamId == TEAM_ALLIANCE ? spell_alliance : spell_horde));
2604 stmt->setUInt64(1, lowGuid);
2605 trans->Append(stmt);
2606
2607 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_SPELL_FACTION_CHANGE);
2608 stmt->setUInt32(0, (newTeamId == TEAM_ALLIANCE ? spell_alliance : spell_horde));
2609 stmt->setUInt32(1, (newTeamId == TEAM_ALLIANCE ? spell_horde : spell_alliance));
2610 stmt->setUInt64(2, lowGuid);
2611 trans->Append(stmt);
2612 }
2613
2614 // Reputation conversion
2615 for (auto [reputation_alliance, reputation_horde] : sObjectMgr->FactionChangeReputation)
2616 {
2617 uint32 newReputation = (newTeamId == TEAM_ALLIANCE) ? reputation_alliance : reputation_horde;
2618 uint32 oldReputation = (newTeamId == TEAM_ALLIANCE) ? reputation_horde : reputation_alliance;
2619
2620 // select old standing set in db
2621 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_REP_BY_FACTION);
2622 stmt->setUInt32(0, oldReputation);
2623 stmt->setUInt64(1, lowGuid);
2624
2625 if (PreparedQueryResult reputationResult = CharacterDatabase.Query(stmt))
2626 {
2627 fields = reputationResult->Fetch();
2628 int32 oldDBRep = fields[0].GetInt32();
2629 FactionEntry const* factionEntry = sFactionStore.LookupEntry(oldReputation);
2630
2631 // old base reputation
2632 int32 oldBaseRep = ReputationMgr::GetBaseReputation(factionEntry, oldRace, playerClass);
2633
2634 // new base reputation
2635 int32 newBaseRep = ReputationMgr::GetBaseReputation(sFactionStore.LookupEntry(newReputation), factionChangeInfo->RaceID, playerClass);
2636
2637 // final reputation shouldnt change
2638 int32 FinalRep = oldDBRep + oldBaseRep;
2639 int32 newDBRep = FinalRep - newBaseRep;
2640
2641 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_REP_BY_FACTION);
2642 stmt->setUInt32(0, newReputation);
2643 stmt->setUInt64(1, lowGuid);
2644 trans->Append(stmt);
2645
2646 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_REP_FACTION_CHANGE);
2647 stmt->setUInt16(0, uint16(newReputation));
2648 stmt->setInt32(1, newDBRep);
2649 stmt->setUInt16(2, uint16(oldReputation));
2650 stmt->setUInt64(3, lowGuid);
2651 trans->Append(stmt);
2652 }
2653 }
2654
2655 // Title conversion
2656 if (!knownTitlesStr.empty())
2657 {
2658 std::vector<std::string_view> tokens = Trinity::Tokenize(knownTitlesStr, ' ', false);
2659 std::vector<uint32> knownTitles;
2660
2661 for (std::string_view token : tokens)
2662 {
2663 if (Optional<uint32> thisMask = Trinity::StringTo<uint32>(token))
2664 knownTitles.push_back(*thisMask);
2665 else
2666 {
2667 TC_LOG_WARN("entities.player", "{} has invalid title data '{}' - skipped, this may result in titles being lost",
2668 GetPlayerInfo(), token);
2669 knownTitles.push_back(0);
2670 }
2671 }
2672
2673 for (auto [title_alliance, title_horde] : sObjectMgr->FactionChangeTitles)
2674 {
2675 CharTitlesEntry const* atitleInfo = sCharTitlesStore.AssertEntry(title_alliance);
2676 CharTitlesEntry const* htitleInfo = sCharTitlesStore.AssertEntry(title_horde);
2677 // new team
2678 if (newTeamId == TEAM_ALLIANCE)
2679 {
2680 uint32 bitIndex = htitleInfo->MaskID;
2681 uint32 index = bitIndex / 32;
2682 if (index >= knownTitles.size())
2683 continue;
2684
2685 uint32 old_flag = 1 << (bitIndex % 32);
2686 uint32 new_flag = 1 << (atitleInfo->MaskID % 32);
2687 if (knownTitles[index] & old_flag)
2688 {
2689 knownTitles[index] &= ~old_flag;
2690 // use index of the new title
2691 knownTitles[atitleInfo->MaskID / 32] |= new_flag;
2692 }
2693 }
2694 else
2695 {
2696 uint32 bitIndex = htitleInfo->MaskID;
2697 uint32 index = bitIndex / 32;
2698 if (index >= knownTitles.size())
2699 continue;
2700
2701 uint32 old_flag = 1 << (bitIndex % 32);
2702 uint32 new_flag = 1 << (htitleInfo->MaskID % 32);
2703 if (knownTitles[index] & old_flag)
2704 {
2705 knownTitles[index] &= ~old_flag;
2706 // use index of the new title
2707 knownTitles[htitleInfo->MaskID / 32] |= new_flag;
2708 }
2709 }
2710
2711 std::ostringstream ss;
2712 for (uint32 mask : knownTitles)
2713 ss << mask << ' ';
2714
2715 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_TITLES_FACTION_CHANGE);
2716 stmt->setString(0, ss.str());
2717 stmt->setUInt64(1, lowGuid);
2718 trans->Append(stmt);
2719
2720 // unset any currently chosen title
2721 stmt = CharacterDatabase.GetPreparedStatement(CHAR_RES_CHAR_TITLES_FACTION_CHANGE);
2722 stmt->setUInt64(0, lowGuid);
2723 trans->Append(stmt);
2724 }
2725 }
2726 }
2727 }
2728
2729 CharacterDatabase.CommitTransaction(trans);
2730
2731 TC_LOG_DEBUG("entities.player", "{} (IP: {}) changed race from {} to {}", GetPlayerInfo(), GetRemoteAddress(), oldRace, factionChangeInfo->RaceID);
2732
2733 SendCharFactionChange(RESPONSE_SUCCESS, factionChangeInfo.get());
2734}
2735
2737{
2738 if (!Player::IsValidRace(packet.Race))
2739 {
2740 TC_LOG_ERROR("misc", "Invalid race ({}) sent by accountId: {}", packet.Race, GetAccountId());
2741 return;
2742 }
2743
2744 if (!Player::IsValidGender(packet.Sex))
2745 {
2746 TC_LOG_ERROR("misc", "Invalid gender ({}) sent by accountId: {}", packet.Sex, GetAccountId());
2747 return;
2748 }
2749
2751 result.Success = true;
2752 result.Name = sDB2Manager.GetNameGenEntry(packet.Race, packet.Sex);
2753
2754 SendPacket(result.Write());
2755}
2756
2758{
2759 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
2760
2761 for (WorldPackets::Character::ReorderCharacters::ReorderInfo const& reorderInfo : reorderChars.Entries)
2762 {
2764 stmt->setUInt8(0, reorderInfo.NewPosition);
2765 stmt->setUInt64(1, reorderInfo.PlayerGUID.GetCounter());
2766 stmt->setUInt32(2, GetAccountId());
2767 trans->Append(stmt);
2768 }
2769
2770 CharacterDatabase.CommitTransaction(trans);
2771}
2772
2774{
2775 // Only players that has not yet gained any experience can use this
2776 if (*_player->m_activePlayerData->XP)
2777 return;
2778
2779 if (ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(_player->GetClass()))
2780 {
2781 if (classEntry->CinematicSequenceID)
2782 _player->SendCinematicStart(classEntry->CinematicSequenceID);
2783 else if (ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(_player->GetRace()))
2784 _player->SendCinematicStart(raceEntry->CinematicSequenceID);
2785 }
2786}
2787
2789{
2791 stmt->setUInt32(0, GetBattlenetAccountId());
2792
2793 _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback([this](PreparedQueryResult result)
2794 {
2795 HandleUndeleteCooldownStatusCallback(std::move(result));
2796 }));
2797}
2798
2800{
2801 uint32 cooldown = 0;
2803 if (result)
2804 {
2805 uint32 lastUndelete = result->Fetch()[0].GetUInt32();
2807 if (lastUndelete + maxCooldown > now)
2808 cooldown = std::max<uint32>(0, lastUndelete + maxCooldown - now);
2809 }
2810
2811 SendUndeleteCooldownStatusResponse(cooldown, maxCooldown);
2812}
2813
2815{
2817 {
2819 return;
2820 }
2821
2823 stmt->setUInt32(0, GetBattlenetAccountId());
2824
2825 std::shared_ptr<WorldPackets::Character::CharacterUndeleteInfo> undeleteInfo = undeleteCharacter.UndeleteInfo;
2827 .WithChainingPreparedCallback([this, undeleteInfo](QueryCallback& queryCallback, PreparedQueryResult result)
2828 {
2829 if (result)
2830 {
2831 uint32 lastUndelete = result->Fetch()[0].GetUInt32();
2832 uint32 maxCooldown = sWorld->getIntConfig(CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_COOLDOWN);
2833 if (lastUndelete && (lastUndelete + maxCooldown > GameTime::GetGameTime()))
2834 {
2835 SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_COOLDOWN, undeleteInfo.get());
2836 return;
2837 }
2838 }
2839
2841 stmt->setUInt64(0, undeleteInfo->CharacterGuid.GetCounter());
2842 queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt));
2843 })
2844 .WithChainingPreparedCallback([this, undeleteInfo](QueryCallback& queryCallback, PreparedQueryResult result)
2845 {
2846 if (!result)
2847 {
2848 SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_CHAR_CREATE, undeleteInfo.get());
2849 return;
2850 }
2851
2852 Field* fields = result->Fetch();
2853 undeleteInfo->Name = fields[1].GetString();
2854 uint32 account = fields[2].GetUInt32();
2855
2856 if (account != GetAccountId())
2857 {
2858 SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_UNKNOWN, undeleteInfo.get());
2859 return;
2860 }
2861
2863 stmt->setString(0, undeleteInfo->Name);
2864 queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt));
2865 })
2866 .WithChainingPreparedCallback([this, undeleteInfo](QueryCallback& queryCallback, PreparedQueryResult result)
2867 {
2868 if (result)
2869 {
2870 SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_NAME_TAKEN_BY_THIS_ACCOUNT, undeleteInfo.get());
2871 return;
2872 }
2873
2879
2881 stmt->setUInt32(0, GetAccountId());
2882 queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt));
2883 })
2884 .WithPreparedCallback([this, undeleteInfo](PreparedQueryResult result)
2885 {
2886 if (result)
2887 {
2888 Field* fields = result->Fetch();
2889
2890 if (fields[0].GetUInt64() >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM)) // SQL's COUNT() returns uint64 but it will always be less than uint8.Max
2891 {
2892 SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_CHAR_CREATE, undeleteInfo.get());
2893 return;
2894 }
2895 }
2896
2898 stmt->setString(0, undeleteInfo->Name);
2899 stmt->setUInt32(1, GetAccountId());
2900 stmt->setUInt64(2, undeleteInfo->CharacterGuid.GetCounter());
2901 CharacterDatabase.Execute(stmt);
2902
2904 loginStmt->setUInt32(0, GetBattlenetAccountId());
2905 LoginDatabase.Execute(loginStmt);
2906
2907 sCharacterCache->UpdateCharacterInfoDeleted(undeleteInfo->CharacterGuid, false, undeleteInfo->Name);
2908
2909 SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_OK, undeleteInfo.get());
2910 }));
2911}
2912
2935
2936void WorldSession::SendCharCreate(ResponseCodes result, ObjectGuid const& guid /*= ObjectGuid::Empty*/)
2937{
2939 response.Code = result;
2940 response.Guid = guid;
2941
2942 SendPacket(response.Write());
2943}
2944
2946{
2948 response.Code = result;
2949
2950 SendPacket(response.Write());
2951}
2952
2954{
2956 packet.Result = result;
2957 packet.Name = renameInfo->NewName;
2958 if (result == RESPONSE_SUCCESS)
2959 packet.Guid = renameInfo->Guid;
2960
2961 SendPacket(packet.Write());
2962}
2963
2965{
2966 if (result == RESPONSE_SUCCESS)
2967 {
2968 WorldPackets::Character::CharCustomizeSuccess response(customizeInfo);
2969 SendPacket(response.Write());
2970 }
2971 else
2972 {
2974 failed.Result = uint8(result);
2975 failed.CharGUID = customizeInfo->CharGUID;
2976 SendPacket(failed.Write());
2977 }
2978}
2979
2981{
2983 packet.Result = result;
2984 packet.Guid = factionChangeInfo->Guid;
2985
2986 if (result == RESPONSE_SUCCESS)
2987 {
2988 packet.Display.emplace();
2989 packet.Display->Name = factionChangeInfo->Name;
2990 packet.Display->SexID = factionChangeInfo->SexID;
2991 packet.Display->Customizations = &factionChangeInfo->Customizations;
2992 packet.Display->RaceID = factionChangeInfo->RaceID;
2993 }
2994
2995 SendPacket(packet.Write());
2996}
2997
2999{
3001 packet.ResultCode = result;
3002 packet.Player = guid;
3003
3004 SendPacket(packet.Write());
3005}
3006
3008{
3010 response.OnCooldown = (currentCooldown > 0);
3011 response.MaxCooldown = maxCooldown;
3012 response.CurrentCooldown = currentCooldown;
3013
3014 SendPacket(response.Write());
3015}
3016
3018{
3020 response.UndeleteInfo = undeleteInfo;
3021 response.Result = result;
3022
3023 SendPacket(response.Write());
3024}
#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_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< MapEntry > sMapStore("Map.db2", &MapLoadInfo::Instance)
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:579
@ NoRaceChangeOnThisMap
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_GM_ON
Definition Language.h:387
@ LOG_LEVEL_INFO
Definition LogCommon.h:29
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:173
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:182
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:176
#define sLog
Definition Log.h:156
#define TC_LOG_WARN(filterType__, message__,...)
Definition Log.h:179
@ 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:1873
@ 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:730
@ EQUIPMENT_SLOT_END
Definition Player.h:734
@ EQUIPMENT_SLOT_OFFHAND
Definition Player.h:731
std::vector< ItemPosCount > ItemPosCountVec
Definition Player.h:827
@ PLAYER_EXTRA_HAS_RACE_CHANGED
Definition Player.h:610
constexpr uint8 INVENTORY_SLOT_BAG_0
Definition Player.h:706
@ PLAYER_FLAGS_CONTESTED_PVP
Definition Player.h:520
@ PLAYER_FLAGS_RESTING
Definition Player.h:517
@ PLAYER_LOCAL_FLAG_OVERRIDE_TRANSPORT_SERVER_TIME
Definition Player.h:577
@ AT_LOGIN_RESET_TALENTS
Definition Player.h:623
@ AT_LOGIN_RESET_SPELLS
Definition Player.h:622
@ AT_LOGIN_RESET_PET_TALENTS
Definition Player.h:625
@ AT_LOGIN_FIRST
Definition Player.h:626
@ AT_LOGIN_RESURRECT
Definition Player.h:629
@ AT_LOGIN_CUSTOMIZE
Definition Player.h:624
@ AT_LOGIN_RENAME
Definition Player.h:621
@ AT_LOGIN_CHANGE_RACE
Definition Player.h:628
@ AT_LOGIN_CHANGE_FACTION
Definition Player.h:627
Trinity::IteratorPair< UF::ChrCustomizationChoice const * > MakeChrCustomizationChoiceRange(Container const &container)
Definition Player.h:3435
@ PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS
Definition Player.h:974
@ PLAYER_LOGIN_QUERY_LOAD_CUSTOMIZATIONS
Definition Player.h:945
@ PLAYER_LOGIN_QUERY_LOAD_CURRENCY
Definition Player.h:998
@ PLAYER_LOGIN_QUERY_LOAD_GLYPHS
Definition Player.h:987
@ PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES
Definition Player.h:976
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_REW
Definition Player.h:995
@ MAX_PLAYER_LOGIN_QUERY
Definition Player.h:1012
@ PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS
Definition Player.h:957
@ PLAYER_LOGIN_QUERY_LOAD_AURA_EFFECTS
Definition Player.h:948
@ PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS
Definition Player.h:996
@ PLAYER_LOGIN_QUERY_LOAD_SOCIAL_LIST
Definition Player.h:972
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWERS
Definition Player.h:1005
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA
Definition Player.h:954
@ PLAYER_LOGIN_QUERY_LOAD_TRAIT_CONFIGS
Definition Player.h:1008
@ PLAYER_LOGIN_QUERY_LOAD_SKILLS
Definition Player.h:991
@ PLAYER_LOGIN_QUERY_LOAD_BG_DATA
Definition Player.h:986
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA_PROGRESS
Definition Player.h:955
@ PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFITS
Definition Player.h:985
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWER_ABILITIES
Definition Player.h:1006
@ PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFIT_SLOT
Definition Player.h:984
@ PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA
Definition Player.h:990
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS
Definition Player.h:966
@ PLAYER_LOGIN_QUERY_LOAD_PET_SLOTS
Definition Player.h:1001
@ PLAYER_LOGIN_QUERY_LOAD_ARTIFACTS
Definition Player.h:960
@ PLAYER_LOGIN_QUERY_LOAD_INVENTORY
Definition Player.h:959
@ PLAYER_LOGIN_QUERY_LOAD_REPUTATION
Definition Player.h:958
@ PLAYER_LOGIN_QUERY_LOAD_AZERITE_MILESTONE_POWERS
Definition Player.h:962
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON_BLUEPRINTS
Definition Player.h:1003
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_AZERITE
Definition Player.h:968
@ PLAYER_LOGIN_QUERY_LOAD_BANK_TAB_SETTINGS
Definition Player.h:1011
@ PLAYER_LOGIN_QUERY_LOAD_FROM
Definition Player.h:944
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS
Definition Player.h:952
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES
Definition Player.h:953
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_AZERITE_UNLOCKED_ESSENCE
Definition Player.h:970
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON_BUILDINGS
Definition Player.h:1004
@ PLAYER_LOGIN_QUERY_LOAD_DATA_FLAGS
Definition Player.h:1010
@ PLAYER_LOGIN_QUERY_LOAD_WEEKLY_QUEST_STATUS
Definition Player.h:992
@ PLAYER_LOGIN_QUERY_LOAD_SPELL_CHARGES
Definition Player.h:975
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_AZERITE_MILESTONE_POWER
Definition Player.h:969
@ PLAYER_LOGIN_QUERY_LOAD_AZERITE
Definition Player.h:961
@ PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS
Definition Player.h:997
@ PLAYER_LOGIN_QUERY_LOAD_GUILD
Definition Player.h:977
@ PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS
Definition Player.h:981
@ PLAYER_LOGIN_QUERY_LOAD_MAILS
Definition Player.h:965
@ PLAYER_LOGIN_QUERY_LOAD_AURAS
Definition Player.h:947
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_AZERITE_EMPOWERED
Definition Player.h:971
@ PLAYER_LOGIN_QUERY_LOAD_TALENTS
Definition Player.h:988
@ PLAYER_LOGIN_QUERY_LOAD_AZERITE_UNLOCKED_ESSENCES
Definition Player.h:963
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON
Definition Player.h:1002
@ PLAYER_LOGIN_QUERY_LOAD_BANNED
Definition Player.h:994
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_ARTIFACT
Definition Player.h:967
@ PLAYER_LOGIN_QUERY_LOAD_ARENA_INFO
Definition Player.h:978
@ PLAYER_LOGIN_QUERY_LOAD_GROUP
Definition Player.h:946
@ PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS
Definition Player.h:980
@ PLAYER_LOGIN_QUERY_LOAD_HOME_BIND
Definition Player.h:973
@ PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION
Definition Player.h:1000
@ PLAYER_LOGIN_QUERY_LOAD_SPELLS
Definition Player.h:950
@ PLAYER_LOGIN_QUERY_LOAD_SPELL_FAVORITES
Definition Player.h:951
@ PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFIT
Definition Player.h:982
@ PLAYER_LOGIN_QUERY_LOAD_DATA_ELEMENTS
Definition Player.h:1009
@ PLAYER_LOGIN_QUERY_LOAD_TRAIT_ENTRIES
Definition Player.h:1007
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_SPAWN_TRACKING
Definition Player.h:956
@ PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFIT_SITUATION
Definition Player.h:983
@ PLAYER_LOGIN_QUERY_LOAD_AZERITE_EMPOWERED
Definition Player.h:964
@ PLAYER_LOGIN_QUERY_LOAD_PVP_TALENTS
Definition Player.h:989
@ PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES
Definition Player.h:999
@ PLAYER_LOGIN_QUERY_LOAD_RANDOM_BG
Definition Player.h:993
@ PLAYER_LOGIN_QUERY_LOAD_AURA_STORED_LOCATIONS
Definition Player.h:949
@ PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS
Definition Player.h:979
Races
Definition RaceMask.h:28
@ RACE_DARK_IRON_DWARF
Definition RaceMask.h:63
@ RACE_TROLL
Definition RaceMask.h:37
@ RACE_UNDEAD_PLAYER
Definition RaceMask.h:34
@ RACE_PANDAREN_NEUTRAL
Definition RaceMask.h:53
@ RACE_ORC
Definition RaceMask.h:31
@ RACE_LIGHTFORGED_DRAENEI
Definition RaceMask.h:59
@ RACE_NONE
Definition RaceMask.h:29
@ RACE_DRAENEI
Definition RaceMask.h:40
@ RACE_EARTHEN_DWARF_HORDE
Definition RaceMask.h:79
@ RACE_NIGHTBORNE
Definition RaceMask.h:56
@ RACE_HIGHMOUNTAIN_TAUREN
Definition RaceMask.h:57
@ RACE_HARANIR_HORDE
Definition RaceMask.h:84
@ RACE_EARTHEN_DWARF_ALLIANCE
Definition RaceMask.h:80
@ RACE_DRACTHYR_HORDE
Definition RaceMask.h:68
@ RACE_ZANDALARI_TROLL
Definition RaceMask.h:60
@ RACE_VOID_ELF
Definition RaceMask.h:58
@ RACE_NIGHTELF
Definition RaceMask.h:33
@ RACE_BLOODELF
Definition RaceMask.h:39
@ RACE_DWARF
Definition RaceMask.h:32
@ RACE_GNOME
Definition RaceMask.h:36
@ RACE_GOBLIN
Definition RaceMask.h:38
@ RACE_KUL_TIRAN
Definition RaceMask.h:61
@ RACE_HUMAN
Definition RaceMask.h:30
@ RACE_DRACTHYR_ALLIANCE
Definition RaceMask.h:67
@ RACE_WORGEN
Definition RaceMask.h:51
@ RACE_PANDAREN_ALLIANCE
Definition RaceMask.h:54
@ RACE_VULPERA
Definition RaceMask.h:64
@ RACE_MECHAGNOME
Definition RaceMask.h:66
@ RACE_HARANIR_ALLIANCE
Definition RaceMask.h:81
@ RACE_MAGHAR_ORC
Definition RaceMask.h:65
@ RACE_PANDAREN_HORDE
Definition RaceMask.h:55
@ RACE_TAUREN
Definition RaceMask.h:35
#define sRealmList
Definition RealmList.h:95
#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:269
@ UNIT_STATE_STUNNED
Definition Unit.h:278
@ 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:209
Definition Group.h:209
Definition Guild.h:329
Definition Item.h:185
uint16 GetPos() const
Definition Item.h:300
LoginQueryHolder(uint32 accountId, ObjectGuid guid)
ObjectGuid GetGuid() const
uint32 GetAccountId() const
virtual bool AddPlayerToMap(Player *player, bool initPlayer=true)
Definition Map.cpp:392
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:6207
void SendEquipError(InventoryResult msg, Item const *item1=nullptr, Item const *item2=nullptr, uint32 itemId=0) const
Definition Player.cpp:13048
void SetWatchedFactionIndex(int32 index)
Definition Player.h:2999
void SendInitialPacketsAfterAddToMap()
Definition Player.cpp:25024
uint32 GetXP() const
Definition Player.h:1313
static Team TeamForRace(uint8 race)
Definition Player.cpp:6371
static TeamId TeamIdForRace(uint8 race)
Definition Player.cpp:6389
InventoryResult CanUnequipItem(uint16 src, bool swap) const
Definition Player.cpp:10931
void RemoveAtLoginFlag(AtLoginFlags flags, bool persist=false)
Definition Player.cpp:28375
void ResetSpells(bool myClassOnly=false)
Definition Player.cpp:25182
bool ModifyMoney(int64 amount, bool sendError=true)
Definition Player.cpp:24800
InventoryResult CanEquipItem(uint8 slot, uint16 &dest, Item *pItem, bool swap, bool not_loading=true) const
Definition Player.cpp:10709
void UpdateAverageItemLevelEquipped()
Definition Player.cpp:30914
void SendRaidDifficulty(bool legacy) const
Definition Player.cpp:21820
void SetPlayerLocalFlag(PlayerLocalFlags flags)
Definition Player.h:2992
Creature * GetNPCIfCanInteractWith(ObjectGuid const &guid, NPCFlags npcFlags, NPCFlags2 npcFlags2) const
Definition Player.cpp:1814
void SetNativeGender(Gender gender) override
Definition Player.h:1335
Gender GetNativeGender() const override
Definition Player.h:1334
UF::UpdateField< UF::ActivePlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_ACTIVE_PLAYER > m_activePlayerData
Definition Player.h:3048
void SetEquipmentSet(EquipmentSetInfo::EquipmentSetData const &newEqSet)
Definition Player.cpp:28145
InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap=false) const
Definition Player.cpp:9975
void SendDungeonDifficulty() const
Definition Player.cpp:21813
void CleanupsBeforeDelete(bool finalCleanup=true) override
Definition Player.cpp:379
void SendTalentsInfoData()
Definition Player.cpp:28051
static void OfflineResurrect(ObjectGuid const &guid, CharacterDatabaseTransaction trans)
Definition Player.cpp:4387
SceneMgr & GetSceneMgr()
Definition Player.h:2873
void ContinueTaxiFlight()
Definition Player.cpp:23318
void SendInitialPacketsBeforeAddToMap()
Definition Player.cpp:24905
static void SavePositionInDB(WorldLocation const &loc, uint16 zoneId, ObjectGuid guid, CharacterDatabaseTransaction trans)
Definition Player.cpp:21773
void SendCorpseReclaimDelay(uint32 delay) const
Definition Player.cpp:26589
int64 GetBarberShopCost(Trinity::IteratorPair< UF::ChrCustomizationChoice const * > newCustomizations) const
Definition Player.cpp:26967
static void SaveCustomizations(CharacterDatabaseTransaction trans, ObjectGuid::LowType guid, Trinity::IteratorPair< UF::ChrCustomizationChoice const * > customizations)
Definition Player.cpp:20818
WorldLocation m_homebind
Definition Player.h:2679
void SwapItem(uint16 src, uint16 dst)
Definition Player.cpp:12567
void InitDisplayIds()
Definition Player.cpp:23404
Item * StoreItem(ItemPosCountVec const &pos, Item *pItem, bool update)
Definition Player.cpp:11365
WorldSession * GetSession() const
Definition Player.h:2256
Item * GetItemByPos(uint16 pos) const
Definition Player.cpp:9538
void ResetTalentSpecialization()
Definition Player.cpp:27649
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition Player.cpp:27532
void AddExploredZones(uint32 pos, uint64 mask)
Definition Player.cpp:6289
void SetInGuild(ObjectGuid::LowType guildId)
Definition Player.cpp:7362
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:1181
void SetPersonalTabard(uint32 style, uint32 color, uint32 borderStyle, uint32 borderColor, uint32 backgroundColor)
Definition Player.cpp:23058
ObjectGuid::LowType GetGuildId() const
Definition Player.h:2147
bool IsGameMaster() const
Definition Player.h:1293
void SetGuildRank(uint8 rankId)
Definition Player.h:2142
void LoadCorpse(PreparedQueryResult result)
Definition Player.cpp:19114
static void DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRealmChars=true, bool deleteFinally=false)
Definition Player.cpp:3658
void SendCinematicStart(uint32 CinematicSequenceId) const
Definition Player.cpp:6198
uint8 getCinematic() const
Definition Player.h:2093
uint32 GetXPForNextLevel() const
Definition Player.h:1314
void SetTransportServerTime(int32 transportServerTime)
Definition Player.h:3004
void DeleteEquipmentSet(uint64 id)
Definition Player.cpp:28359
bool LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const &holder)
Definition Player.cpp:17930
static bool IsValidGender(uint8 Gender)
Definition Player.h:1859
void UpdateAverageItemLevelTotal()
Definition Player.cpp:30857
bool HasAtLoginFlag(AtLoginFlags f) const
Definition Player.h:2709
static void LeaveAllArenaTeams(ObjectGuid guid)
Definition Player.cpp:23068
void RemoveItem(uint8 bag, uint8 slot, bool update)
Definition Player.cpp:11907
static bool IsValidRace(uint8 Race)
Definition Player.h:1861
int32 CalculateCorpseReclaimDelay(bool load=false) const
Definition Player.cpp:26548
Group * GetGroup(Optional< uint8 > partyIndex)
Definition Player.h:2781
bool HasPlayerFlag(PlayerFlags flags) const
Definition Player.h:2895
void SetGuildLevel(uint32 level)
Definition Player.h:2144
void SetTaxiCheater(bool on)
Definition Player.h:1300
void SetVirtualPlayerRealm(uint32 virtualRealmAddress)
Definition Player.h:2936
void SetContestedPvP(Player *attackedPlayer=nullptr)
Definition Player.cpp:21933
Item * GetItemByGuid(ObjectGuid guid) const
Definition Player.cpp:9522
void ResummonPetTemporaryUnSummonedIfAny()
Definition Player.cpp:27944
PlayerCreateMode GetCreateMode() const
Definition Player.h:2091
bool ResetTalents(bool noCost=false)
Definition Player.cpp:3427
void SetInGameTime(uint32 time)
Definition Player.h:1825
void setCinematic(uint8 cine)
Definition Player.h:2094
ReputationMgr & GetReputationMgr()
Definition Player.h:2422
bool IsQuestRewarded(uint32 quest_id) const
Definition Player.cpp:24839
void SetCustomizations(Trinity::IteratorPair< Iter > customizations, bool markChanged=true)
Definition Player.h:2921
Team GetTeam() const
Definition Player.h:2406
bool HasEnoughMoney(uint64 amount) const
Definition Player.h:1892
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)
int32 GetBaseReputation(FactionEntry const *factionEntry) const
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:2533
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:10876
void SetStandState(UnitStandStateType state, uint32 animKitID=0)
Definition Unit.cpp:10804
uint8 GetClass() const
Definition Unit.h:776
MotionMaster * GetMotionMaster()
Definition Unit.h:1750
DeathState m_deathState
Definition Unit.h:1920
bool IsStandState() const
Definition Unit.cpp:10798
void UpdateMountCapability()
Definition Unit.cpp:8478
void SetPvpFlag(UnitPVPStateFlags flags)
Definition Unit.h:896
void RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const *source=nullptr)
Definition Unit.cpp:4259
bool HasUnitState(const uint32 f) const
Definition Unit.h:755
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4822
UnitStandStateType GetStandState() const
Definition Unit.h:915
bool SetWaterWalking(bool enable)
Definition Unit.cpp:13581
uint8 GetLevel() const
Definition Unit.h:769
uint8 GetRace() const
Definition Unit.h:773
bool IsInCombat() const
Definition Unit.h:1073
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:1575
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2222
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 HandleCharEnumOpcode(WorldPackets::Character::EnumCharacters &enumCharacters)
void SetPlayer(Player *player)
void HandleRandomizeCharNameOpcode(WorldPackets::Character::GenerateRandomCharacterName &packet)
void HandleOpeningCinematic(WorldPackets::Misc::OpeningCinematic &packet)
void HandleSetFactionAtWar(WorldPackets::Character::SetFactionAtWar &packet)
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
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
void HandleCharUndeleteEnumOpcode(WorldPackets::Character::EnumCharacters &enumCharacters)
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:919
uint32 GetVirtualRealmAddress()
Definition World.cpp:3500
@ CONFIG_ARENA_SEASON_ID
Definition World.h:344
@ CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK
Definition World.h:256
@ CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_EVOKER
Definition World.h:261
@ CONFIG_CHARACTER_CREATING_DISABLED
Definition World.h:255
@ CONFIG_ENABLE_SINFO_LOGIN
Definition World.h:354
@ CONFIG_CHARACTERS_PER_ACCOUNT
Definition World.h:257
@ CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_COOLDOWN
Definition World.h:408
@ CONFIG_CHARACTER_CREATING_EVOKERS_PER_REALM
Definition World.h:259
@ CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_DEMON_HUNTER
Definition World.h:260
@ CONFIG_SKIP_CINEMATICS
Definition World.h:262
@ CONFIG_CHARACTERS_PER_REALM
Definition World.h:258
@ 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:198
@ 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:440
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< int32, 2 > 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::@199::@233 barberChair
PlayerCreateInfoSpells castSpells[size_t(PlayerCreateMode::Max)]
Definition ObjectMgr.h:664
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 HasRace(uint32 raceId) const
Definition RaceMask.h:149
constexpr bool IsEmpty() const
Definition RaceMask.h:167
Array< ChrCustomizationChoice, 250 > Customizations