TrinityCore
Loading...
Searching...
No Matches
cs_character.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/* ScriptData
19Name: character_commandscript
20%Complete: 100
21Comment: All character related commands
22Category: commandscripts
23EndScriptData */
24
25#include "ScriptMgr.h"
26#include "AccountMgr.h"
27#include "CharacterCache.h"
28#include "Chat.h"
29#include "ChatCommand.h"
30#include "DatabaseEnv.h"
31#include "DB2Stores.h"
32#include "Log.h"
33#include "ObjectMgr.h"
34#include "Player.h"
35#include "PlayerDump.h"
36#include "ReputationMgr.h"
37#include "World.h"
38#include "WorldSession.h"
39#include <sstream>
40
41using namespace Trinity::ChatCommands;
42
44{
45public:
46 character_commandscript() : CommandScript("character_commandscript") { }
47
48 std::span<ChatCommandBuilder const> GetCommands() const override
49 {
50 static ChatCommandTable pdumpCommandTable =
51 {
55 };
56 static ChatCommandTable characterDeletedCommandTable =
57 {
62 };
63
64 static ChatCommandTable characterCommandTable =
65 {
70 { "deleted", characterDeletedCommandTable },
76 };
77
78 static ChatCommandTable commandTable =
79 {
80 { "character", characterCommandTable },
81 { "levelup", HandleLevelUpCommand, rbac::RBAC_PERM_COMMAND_LEVELUP, Console::No },
82 { "pdump", pdumpCommandTable },
83 };
84 return commandTable;
85 }
86
87 // Stores informations about a deleted character
89 {
91 std::string name;
93 std::string accountName;
94 time_t deleteDate;
95 };
96
97 typedef std::list<DeletedInfo> DeletedInfoList;
98
106 static bool GetDeletedCharacterInfoList(DeletedInfoList& foundList, std::string_view searchString)
107 {
108 PreparedQueryResult result;
110 if (!searchString.empty())
111 {
112 // search by GUID
113 if (Optional<uint64> guidValue = Trinity::StringTo<uint64>(searchString))
114 {
115 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_DEL_INFO_BY_GUID);
116 stmt->setUInt64(0, *guidValue);
117 result = CharacterDatabase.Query(stmt);
118 }
119 // search by name
120 else
121 {
122 std::string normalizedName(searchString);
123 if (!normalizePlayerName(normalizedName))
124 return false;
125
126 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_DEL_INFO_BY_NAME);
127 stmt->setString(0, normalizedName);
128 result = CharacterDatabase.Query(stmt);
129 }
130 }
131 else
132 {
133 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_DEL_INFO);
134 result = CharacterDatabase.Query(stmt);
135 }
136
137 if (result)
138 {
139 do
140 {
141 Field* fields = result->Fetch();
142
143 DeletedInfo info;
144
145 info.guid = ObjectGuid::Create<HighGuid::Player>(fields[0].GetUInt64());
146 info.name = fields[1].GetString();
147 info.accountId = fields[2].GetUInt32();
148
149 // account name will be empty for nonexisting account
151 info.deleteDate = fields[3].GetInt64();
152 foundList.push_back(info);
153 }
154 while (result->NextRow());
155 }
156
157 return true;
158 }
159
170 static void HandleCharacterDeletedListHelper(DeletedInfoList const& foundList, ChatHandler* handler)
171 {
172 if (!handler->GetSession())
173 {
177 }
178
179 for (DeletedInfoList::const_iterator itr = foundList.begin(); itr != foundList.end(); ++itr)
180 {
181 std::string dateStr = TimeToTimestampStr(itr->deleteDate);
182
183 if (!handler->GetSession())
185 Trinity::ToString(itr->guid.GetCounter()), itr->name.c_str(), itr->accountName.empty() ? "<Not existing>" : itr->accountName.c_str(),
186 itr->accountId, dateStr.c_str());
187 else
189 Trinity::ToString(itr->guid.GetCounter()), itr->name.c_str(), itr->accountName.empty() ? "<Not existing>" : itr->accountName.c_str(),
190 itr->accountId, dateStr.c_str());
191 }
192
193 if (!handler->GetSession())
195 }
196
207 static void HandleCharacterDeletedRestoreHelper(DeletedInfo const& delInfo, ChatHandler* handler)
208 {
209 if (delInfo.accountName.empty()) // account does not exist
210 {
212 return;
213 }
214
215 // check character count
217 if (charcount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM))
218 {
220 return;
221 }
222
223 if (!sCharacterCache->GetCharacterGuidByName(delInfo.name).IsEmpty())
224 {
226 return;
227 }
228
230 stmt->setString(0, delInfo.name);
231 stmt->setUInt32(1, delInfo.accountId);
232 stmt->setUInt64(2, delInfo.guid.GetCounter());
233 CharacterDatabase.Execute(stmt);
234
235 sCharacterCache->UpdateCharacterInfoDeleted(delInfo.guid, false, delInfo.name);
236 }
237
239 {
240 if (!player)
241 player = PlayerIdentifier::FromTargetOrSelf(handler);
242 if (!player || !player->IsConnected())
243 {
245 handler->SetSentErrorMessage(true);
246 return false;
247 }
248
249 Player const* target = player->GetConnectedPlayer();
250
251 LocaleConstant loc = handler->GetSessionDbcLocale();
252 char const* knownStr = handler->GetTrinityString(LANG_KNOWN);
253
254 // Search in CharTitles.dbc
255 for (uint32 id = 0; id < sCharTitlesStore.GetNumRows(); id++)
256 {
257 CharTitlesEntry const* titleInfo = sCharTitlesStore.LookupEntry(id);
258
259 if (titleInfo && target->HasTitle(titleInfo))
260 {
261 char const* name = target->GetNativeGender() == GENDER_MALE ? titleInfo->Name[loc] : titleInfo->Name1[loc];
262 if (!*name)
263 name = (target->GetNativeGender() == GENDER_MALE ? titleInfo->Name[sWorld->GetDefaultDbcLocale()] : titleInfo->Name1[sWorld->GetDefaultDbcLocale()]);
264 if (!*name)
265 continue;
266
267 char const* activeStr = "";
268 if (*target->m_playerData->PlayerTitle == titleInfo->MaskID)
269 activeStr = handler->GetTrinityString(LANG_ACTIVE);
270
271 std::string titleName = ChatHandler::PGetParseString(name, player->GetName());
272
273 // send title in "id (idx:idx) - [namedlink locale]" format
274 if (handler->GetSession())
275 handler->PSendSysMessage(LANG_TITLE_LIST_CHAT, id, titleInfo->MaskID, id, titleName.c_str(), localeNames[loc], knownStr, activeStr);
276 else
277 handler->PSendSysMessage(LANG_TITLE_LIST_CONSOLE, id, titleInfo->MaskID, name, localeNames[loc], knownStr, activeStr);
278 }
279 }
280
281 return true;
282 }
283
284 //rename characters
286 {
287 if (!player && newNameV)
288 return false;
289
290 if (!player)
291 player = PlayerIdentifier::FromTarget(handler);
292 if (!player)
293 return false;
294
295 if (handler->HasLowerSecurity(nullptr, player->GetGUID()))
296 return false;
297
298 if (newNameV)
299 {
300 std::string newName{ *newNameV };
301 if (!normalizePlayerName(newName))
302 {
304 handler->SetSentErrorMessage(true);
305 return false;
306 }
307
308 if (ObjectMgr::CheckPlayerName(newName, player->IsConnected() ? player->GetConnectedPlayer()->GetSession()->GetSessionDbcLocale() : sWorld->GetDefaultDbcLocale(), true) != CHAR_NAME_SUCCESS)
309 {
311 handler->SetSentErrorMessage(true);
312 return false;
313 }
314
315 if (WorldSession* session = handler->GetSession())
316 {
317 if (!session->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(newName))
318 {
320 handler->SetSentErrorMessage(true);
321 return false;
322 }
323 }
324
326 stmt->setString(0, newName);
327 PreparedQueryResult result = CharacterDatabase.Query(stmt);
328 if (result)
329 {
330 handler->PSendSysMessage(LANG_RENAME_PLAYER_ALREADY_EXISTS, newName.c_str());
331 handler->SetSentErrorMessage(true);
332 return false;
333 }
334
335 // Remove declined name from db
336 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_DECLINED_NAME);
337 stmt->setUInt64(0, player->GetGUID().GetCounter());
338 CharacterDatabase.Execute(stmt);
339
340 if (Player* target = player->GetConnectedPlayer())
341 {
342 target->SetName(newName);
343
344 if (WorldSession* session = target->GetSession())
345 session->KickPlayer("HandleCharacterRenameCommand GM Command renaming character");
346 }
347 else
348 {
349 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_NAME_BY_GUID);
350 stmt->setString(0, newName);
351 stmt->setUInt64(1, player->GetGUID().GetCounter());
352 CharacterDatabase.Execute(stmt);
353 }
354
355 sCharacterCache->UpdateCharacterData(*player, newName);
356
357 handler->PSendSysMessage(LANG_RENAME_PLAYER_WITH_NEW_NAME, player->GetName().c_str(), newName.c_str());
358
359 if (WorldSession* session = handler->GetSession())
360 {
361 if (Player* player = session->GetPlayer())
362 sLog->OutCommand(session->GetAccountId(), "GM {} (Account: {}) forced rename {} to player {} (Account: {})", player->GetName(), session->GetAccountId(), newName, player->GetName(), sCharacterCache->GetCharacterAccountIdByGuid(player->GetGUID()));
363 }
364 else
365 sLog->OutCommand(0, "CONSOLE forced rename '{}' to '{}' ({})", player->GetName(), newName, player->GetGUID().ToString());
366 }
367 else
368 {
369 if (Player* target = player->GetConnectedPlayer())
370 {
371 handler->PSendSysMessage(LANG_RENAME_PLAYER, handler->GetNameLink(target).c_str());
372 target->SetAtLoginFlag(AT_LOGIN_RENAME);
373 }
374 else
375 {
376 // check offline security
377 if (handler->HasLowerSecurity(nullptr, player->GetGUID()))
378 return false;
379
380 handler->PSendSysMessage(LANG_RENAME_PLAYER_GUID, handler->playerLink(*player).c_str(), player->GetGUID().ToString().c_str());
381
384 stmt->setUInt64(1, player->GetGUID().GetCounter());
385 CharacterDatabase.Execute(stmt);
386 }
387 }
388
389 return true;
390 }
391
392 // customize characters
394 {
395 if (!player)
396 player = PlayerIdentifier::FromTarget(handler);
397 if (!player)
398 return false;
399
400 if (Player* target = player->GetConnectedPlayer())
401 {
402 handler->PSendSysMessage(LANG_CUSTOMIZE_PLAYER, handler->GetNameLink(target).c_str());
403 target->SetAtLoginFlag(AT_LOGIN_CUSTOMIZE);
404 }
405 else
406 {
407 handler->PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, handler->playerLink(*player).c_str(), player->GetGUID().ToString().c_str());
409 stmt->setUInt16(0, static_cast<uint16>(AT_LOGIN_CUSTOMIZE));
410 stmt->setUInt64(1, player->GetGUID().GetCounter());
411 CharacterDatabase.Execute(stmt);
412 }
413
414 return true;
415 }
416
418 {
419 if (!player)
420 player = PlayerIdentifier::FromTarget(handler);
421 if (!player)
422 return false;
423
424 CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(player->GetGUID());
425 if (!characterInfo)
426 return false;
427
428 if (characterInfo->Level < 10)
429 {
431 handler->SetSentErrorMessage(true);
432 return false;
433 }
434
435 if (characterInfo->Class == CLASS_DEATH_KNIGHT && characterInfo->Level < 60)
436 {
438 handler->SetSentErrorMessage(true);
439 return false;
440 }
441
442 if (Player* target = player->GetConnectedPlayer())
443 {
444 handler->PSendSysMessage(LANG_CUSTOMIZE_PLAYER, handler->GetNameLink(target).c_str());
445 target->SetAtLoginFlag(AT_LOGIN_CHANGE_FACTION);
446 }
447 else
448 {
449 handler->PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, handler->playerLink(*player).c_str(), player->GetGUID().ToString().c_str());
452 stmt->setUInt64(1, player->GetGUID().GetCounter());
453 CharacterDatabase.Execute(stmt);
454 }
455
456 return true;
457 }
458
460 {
461 if (!player)
462 player = PlayerIdentifier::FromTarget(handler);
463 if (!player)
464 return false;
465
466 if (Player* target = player->GetConnectedPlayer())
467 {
468 handler->PSendSysMessage(LANG_CUSTOMIZE_PLAYER, handler->GetNameLink(target).c_str());
469 target->SetAtLoginFlag(AT_LOGIN_CHANGE_RACE);
470 }
471 else
472 {
473 handler->PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, handler->playerLink(*player).c_str(), player->GetGUID().ToString().c_str());
476 stmt->setUInt64(1, player->GetGUID().GetCounter());
477 CharacterDatabase.Execute(stmt);
478 }
479
480 return true;
481 }
482
484 {
485 if (!player)
486 player = PlayerIdentifier::FromTarget(handler);
487 if (!player)
488 return false;
489
490 CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(player->GetGUID());
491 if (!characterInfo)
492 {
494 handler->SetSentErrorMessage(true);
495 return false;
496 }
497
498 uint32 oldAccountId = characterInfo->AccountId;
499 // nothing to do :)
500 if (newAccount.GetID() == oldAccountId)
501 return true;
502
503 if (uint32 charCount = AccountMgr::GetCharactersCount(newAccount.GetID()))
504 {
505 if (charCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM))
506 {
507 handler->PSendSysMessage(LANG_ACCOUNT_CHARACTER_LIST_FULL, newAccount.GetName().c_str(), newAccount.GetID());
508 handler->SetSentErrorMessage(true);
509 return false;
510 }
511 }
512
513 if (Player* onlinePlayer = player->GetConnectedPlayer())
514 onlinePlayer->GetSession()->KickPlayer("HandleCharacterChangeAccountCommand GM Command transferring character to another account");
515
517 charStmt->setUInt32(0, newAccount.GetID());
518 charStmt->setUInt64(1, player->GetGUID().GetCounter());
519 CharacterDatabase.DirectExecute(charStmt);
520
521 sWorld->UpdateRealmCharCount(oldAccountId);
522 sWorld->UpdateRealmCharCount(newAccount.GetID());
523
524 sCharacterCache->UpdateCharacterAccountId(*player, newAccount.GetID());
525
526 handler->PSendSysMessage(LANG_CHANGEACCOUNT_SUCCESS, player->GetName().c_str(), newAccount.GetName().c_str());
527
528 std::string logString = Trinity::StringFormat("changed ownership of player {} ({}) from account {} to account {}", player->GetName(), player->GetGUID().ToString(), oldAccountId, newAccount.GetID());
529 if (WorldSession* session = handler->GetSession())
530 {
531 if (Player* player = session->GetPlayer())
532 sLog->OutCommand(session->GetAccountId(), "GM {} (Account: {}) {}", player->GetName(), session->GetAccountId(), logString);
533 }
534 else
535 sLog->OutCommand(0, "{} {}", handler->GetTrinityString(LANG_CONSOLE), logString);
536 return true;
537 }
538
540 {
541 if (!player)
542 player = PlayerIdentifier::FromTargetOrSelf(handler);
543 if (!player || !player->IsConnected())
544 {
546 handler->SetSentErrorMessage(true);
547 return false;
548 }
549
550 Player const* target = player->GetConnectedPlayer();
551 LocaleConstant loc = handler->GetSessionDbcLocale();
552
553 FactionStateList const& targetFSL = target->GetReputationMgr().GetStateList();
554 for (FactionStateList::const_iterator itr = targetFSL.begin(); itr != targetFSL.end(); ++itr)
555 {
556 FactionState const& faction = itr->second;
557 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction.ID);
558 char const* factionName = factionEntry ? factionEntry->Name[loc] : "#Not found#";
559 std::string rankName = target->GetReputationMgr().GetReputationRankName(factionEntry);
560 std::ostringstream ss;
561 if (handler->GetSession())
562 ss << faction.ID << " - |cffffffff|Hfaction:" << faction.ID << "|h[" << factionName << ' ' << localeNames[loc] << "]|h|r";
563 else
564 ss << faction.ID << " - " << factionName << ' ' << localeNames[loc];
565
566 ss << ' ' << rankName << " (" << target->GetReputationMgr().GetReputation(factionEntry) << ')';
567
571 ss << handler->GetTrinityString(LANG_FACTION_ATWAR);
580
581 handler->SendSysMessage(ss.view());
582 }
583
584 return true;
585 }
586
598 {
599 DeletedInfoList foundList;
600 if (!GetDeletedCharacterInfoList(foundList, needle.value_or(""sv)))
601 return false;
602
603 // if no characters have been found, output a warning
604 if (foundList.empty())
605 {
607 handler->SetSentErrorMessage(true);
608 return false;
609 }
610
611 HandleCharacterDeletedListHelper(foundList, handler);
612
613 return true;
614 }
615
629 static bool HandleCharacterDeletedRestoreCommand(ChatHandler* handler, std::string_view needle, Optional<std::string_view> const& newCharName, Optional<AccountIdentifier> const& newAccount)
630 {
631 DeletedInfoList foundList;
632 if (!GetDeletedCharacterInfoList(foundList, needle))
633 return false;
634
635 if (foundList.empty())
636 {
638 handler->SetSentErrorMessage(true);
639 return false;
640 }
641
643 HandleCharacterDeletedListHelper(foundList, handler);
644
645 if (!newCharName)
646 {
647 // Drop nonexisting account cases
648 for (DeletedInfoList::iterator itr = foundList.begin(); itr != foundList.end(); ++itr)
650 return true;
651 }
652
653 if (foundList.size() == 1)
654 {
655 std::string newName{ *newCharName };
656 DeletedInfo delInfo = foundList.front();
657
658 // update name
659 delInfo.name = newName;
660
661 // if new account provided update deleted info
662 if (newAccount)
663 {
664 delInfo.accountId = newAccount->GetID();
665 delInfo.accountName = newAccount->GetName();
666 }
667
668 HandleCharacterDeletedRestoreHelper(delInfo, handler);
669 return true;
670 }
671
673 handler->SetSentErrorMessage(true);
674 return false;
675 }
676
687 static bool HandleCharacterDeletedDeleteCommand(ChatHandler* handler, std::string_view needle)
688 {
689 DeletedInfoList foundList;
690 if (!GetDeletedCharacterInfoList(foundList, needle))
691 return false;
692
693 if (foundList.empty())
694 {
696 handler->SetSentErrorMessage(true);
697 return false;
698 }
699
701 HandleCharacterDeletedListHelper(foundList, handler);
702
703 // Call the appropriate function to delete them (current account for deleted characters is 0)
704 for (DeletedInfoList::const_iterator itr = foundList.begin(); itr != foundList.end(); ++itr)
705 Player::DeleteFromDB(itr->guid, 0, false, true);
706
707 return true;
708 }
709
722 {
723 int32 keepDays = static_cast<int32>(sWorld->getIntConfig(CONFIG_CHARDELETE_KEEP_DAYS));
724
725 if (days)
726 keepDays = static_cast<int32>(*days);
727 else if (keepDays <= 0) // config option value 0 -> disabled and can't be used
728 return false;
729
730 Player::DeleteOldCharacters(static_cast<uint32>(keepDays));
731
732 return true;
733 }
734
736 {
737 uint32 accountId;
738 if (Player* target = player.GetConnectedPlayer())
739 {
740 accountId = target->GetSession()->GetAccountId();
741 target->GetSession()->KickPlayer("HandleCharacterEraseCommand GM Command deleting character");
742 }
743 else
744 accountId = sCharacterCache->GetCharacterAccountIdByGuid(player);
745
746 std::string accountName;
747 AccountMgr::GetName(accountId, accountName);
748
749 Player::DeleteFromDB(player, accountId, true, true);
750 handler->PSendSysMessage(LANG_CHARACTER_DELETED, player.GetName().c_str(), player.GetGUID().ToString().c_str(), accountName.c_str(), accountId);
751
752 return true;
753 }
754
756 {
757 if (!player)
758 player = PlayerIdentifier::FromTargetOrSelf(handler);
759 if (!player)
760 return false;
761
762 uint8 oldlevel = static_cast<uint8>(player->IsConnected() ? player->GetConnectedPlayer()->GetLevel() : sCharacterCache->GetCharacterLevelByGuid(*player));
763
764 if (newlevel < 1)
765 newlevel = 1;
766
767 if (newlevel > static_cast<int16>(STRONG_MAX_LEVEL))
768 newlevel = static_cast<int16>(STRONG_MAX_LEVEL);
769
770 if (Player* target = player->GetConnectedPlayer())
771 {
772 target->GiveLevel(static_cast<uint8>(newlevel));
773 target->InitTalentForLevel();
774 target->SetXP(0);
775
776 if (handler->needReportToTarget(target))
777 {
778 if (oldlevel == newlevel)
779 ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_LEVEL_PROGRESS_RESET, handler->GetNameLink().c_str());
780 else if (oldlevel < static_cast<uint8>(newlevel))
781 ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_LEVEL_UP, handler->GetNameLink().c_str(), newlevel);
782 else // if (oldlevel > newlevel)
783 ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_LEVEL_DOWN, handler->GetNameLink().c_str(), newlevel);
784 }
785 }
786 else
787 {
788 // Update level and reset XP, everything else will be updated at login
790 stmt->setUInt8(0, static_cast<uint8>(newlevel));
791 stmt->setUInt64(1, player->GetGUID().GetCounter());
792 CharacterDatabase.Execute(stmt);
793 }
794
795 if (!handler->GetSession() || (handler->GetSession()->GetPlayer() != player->GetConnectedPlayer())) // including chr == NULL
796 handler->PSendSysMessage(LANG_YOU_CHANGE_LVL, handler->playerLink(*player).c_str(), newlevel);
797
798 return true;
799 }
800
802 {
803 if (!player)
804 player = PlayerIdentifier::FromTargetOrSelf(handler);
805 if (!player)
806 return false;
807
808 uint8 oldlevel = static_cast<uint8>(player->IsConnected() ? player->GetConnectedPlayer()->GetLevel() : sCharacterCache->GetCharacterLevelByGuid(*player));
809 int16 newlevel = static_cast<int16>(oldlevel) + level;
810
811 if (newlevel < 1)
812 newlevel = 1;
813
814 if (newlevel > static_cast<int16>(STRONG_MAX_LEVEL))
815 newlevel = static_cast<int16>(STRONG_MAX_LEVEL);
816
817 if (Player* target = player->GetConnectedPlayer())
818 {
819 target->GiveLevel(static_cast<uint8>(newlevel));
820 target->InitTalentForLevel();
821 target->SetXP(0);
822
823 if (handler->needReportToTarget(target))
824 {
825 if (oldlevel == newlevel)
826 ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_LEVEL_PROGRESS_RESET, handler->GetNameLink().c_str());
827 else if (oldlevel < static_cast<uint8>(newlevel))
828 ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_LEVEL_UP, handler->GetNameLink().c_str(), newlevel);
829 else // if (oldlevel > newlevel)
830 ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_LEVEL_DOWN, handler->GetNameLink().c_str(), newlevel);
831 }
832 }
833 else
834 {
835 // Update level and reset XP, everything else will be updated at login
837 stmt->setUInt8(0, static_cast<uint8>(newlevel));
838 stmt->setUInt64(1, player->GetGUID().GetCounter());
839 CharacterDatabase.Execute(stmt);
840 }
841
842 if (!handler->GetSession() || (handler->GetSession()->GetPlayer() != player->GetConnectedPlayer())) // including chr == NULL
843 handler->PSendSysMessage(LANG_YOU_CHANGE_LVL, handler->playerLink(*player).c_str(), newlevel);
844
845 return true;
846 }
847
849 {
850 std::string name;
851 if (!ValidatePDumpTarget(handler, name, characterName, characterGUID))
852 return false;
853
854 std::string dump;
855 switch (PlayerDumpWriter().WriteDumpToString(dump, player.GetGUID().GetCounter()))
856 {
857 case DUMP_SUCCESS:
858 break;
861 handler->SetSentErrorMessage(true);
862 return false;
863 case DUMP_FILE_OPEN_ERROR: // this error code should not happen
864 default:
866 handler->SetSentErrorMessage(true);
867 return false;
868 }
869
870 switch (PlayerDumpReader().LoadDumpFromString(dump, account, name, characterGUID.value_or(0)))
871 {
872 case DUMP_SUCCESS:
873 break;
875 handler->PSendSysMessage(LANG_ACCOUNT_CHARACTER_LIST_FULL, account.GetName().c_str(), account.GetID());
876 handler->SetSentErrorMessage(true);
877 return false;
878 case DUMP_FILE_OPEN_ERROR: // this error code should not happen
879 case DUMP_FILE_BROKEN: // this error code should not happen
880 default:
882 handler->SetSentErrorMessage(true);
883 return false;
884 }
885
886 // ToDo: use a new trinity_string for this commands
888
889 return true;
890 }
891
892 static bool HandlePDumpLoadCommand(ChatHandler* handler, std::string fileName, AccountIdentifier account, Optional<std::string_view> characterName, Optional<ObjectGuid::LowType> characterGUID)
893 {
894 std::string name;
895 if (!ValidatePDumpTarget(handler, name, characterName, characterGUID))
896 return false;
897
898 switch (PlayerDumpReader().LoadDumpFromFile(fileName, account, name, characterGUID.value_or(0)))
899 {
900 case DUMP_SUCCESS:
902 break;
904 handler->PSendSysMessage(LANG_FILE_OPEN_FAIL, fileName.c_str());
905 handler->SetSentErrorMessage(true);
906 return false;
907 case DUMP_FILE_BROKEN:
908 handler->PSendSysMessage(LANG_DUMP_BROKEN, fileName.c_str());
909 handler->SetSentErrorMessage(true);
910 return false;
912 handler->PSendSysMessage(LANG_ACCOUNT_CHARACTER_LIST_FULL, account.GetName().c_str(), account.GetID());
913 handler->SetSentErrorMessage(true);
914 return false;
915 default:
917 handler->SetSentErrorMessage(true);
918 return false;
919 }
920
921 return true;
922 }
923
924 static bool ValidatePDumpTarget(ChatHandler* handler, std::string& name, Optional<std::string_view> characterName, Optional<ObjectGuid::LowType> characterGUID)
925 {
926 if (characterName)
927 {
928 name.assign(*characterName);
929 // normalize the name if specified and check if it exists
930 if (!normalizePlayerName(name))
931 {
933 handler->SetSentErrorMessage(true);
934 return false;
935 }
936
937 if (ObjectMgr::CheckPlayerName(name, sWorld->GetDefaultDbcLocale(), true) != CHAR_NAME_SUCCESS)
938 {
940 handler->SetSentErrorMessage(true);
941 return false;
942 }
943 }
944
945 if (characterGUID)
946 {
947 if (sCharacterCache->GetCharacterCacheByGuid(ObjectGuid::Create<HighGuid::Player>(*characterGUID)))
948 {
949 handler->PSendSysMessage(LANG_CHARACTER_GUID_IN_USE, *characterGUID);
950 handler->SetSentErrorMessage(true);
951 return false;
952 }
953 }
954
955 return true;
956 }
957
958 static bool HandlePDumpWriteCommand(ChatHandler* handler, std::string fileName, PlayerIdentifier player)
959 {
960 switch (PlayerDumpWriter().WriteDumpToFile(fileName, player.GetGUID().GetCounter()))
961 {
962 case DUMP_SUCCESS:
964 break;
966 handler->PSendSysMessage(LANG_FILE_OPEN_FAIL, fileName.c_str());
967 handler->SetSentErrorMessage(true);
968 return false;
971 handler->SetSentErrorMessage(true);
972 return false;
973 default:
975 handler->SetSentErrorMessage(true);
976 return false;
977 }
978
979 return true;
980 }
981};
982
#define sCharacterCache
@ CHAR_SEL_CHECK_NAME
@ CHAR_UPD_LEVEL
@ CHAR_SEL_CHAR_DEL_INFO_BY_NAME
@ CHAR_SEL_CHAR_DEL_INFO
@ CHAR_DEL_CHAR_DECLINED_NAME
@ CHAR_UPD_NAME_BY_GUID
@ CHAR_SEL_CHAR_DEL_INFO_BY_GUID
@ CHAR_UPD_ACCOUNT_BY_GUID
@ CHAR_UPD_ADD_AT_LOGIN_FLAG
@ CHAR_UPD_RESTORE_DELETE_INFO
char const * localeNames[TOTAL_LOCALES]
Definition Common.cpp:20
LocaleConstant
Definition Common.h:51
DB2Storage< CharTitlesEntry > sCharTitlesStore("CharTitles.db2", &CharTitlesLoadInfo::Instance)
DB2Storage< FactionEntry > sFactionStore("Faction.db2", &FactionLoadInfo::Instance)
@ STRONG_MAX_LEVEL
Definition DBCEnums.h:49
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
uint8_t uint8
Definition Define.h:156
int16_t int16
Definition Define.h:151
int32_t int32
Definition Define.h:150
uint16_t uint16
Definition Define.h:155
uint32_t uint32
Definition Define.h:154
@ LANG_FACTION_PEACE_FORCED
Definition Language.h:369
@ LANG_CHARACTER_DELETED_SKIP_NAME
Definition Language.h:862
@ LANG_CHARACTER_DELETED_LIST_LINE_CHAT
Definition Language.h:863
@ LANG_RENAME_PLAYER
Definition Language.h:301
@ LANG_FACTION_ATWAR
Definition Language.h:368
@ LANG_CHARACTER_DELETED_ERR_RENAME
Definition Language.h:859
@ LANG_CHARACTER_DELETED_LIST_HEADER
Definition Language.h:853
@ LANG_KNOWN
Definition Language.h:63
@ LANG_DUMP_BROKEN
Definition Language.h:890
@ LANG_CHARACTER_DELETED_LIST_LINE_CONSOLE
Definition Language.h:854
@ LANG_FACTION_INVISIBLE_FORCED
Definition Language.h:371
@ LANG_COMMAND_EXPORT_DELETED_CHAR
Definition Language.h:906
@ LANG_FILE_OPEN_FAIL
Definition Language.h:888
@ LANG_CHANGEFACTION_NOT_ELIGIBLE_60
Definition Language.h:453
@ LANG_CHARACTER_GUID_IN_USE
Definition Language.h:893
@ LANG_CUSTOMIZE_PLAYER_GUID
Definition Language.h:401
@ LANG_ACCOUNT_CHARACTER_LIST_FULL
Definition Language.h:889
@ LANG_RENAME_PLAYER_WITH_NEW_NAME
Definition Language.h:131
@ LANG_YOU_CHANGE_LVL
Definition Language.h:163
@ LANG_TITLE_LIST_CHAT
Definition Language.h:404
@ LANG_CHARACTER_DELETED_RESTORE
Definition Language.h:857
@ LANG_CHARACTER_DELETED
Definition Language.h:846
@ LANG_COMMAND_EXPORT_SUCCESS
Definition Language.h:548
@ LANG_FACTION_HIDDEN
Definition Language.h:370
@ LANG_CONSOLE
Definition Language.h:1104
@ LANG_CUSTOMIZE_PLAYER
Definition Language.h:400
@ LANG_ACTIVE
Definition Language.h:67
@ LANG_PLAYER_NOT_FOUND
Definition Language.h:570
@ LANG_CHARACTER_DELETED_SKIP_FULL
Definition Language.h:861
@ LANG_CHARACTER_DELETED_LIST_EMPTY
Definition Language.h:856
@ LANG_CHARACTER_DELETED_LIST_BAR
Definition Language.h:855
@ LANG_BAD_VALUE
Definition Language.h:149
@ LANG_TITLE_LIST_CONSOLE
Definition Language.h:405
@ LANG_COMMAND_IMPORT_FAILED
Definition Language.h:547
@ LANG_YOURS_LEVEL_UP
Definition Language.h:641
@ LANG_YOURS_LEVEL_PROGRESS_RESET
Definition Language.h:643
@ LANG_RESERVED_NAME
Definition Language.h:208
@ LANG_COMMAND_EXPORT_FAILED
Definition Language.h:549
@ LANG_CHANGEFACTION_NOT_ELIGIBLE_10
Definition Language.h:452
@ LANG_FACTION_INACTIVE
Definition Language.h:372
@ LANG_RENAME_PLAYER_ALREADY_EXISTS
Definition Language.h:130
@ LANG_CHARACTER_DELETED_SKIP_ACCOUNT
Definition Language.h:860
@ LANG_RENAME_PLAYER_GUID
Definition Language.h:302
@ LANG_CHANGEACCOUNT_SUCCESS
Definition Language.h:960
@ LANG_FACTION_VISIBLE
Definition Language.h:367
@ LANG_YOURS_LEVEL_DOWN
Definition Language.h:642
@ LANG_INVALID_CHARACTER_NAME
Definition Language.h:891
@ LANG_COMMAND_IMPORT_SUCCESS
Definition Language.h:546
@ LANG_CHARACTER_DELETED_DELETE
Definition Language.h:858
#define sLog
Definition Log.h:156
bool normalizePlayerName(std::string &name)
#define sObjectMgr
Definition ObjectMgr.h:1873
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
@ DUMP_FILE_OPEN_ERROR
Definition PlayerDump.h:67
@ DUMP_CHARACTER_DELETED
Definition PlayerDump.h:70
@ DUMP_SUCCESS
Definition PlayerDump.h:66
@ DUMP_TOO_MANY_CHARS
Definition PlayerDump.h:68
@ DUMP_FILE_BROKEN
Definition PlayerDump.h:69
@ 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
std::map< RepListID, FactionState > FactionStateList
@ CLASS_DEATH_KNIGHT
@ GENDER_MALE
@ CHAR_NAME_SUCCESS
std::string TimeToTimestampStr(time_t t)
Definition Util.cpp:254
static uint32 GetCharactersCount(uint32 accountId)
static bool GetName(uint32 accountId, std::string &name)
std::string playerLink(std::string const &name) const
Definition Chat.cpp:603
WorldSession * GetSession()
Definition Chat.h:42
virtual LocaleConstant GetSessionDbcLocale() const
Definition Chat.cpp:593
virtual std::string GetNameLink() const
Definition Chat.cpp:56
bool HasLowerSecurity(Player *target, ObjectGuid guid, bool strong=false)
Definition Chat.cpp:61
static std::string PGetParseString(std::string_view fmt, Args &&... args) noexcept
Definition Chat.h:74
void SetSentErrorMessage(bool val)
Definition Chat.h:127
void PSendSysMessage(char const *fmt, Args &&... args)
Definition Chat.h:62
virtual void SendSysMessage(std::string_view str, bool escapeCharacters=false)
Definition Chat.cpp:111
virtual bool needReportToTarget(Player *chr) const
Definition Chat.cpp:587
virtual char const * GetTrinityString(uint32 entry) const
Definition Chat.cpp:46
constexpr bool HasFlag(T flag) const
Definition EnumFlag.h:106
Class used to access individual fields of database query result.
Definition Field.h:94
uint32 GetUInt32() const noexcept
Definition Field.cpp:57
std::string GetString() const noexcept
Definition Field.cpp:113
int64 GetInt64() const noexcept
Definition Field.cpp:78
LowType GetCounter() const
Definition ObjectGuid.h:336
std::string ToString() const
static ResponseCodes CheckPlayerName(std::string_view name, LocaleConstant locale, bool create=false)
UF::UpdateField< UF::PlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_PLAYER > m_playerData
Definition Player.h:3047
static void DeleteOldCharacters()
Definition Player.cpp:4172
Gender GetNativeGender() const override
Definition Player.h:1334
bool HasTitle(uint32 bitIndex) const
Definition Player.cpp:27006
static void DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRealmChars=true, bool deleteFinally=false)
Definition Player.cpp:3658
ReputationMgr & GetReputationMgr()
Definition Player.h:2422
void setUInt16(uint8 index, uint16 value)
void setString(uint8 index, std::string &&value)
void setUInt32(uint8 index, uint32 value)
void setUInt64(uint8 index, uint64 value)
void setUInt8(uint8 index, uint8 value)
std::string GetReputationRankName(FactionEntry const *factionEntry) const
FactionStateList const & GetStateList() const
int32 GetReputation(uint32 faction_id) const
Player session in the World.
Player * GetPlayer() const
static bool GetDeletedCharacterInfoList(DeletedInfoList &foundList, std::string_view searchString)
static bool HandlePDumpLoadCommand(ChatHandler *handler, std::string fileName, AccountIdentifier account, Optional< std::string_view > characterName, Optional< ObjectGuid::LowType > characterGUID)
static bool HandleCharacterDeletedDeleteCommand(ChatHandler *handler, std::string_view needle)
static bool HandleLevelUpCommand(ChatHandler *handler, Optional< PlayerIdentifier > player, int16 level)
static bool HandleCharacterDeletedRestoreCommand(ChatHandler *handler, std::string_view needle, Optional< std::string_view > const &newCharName, Optional< AccountIdentifier > const &newAccount)
static bool HandleCharacterLevelCommand(ChatHandler *handler, Optional< PlayerIdentifier > player, int16 newlevel)
static void HandleCharacterDeletedRestoreHelper(DeletedInfo const &delInfo, ChatHandler *handler)
static bool HandlePDumpCopyCommand(ChatHandler *handler, PlayerIdentifier player, AccountIdentifier account, Optional< std::string_view > characterName, Optional< ObjectGuid::LowType > characterGUID)
static bool HandleCharacterCustomizeCommand(ChatHandler *handler, Optional< PlayerIdentifier > player)
static bool HandleCharacterRenameCommand(ChatHandler *handler, Optional< PlayerIdentifier > player, Optional< std::string_view > newNameV)
static bool HandleCharacterChangeRaceCommand(ChatHandler *handler, Optional< PlayerIdentifier > player)
static bool HandleCharacterDeletedOldCommand(ChatHandler *, Optional< uint16 > days)
static bool HandleCharacterChangeAccountCommand(ChatHandler *handler, Optional< PlayerIdentifier > player, AccountIdentifier newAccount)
static bool ValidatePDumpTarget(ChatHandler *handler, std::string &name, Optional< std::string_view > characterName, Optional< ObjectGuid::LowType > characterGUID)
static bool HandleCharacterTitlesCommand(ChatHandler *handler, Optional< PlayerIdentifier > player)
static void HandleCharacterDeletedListHelper(DeletedInfoList const &foundList, ChatHandler *handler)
static bool HandlePDumpWriteCommand(ChatHandler *handler, std::string fileName, PlayerIdentifier player)
std::span< ChatCommandBuilder const > GetCommands() const override
static bool HandleCharacterReputationCommand(ChatHandler *handler, Optional< PlayerIdentifier > player)
static bool HandleCharacterEraseCommand(ChatHandler *handler, PlayerIdentifier player)
static bool HandleCharacterDeletedListCommand(ChatHandler *handler, Optional< std::string_view > const &needle)
static bool HandleCharacterChangeFactionCommand(ChatHandler *handler, Optional< PlayerIdentifier > player)
std::list< DeletedInfo > DeletedInfoList
void AddSC_character_commandscript()
#define sWorld
Definition World.h:919
@ CONFIG_CHARDELETE_KEEP_DAYS
Definition World.h:366
@ CONFIG_CHARACTERS_PER_REALM
Definition World.h:258
ChatCommandBuilder const [] ChatCommandTable
Definition ChatCommand.h:49
std::string ToString(Type &&val, Params &&... params)
std::string StringFormat(FormatString< Args... > fmt, Args &&... args) noexcept
Default TC string format function.
@ RBAC_PERM_COMMAND_CHARACTER_CHANGERACE
Definition RBAC.h:192
@ RBAC_PERM_COMMAND_PDUMP_COPY
Definition RBAC.h:750
@ RBAC_PERM_COMMAND_CHARACTER_DELETED_OLD
Definition RBAC.h:197
@ RBAC_PERM_COMMAND_LEVELUP
Definition RBAC.h:203
@ RBAC_PERM_COMMAND_CHARACTER_LEVEL
Definition RBAC.h:199
@ RBAC_PERM_COMMAND_CHARACTER_DELETED_DELETE
Definition RBAC.h:194
@ RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME
Definition RBAC.h:70
@ RBAC_PERM_COMMAND_CHARACTER_CHANGEFACTION
Definition RBAC.h:191
@ RBAC_PERM_COMMAND_CHARACTER_TITLES
Definition RBAC.h:202
@ RBAC_PERM_COMMAND_CHARACTER_CUSTOMIZE
Definition RBAC.h:190
@ RBAC_PERM_COMMAND_CHARACTER_CHANGEACCOUNT
Definition RBAC.h:572
@ RBAC_PERM_COMMAND_CHARACTER_RENAME
Definition RBAC.h:200
@ RBAC_PERM_COMMAND_CHARACTER_ERASE
Definition RBAC.h:198
@ RBAC_PERM_COMMAND_PDUMP_LOAD
Definition RBAC.h:205
@ RBAC_PERM_COMMAND_CHARACTER_REPUTATION
Definition RBAC.h:201
@ RBAC_PERM_COMMAND_CHARACTER_DELETED_LIST
Definition RBAC.h:195
@ RBAC_PERM_COMMAND_CHARACTER_DELETED_RESTORE
Definition RBAC.h:196
@ RBAC_PERM_COMMAND_PDUMP_WRITE
Definition RBAC.h:206
LocalizedString Name1
LocalizedString Name
LocalizedString Name
EnumFlag< ReputationFlags > Flags
static Optional< PlayerIdentifier > FromTarget(ChatHandler *handler)
std::string const & GetName() const
static Optional< PlayerIdentifier > FromTargetOrSelf(ChatHandler *handler)
std::string name
the character name
std::string accountName
the account name
time_t deleteDate
the date at which the character has been deleted
ObjectGuid guid
the GUID from the character