diff options
author | Treeston <treeston.mmoc@gmail.com> | 2020-09-07 15:38:23 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2022-02-05 14:44:01 +0100 |
commit | 1e9d60b4ac085bbc58ba7217a010d9272510cc9e (patch) | |
tree | 0c1eb540b6de57df74c45dc01f54aea7c2de39e3 | |
parent | cb2a2843597af344db54a2ed34885e204fed5c0f (diff) |
Scripts/Commands: .character command conversion
(cherry picked from commit 00dd337b5d2c91907424828d7eebe3191931b036)
-rw-r--r-- | src/server/database/Database/PreparedStatement.cpp | 6 | ||||
-rw-r--r-- | src/server/database/Database/PreparedStatement.h | 1 | ||||
-rw-r--r-- | src/server/game/Accounts/AccountMgr.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Accounts/AccountMgr.h | 2 | ||||
-rw-r--r-- | src/server/game/Chat/ChatCommands/ChatCommandTags.cpp | 62 | ||||
-rw-r--r-- | src/server/game/Chat/ChatCommands/ChatCommandTags.h | 21 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_character.cpp | 589 |
7 files changed, 261 insertions, 424 deletions
diff --git a/src/server/database/Database/PreparedStatement.cpp b/src/server/database/Database/PreparedStatement.cpp index c387d7d6ad8..8c57654b5b2 100644 --- a/src/server/database/Database/PreparedStatement.cpp +++ b/src/server/database/Database/PreparedStatement.cpp @@ -101,6 +101,12 @@ void PreparedStatementBase::setString(const uint8 index, const std::string& valu statement_data[index].data = value; } +void PreparedStatementBase::setStringView(const uint8 index, const std::string_view value) +{ + ASSERT(index < statement_data.size()); + statement_data[index].data.emplace<std::string>(value); +} + void PreparedStatementBase::setBinary(const uint8 index, const std::vector<uint8>& value) { ASSERT(index < statement_data.size()); diff --git a/src/server/database/Database/PreparedStatement.h b/src/server/database/Database/PreparedStatement.h index b920289623e..af4db9c310e 100644 --- a/src/server/database/Database/PreparedStatement.h +++ b/src/server/database/Database/PreparedStatement.h @@ -76,6 +76,7 @@ class TC_DATABASE_API PreparedStatementBase void setFloat(const uint8 index, const float value); void setDouble(const uint8 index, const double value); void setString(const uint8 index, const std::string& value); + void setStringView(const uint8 index, const std::string_view value); void setBinary(const uint8 index, const std::vector<uint8>& value); template <size_t Size> void setBinary(const uint8 index, std::array<uint8, Size> const& value) diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp index ce517bb470b..cbe4c6e430c 100644 --- a/src/server/game/Accounts/AccountMgr.cpp +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -284,10 +284,10 @@ AccountOpResult AccountMgr::ChangeRegEmail(uint32 accountId, std::string newEmai return AccountOpResult::AOR_OK; } -uint32 AccountMgr::GetId(std::string const& username) +uint32 AccountMgr::GetId(std::string_view username) { LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ID_BY_USERNAME); - stmt->setString(0, username); + stmt->setStringView(0, username); PreparedQueryResult result = LoginDatabase.Query(stmt); return (result) ? (*result)[0].GetUInt32() : 0; diff --git a/src/server/game/Accounts/AccountMgr.h b/src/server/game/Accounts/AccountMgr.h index 41a1948fdd4..9e28396df06 100644 --- a/src/server/game/Accounts/AccountMgr.h +++ b/src/server/game/Accounts/AccountMgr.h @@ -67,7 +67,7 @@ class TC_GAME_API AccountMgr static bool CheckPassword(uint32 accountId, std::string password); static bool CheckEmail(uint32 accountId, std::string newEmail); - static uint32 GetId(std::string const& username); + static uint32 GetId(std::string_view username); static uint32 GetSecurity(uint32 accountId, int32 realmId); [[nodiscard]] static QueryCallback GetSecurityAsync(uint32 accountId, int32 realmId, std::function<void(uint32)> callback); static bool GetName(uint32 accountId, std::string& name); diff --git a/src/server/game/Chat/ChatCommands/ChatCommandTags.cpp b/src/server/game/Chat/ChatCommands/ChatCommandTags.cpp index 0f11f1cd66f..8c5917e086d 100644 --- a/src/server/game/Chat/ChatCommands/ChatCommandTags.cpp +++ b/src/server/game/Chat/ChatCommands/ChatCommandTags.cpp @@ -17,6 +17,7 @@ #include "ChatCommandTags.h" +#include "AccountMgr.h" #include "CharacterCache.h" #include "Chat.h" #include "ChatCommandArgs.h" @@ -55,22 +56,65 @@ Optional<std::string_view> Trinity::ChatCommands::QuotedString::TryConsume(std:: return std::nullopt; } -Optional<std::string_view> Trinity::ChatCommands::PlayerIdentifier::TryConsume(std::string_view args) +Optional<std::string_view> Trinity::ChatCommands::AccountIdentifier::TryConsume(std::string_view args) { - Variant<Hyperlink<player>, std::string_view> name; - Optional<std::string_view> next = Trinity::Impl::ChatCommands::ArgInfo<decltype(name)>::TryConsume(name, args); + std::string_view text; + Optional<std::string_view> next = Trinity::Impl::ChatCommands::ArgInfo<std::string_view>::TryConsume(text, args); if (!next) return std::nullopt; - _name = static_cast<std::string_view>(name); - normalizePlayerName(_name); + // first try parsing as account name + _name.assign(text); + if (!Utf8ToUpperOnlyLatin(_name)) + return std::nullopt; + _id = AccountMgr::GetId(_name); + if (_id) // account with name exists, we are done + return next; + + // try parsing as account id instead + Optional<uint32> id = Trinity::StringTo<uint32>(text, 10); + if (!id) + return std::nullopt; + _id = *id; + + if (AccountMgr::GetName(_id, _name)) + return next; + else + return std::nullopt; +} - if ((_player = ObjectAccessor::FindPlayerByName(_name))) - _guid = _player->GetGUID(); - else if (!(_guid = sCharacterCache->GetCharacterGuidByName(_name))) +Optional<std::string_view> Trinity::ChatCommands::PlayerIdentifier::TryConsume(std::string_view args) +{ + Variant<Hyperlink<player>, ObjectGuid::LowType, std::string_view> val; + Optional<std::string_view> next = Trinity::Impl::ChatCommands::ArgInfo<decltype(val)>::TryConsume(val, args); + if (!next) return std::nullopt; - return next; + if (val.holds_alternative<ObjectGuid::LowType>()) + { + _guid = ObjectGuid::Create<HighGuid::Player>(val.get<ObjectGuid::LowType>()); + if ((_player = ObjectAccessor::FindPlayerByLowGUID(_guid.GetCounter()))) + _name = _player->GetName(); + else if (!sCharacterCache->GetCharacterNameByGuid(_guid, _name)) + return std::nullopt; + return next; + } + else + { + if (val.holds_alternative<Hyperlink<player>>()) + _name.assign(static_cast<std::string_view>(val.get<Hyperlink<player>>())); + else + _name.assign(val.get<std::string_view>()); + + if (!normalizePlayerName(_name)) + return std::nullopt; + + if ((_player = ObjectAccessor::FindPlayerByName(_name))) + _guid = _player->GetGUID(); + else if (!(_guid = sCharacterCache->GetCharacterGuidByName(_name))) + return std::nullopt; + return next; + } } Trinity::ChatCommands::PlayerIdentifier::PlayerIdentifier(Player& player) diff --git a/src/server/game/Chat/ChatCommands/ChatCommandTags.h b/src/server/game/Chat/ChatCommands/ChatCommandTags.h index 19d3258753c..321bdd3219b 100644 --- a/src/server/game/Chat/ChatCommands/ChatCommandTags.h +++ b/src/server/game/Chat/ChatCommands/ChatCommandTags.h @@ -120,6 +120,24 @@ namespace Trinity::ChatCommands TC_GAME_API Optional<std::string_view> TryConsume(std::string_view args); }; + struct TC_GAME_API AccountIdentifier : Trinity::Impl::ChatCommands::ContainerTag + { + using value_type = uint32; + + operator uint32() const { return _id; } + operator std::string const& () const { return _name; } + operator std::string_view() const { return { _name }; } + + uint32 GetID() const { return _id; } + std::string const& GetName() const { return _name; } + + Optional<std::string_view> TryConsume(std::string_view args); + + private: + uint32 _id; + std::string _name; + }; + struct TC_GAME_API PlayerIdentifier : Trinity::Impl::ChatCommands::ContainerTag { using value_type = Player*; @@ -137,7 +155,8 @@ namespace Trinity::ChatCommands std::string const& GetName() { return _name; } ObjectGuid GetGUID() const { return _guid; } - Player* GetPlayer() const { return _player; } + bool IsConnected() const { return (_player != nullptr); } + Player* GetConnectedPlayer() const { return _player; } Optional<std::string_view> TryConsume(std::string_view args); diff --git a/src/server/scripts/Commands/cs_character.cpp b/src/server/scripts/Commands/cs_character.cpp index 2add325bfa2..a05b670b9e1 100644 --- a/src/server/scripts/Commands/cs_character.cpp +++ b/src/server/scripts/Commands/cs_character.cpp @@ -38,6 +38,7 @@ EndScriptData */ #include "WorldSession.h" #include <sstream> +using namespace Trinity::ChatCommands; class character_commandscript : public CommandScript { public: @@ -66,7 +67,7 @@ public: { "changeaccount", rbac::RBAC_PERM_COMMAND_CHARACTER_CHANGEACCOUNT, true, &HandleCharacterChangeAccountCommand, "", }, { "deleted", rbac::RBAC_PERM_COMMAND_CHARACTER_DELETED, true, nullptr, "", characterDeletedCommandTable }, { "erase", rbac::RBAC_PERM_COMMAND_CHARACTER_ERASE, true, &HandleCharacterEraseCommand, "", }, - { "level", rbac::RBAC_PERM_COMMAND_CHARACTER_LEVEL, true, &HandleCharacterLevelCommand, "", }, + { "level", rbac::RBAC_PERM_COMMAND_CHARACTER_LEVEL, true, &HandleLevelUpCommand, "", }, { "rename", rbac::RBAC_PERM_COMMAND_CHARACTER_RENAME, true, &HandleCharacterRenameCommand, "", }, { "reputation", rbac::RBAC_PERM_COMMAND_CHARACTER_REPUTATION, true, &HandleCharacterReputationCommand, "", }, { "titles", rbac::RBAC_PERM_COMMAND_CHARACTER_TITLES, true, &HandleCharacterTitlesCommand, "", }, @@ -100,7 +101,7 @@ public: * @param searchString the search string which either contains a player GUID or a part fo the character-name * @return returns false if there was a problem while selecting the characters (e.g. player name not normalizeable) */ - static bool GetDeletedCharacterInfoList(DeletedInfoList& foundList, std::string searchString) + static bool GetDeletedCharacterInfoList(DeletedInfoList& foundList, std::string& searchString) { PreparedQueryResult result; CharacterDatabasePreparedStatement* stmt; @@ -231,45 +232,21 @@ public: sCharacterCache->UpdateCharacterInfoDeleted(delInfo.guid, false, &delInfo.name); } - static void HandleCharacterLevel(Player* player, ObjectGuid playerGuid, uint32 oldLevel, uint32 newLevel, ChatHandler* handler) + static bool HandleCharacterTitlesCommand(ChatHandler* handler, Optional<PlayerIdentifier> player) { - if (player) + if (!player) + player = PlayerIdentifier::FromTargetOrSelf(handler); + if (!player || !player->IsConnected()) { - player->GiveLevel(newLevel); - player->InitTalentForLevel(); - player->SetXP(0); - - if (handler->needReportToTarget(player)) - { - if (oldLevel == newLevel) - ChatHandler(player->GetSession()).PSendSysMessage(LANG_YOURS_LEVEL_PROGRESS_RESET, handler->GetNameLink().c_str()); - else if (oldLevel < newLevel) - ChatHandler(player->GetSession()).PSendSysMessage(LANG_YOURS_LEVEL_UP, handler->GetNameLink().c_str(), newLevel); - else // if (oldlevel > newlevel) - ChatHandler(player->GetSession()).PSendSysMessage(LANG_YOURS_LEVEL_DOWN, handler->GetNameLink().c_str(), newLevel); - } - } - else - { - // Update level and reset XP, everything else will be updated at login - CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_LEVEL); - stmt->setUInt8(0, uint8(newLevel)); - stmt->setUInt64(1, playerGuid.GetCounter()); - CharacterDatabase.Execute(stmt); - } - } - - static bool HandleCharacterTitlesCommand(ChatHandler* handler, char const* args) - { - if (!*args) + handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); + handler->SetSentErrorMessage(true); return false; + } - Player* target; - if (!handler->extractPlayerTarget((char*)args, &target)) - return false; + Player const* target = player->GetConnectedPlayer(); LocaleConstant loc = handler->GetSessionDbcLocale(); - char const* targetName = target->GetName().c_str(); + std::string const& targetName = player->GetName(); char const* knownStr = handler->GetTrinityString(LANG_KNOWN); // Search in CharTitles.dbc @@ -279,21 +256,23 @@ public: if (titleInfo && target->HasTitle(titleInfo)) { - std::string name = target->GetNativeGender() == GENDER_MALE ? titleInfo->Name[loc] : titleInfo->Name1[loc]; - if (name.empty()) + char const* name = target->GetNativeGender() == GENDER_MALE ? titleInfo->Name[loc] : titleInfo->Name1[loc]; + if (!*name) + name = (target->GetNativeGender() == GENDER_MALE ? titleInfo->Name[sWorld->GetDefaultDbcLocale()] : titleInfo->Name1[sWorld->GetDefaultDbcLocale()]); + if (!*name) continue; - char const* activeStr = *target->m_playerData->PlayerTitle == titleInfo->MaskID - ? handler->GetTrinityString(LANG_ACTIVE) - : ""; + char const* activeStr = ""; + if (*target->m_playerData->PlayerTitle == titleInfo->MaskID) + activeStr = handler->GetTrinityString(LANG_ACTIVE); - std::string titleNameStr = Trinity::StringFormat(name.c_str(), targetName); + std::string titleName = Trinity::StringFormat(name, targetName.c_str()); // send title in "id (idx:idx) - [namedlink locale]" format if (handler->GetSession()) - handler->PSendSysMessage(LANG_TITLE_LIST_CHAT, id, titleInfo->MaskID, id, titleNameStr.c_str(), localeNames[loc], knownStr, activeStr); + handler->PSendSysMessage(LANG_TITLE_LIST_CHAT, id, titleInfo->MaskID, id, titleName.c_str(), localeNames[loc], knownStr, activeStr); else - handler->PSendSysMessage(LANG_TITLE_LIST_CONSOLE, id, titleInfo->MaskID, name.c_str(), localeNames[loc], knownStr, activeStr); + handler->PSendSysMessage(LANG_TITLE_LIST_CONSOLE, id, titleInfo->MaskID, name, localeNames[loc], knownStr, activeStr); } } @@ -301,38 +280,22 @@ public: } //rename characters - static bool HandleCharacterRenameCommand(ChatHandler* handler, char const* args) + static bool HandleCharacterRenameCommand(ChatHandler* handler, Optional<PlayerIdentifier> player, Optional<std::string_view> newNameV) { - Player* target; - ObjectGuid targetGuid; - std::string targetName; - if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) + if (!player && newNameV) return false; - char const* newNameStr = strtok(nullptr, " "); - - if (newNameStr) - { - std::string playerOldName; - std::string newName = newNameStr; - - if (target) - { - // check online security - if (handler->HasLowerSecurity(target, ObjectGuid::Empty)) - return false; - - playerOldName = target->GetName(); - } - else - { - // check offline security - if (handler->HasLowerSecurity(nullptr, targetGuid)) - return false; + if (!player) + player = PlayerIdentifier::FromTarget(handler); + if (!player) + return false; - sCharacterCache->GetCharacterNameByGuid(targetGuid, playerOldName); - } + if (handler->HasLowerSecurity(nullptr, player->GetGUID())) + return false; + if (newNameV) + { + std::string newName{ *newNameV }; if (!normalizePlayerName(newName)) { handler->SendSysMessage(LANG_BAD_VALUE); @@ -340,7 +303,7 @@ public: return false; } - if (ObjectMgr::CheckPlayerName(newName, target ? target->GetSession()->GetSessionDbcLocale() : sWorld->GetDefaultDbcLocale(), true) != CHAR_NAME_SUCCESS) + if (ObjectMgr::CheckPlayerName(newName, player->IsConnected() ? player->GetConnectedPlayer()->GetSession()->GetSessionDbcLocale() : sWorld->GetDefaultDbcLocale(), true) != CHAR_NAME_SUCCESS) { handler->SendSysMessage(LANG_BAD_VALUE); handler->SetSentErrorMessage(true); @@ -369,10 +332,10 @@ public: // Remove declined name from db stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_DECLINED_NAME); - stmt->setUInt64(0, targetGuid.GetCounter()); + stmt->setUInt64(0, player->GetGUID().GetCounter()); CharacterDatabase.Execute(stmt); - if (target) + if (Player* target = player->GetConnectedPlayer()) { target->SetName(newName); @@ -383,45 +346,40 @@ public: { stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_NAME_BY_GUID); stmt->setString(0, newName); - stmt->setUInt64(1, targetGuid.GetCounter()); + stmt->setUInt64(1, player->GetGUID().GetCounter()); CharacterDatabase.Execute(stmt); } - sCharacterCache->UpdateCharacterData(targetGuid, newName); + sCharacterCache->UpdateCharacterData(*player, newName); - handler->PSendSysMessage(LANG_RENAME_PLAYER_WITH_NEW_NAME, playerOldName.c_str(), newName.c_str()); + handler->PSendSysMessage(LANG_RENAME_PLAYER_WITH_NEW_NAME, player->GetName().c_str(), newName.c_str()); if (WorldSession* session = handler->GetSession()) { if (Player* player = session->GetPlayer()) - sLog->outCommand(session->GetAccountId(), "GM %s (Account: %u) forced rename %s to player %s (Account: %u)", player->GetName().c_str(), session->GetAccountId(), newName.c_str(), playerOldName.c_str(), sCharacterCache->GetCharacterAccountIdByGuid(targetGuid)); + sLog->outCommand(session->GetAccountId(), "GM %s (Account: %u) forced rename %s to player %s (Account: %u)", player->GetName().c_str(), session->GetAccountId(), newName.c_str(), player->GetName().c_str(), sCharacterCache->GetCharacterAccountIdByGuid(player->GetGUID())); } else - sLog->outCommand(0, "CONSOLE forced rename '%s' to '%s' (%s)", playerOldName.c_str(), newName.c_str(), targetGuid.ToString().c_str()); + sLog->outCommand(0, "CONSOLE forced rename '%s' to '%s' (%s)", player->GetName().c_str(), newName.c_str(), player->GetGUID().ToString().c_str()); } else { - if (target) + if (Player* target = player->GetConnectedPlayer()) { - // check online security - if (handler->HasLowerSecurity(target, ObjectGuid::Empty)) - return false; - handler->PSendSysMessage(LANG_RENAME_PLAYER, handler->GetNameLink(target).c_str()); target->SetAtLoginFlag(AT_LOGIN_RENAME); } else { // check offline security - if (handler->HasLowerSecurity(nullptr, targetGuid)) + if (handler->HasLowerSecurity(nullptr, player->GetGUID())) return false; - std::string oldNameLink = handler->playerLink(targetName); - handler->PSendSysMessage(LANG_RENAME_PLAYER_GUID, oldNameLink.c_str(), targetGuid.ToString().c_str()); + handler->PSendSysMessage(LANG_RENAME_PLAYER_GUID, handler->playerLink(player->GetName()).c_str(), player->GetGUID().ToString().c_str()); CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); stmt->setUInt16(0, uint16(AT_LOGIN_RENAME)); - stmt->setUInt64(1, targetGuid.GetCounter()); + stmt->setUInt64(1, player->GetGUID().GetCounter()); CharacterDatabase.Execute(stmt); } } @@ -429,145 +387,87 @@ public: return true; } - static bool HandleCharacterLevelCommand(ChatHandler* handler, char const* args) - { - char* nameStr; - char* levelStr; - handler->extractOptFirstArg((char*)args, &nameStr, &levelStr); - if (!levelStr) - return false; - - // exception opt second arg: .character level $name - if (isalpha(levelStr[0])) - { - nameStr = levelStr; - levelStr = nullptr; // current level will used - } - - Player* target; - ObjectGuid targetGuid; - std::string targetName; - if (!handler->extractPlayerTarget(nameStr, &target, &targetGuid, &targetName)) - return false; - - int32 oldlevel = target ? target->GetLevel() : sCharacterCache->GetCharacterLevelByGuid(targetGuid); - int32 newlevel = levelStr ? atoi(levelStr) : oldlevel; - - if (newlevel < 1) - return false; // invalid level - - if (newlevel > STRONG_MAX_LEVEL) // hardcoded maximum level - newlevel = STRONG_MAX_LEVEL; - - HandleCharacterLevel(target, targetGuid, oldlevel, newlevel, handler); - if (!handler->GetSession() || handler->GetSession()->GetPlayer() != target) // including player == NULL - { - std::string nameLink = handler->playerLink(targetName); - handler->PSendSysMessage(LANG_YOU_CHANGE_LVL, nameLink.c_str(), newlevel); - } - - return true; - } - // customize characters - static bool HandleCharacterCustomizeCommand(ChatHandler* handler, char const* args) + static bool HandleCharacterCustomizeCommand(ChatHandler* handler, Optional<PlayerIdentifier> player) { - Player* target; - ObjectGuid targetGuid; - std::string targetName; - if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) + if (!player) + player = PlayerIdentifier::FromTarget(handler); + if (!player) return false; - CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); - stmt->setUInt16(0, uint16(AT_LOGIN_CUSTOMIZE)); - if (target) + if (Player* target = player->GetConnectedPlayer()) { handler->PSendSysMessage(LANG_CUSTOMIZE_PLAYER, handler->GetNameLink(target).c_str()); target->SetAtLoginFlag(AT_LOGIN_CUSTOMIZE); - stmt->setUInt64(1, target->GetGUID().GetCounter()); } else { - std::string oldNameLink = handler->playerLink(targetName); - stmt->setUInt64(1, targetGuid.GetCounter()); - handler->PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, oldNameLink.c_str(), targetGuid.ToString().c_str()); + handler->PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, handler->playerLink(player->GetName()).c_str(), player->GetGUID().GetCounter()); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); + stmt->setUInt16(0, static_cast<uint16>(AT_LOGIN_CUSTOMIZE)); + stmt->setUInt64(1, player->GetGUID().GetCounter()); + CharacterDatabase.Execute(stmt); } - CharacterDatabase.Execute(stmt); return true; } - static bool HandleCharacterChangeFactionCommand(ChatHandler* handler, char const* args) + static bool HandleCharacterChangeFactionCommand(ChatHandler* handler, Optional<PlayerIdentifier> player) { - Player* target; - ObjectGuid targetGuid; - std::string targetName; - - if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) + if (!player) + player = PlayerIdentifier::FromTarget(handler); + if (!player) return false; - CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); - stmt->setUInt16(0, uint16(AT_LOGIN_CHANGE_FACTION)); - if (target) + if (Player* target = player->GetConnectedPlayer()) { handler->PSendSysMessage(LANG_CUSTOMIZE_PLAYER, handler->GetNameLink(target).c_str()); target->SetAtLoginFlag(AT_LOGIN_CHANGE_FACTION); - stmt->setUInt64(1, target->GetGUID().GetCounter()); } else { - std::string oldNameLink = handler->playerLink(targetName); - handler->PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, oldNameLink.c_str(), targetGuid.ToString().c_str()); - stmt->setUInt64(1, targetGuid.GetCounter()); + handler->PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, handler->playerLink(player->GetName()).c_str(), player->GetGUID().GetCounter()); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); + stmt->setUInt16(0, uint16(AT_LOGIN_CHANGE_FACTION)); + stmt->setUInt64(1, player->GetGUID().GetCounter()); + CharacterDatabase.Execute(stmt); } - CharacterDatabase.Execute(stmt); return true; } - static bool HandleCharacterChangeRaceCommand(ChatHandler* handler, char const* args) + static bool HandleCharacterChangeRaceCommand(ChatHandler* handler, Optional<PlayerIdentifier> player) { - Player* target; - ObjectGuid targetGuid; - std::string targetName; - if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) + if (!player) + player = PlayerIdentifier::FromTarget(handler); + if (!player) return false; - CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); - stmt->setUInt16(0, uint16(AT_LOGIN_CHANGE_RACE)); - if (target) + if (Player* target = player->GetConnectedPlayer()) { - /// @todo add text into database handler->PSendSysMessage(LANG_CUSTOMIZE_PLAYER, handler->GetNameLink(target).c_str()); target->SetAtLoginFlag(AT_LOGIN_CHANGE_RACE); - stmt->setUInt64(1, target->GetGUID().GetCounter()); } else { - std::string oldNameLink = handler->playerLink(targetName); - /// @todo add text into database - handler->PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, oldNameLink.c_str(), targetGuid.ToString().c_str()); - stmt->setUInt64(1, targetGuid.GetCounter()); + handler->PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, handler->playerLink(player->GetName()).c_str(), player->GetGUID().GetCounter()); + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); + stmt->setUInt16(0, uint16(AT_LOGIN_CHANGE_RACE)); + stmt->setUInt64(1, player->GetGUID().GetCounter()); + CharacterDatabase.Execute(stmt); } - CharacterDatabase.Execute(stmt); return true; } - static bool HandleCharacterChangeAccountCommand(ChatHandler* handler, char const* args) + static bool HandleCharacterChangeAccountCommand(ChatHandler* handler, Optional<PlayerIdentifier> player, AccountIdentifier newAccount) { - char* playerNameStr; - char* accountNameStr; - handler->extractOptFirstArg(const_cast<char*>(args), &playerNameStr, &accountNameStr); - if (!accountNameStr) + if (!player) + player = PlayerIdentifier::FromTarget(handler); + if (!player) return false; - ObjectGuid targetGuid; - std::string targetName; - if (!handler->extractPlayerTarget(playerNameStr, nullptr, &targetGuid, &targetName)) - return false; - - CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(targetGuid); + CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(player->GetGUID()); if (!characterInfo) { handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); @@ -576,54 +476,33 @@ public: } uint32 oldAccountId = characterInfo->AccountId; - uint32 newAccountId = oldAccountId; - - std::string accountName(accountNameStr); - if (!Utf8ToUpperOnlyLatin(accountName)) - { - handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); - handler->SetSentErrorMessage(true); - return false; - } - - LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME); - stmt->setString(0, accountName); - if (PreparedQueryResult result = LoginDatabase.Query(stmt)) - newAccountId = (*result)[0].GetUInt32(); - else - { - handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); - handler->SetSentErrorMessage(true); - return false; - } - // nothing to do :) - if (newAccountId == oldAccountId) + if (newAccount.GetID() == oldAccountId) return true; - if (uint32 charCount = AccountMgr::GetCharactersCount(newAccountId)) + if (uint32 charCount = AccountMgr::GetCharactersCount(newAccount.GetID())) { if (charCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM)) { - handler->PSendSysMessage(LANG_ACCOUNT_CHARACTER_LIST_FULL, accountName.c_str(), newAccountId); + handler->PSendSysMessage(LANG_ACCOUNT_CHARACTER_LIST_FULL, newAccount.GetName().c_str(), newAccount.GetID()); handler->SetSentErrorMessage(true); return false; } } CharacterDatabasePreparedStatement* charStmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ACCOUNT_BY_GUID); - charStmt->setUInt32(0, newAccountId); - charStmt->setUInt32(1, targetGuid.GetCounter()); + charStmt->setUInt32(0, newAccount.GetID()); + charStmt->setUInt64(1, player->GetGUID().GetCounter()); CharacterDatabase.DirectExecute(charStmt); sWorld->UpdateRealmCharCount(oldAccountId); - sWorld->UpdateRealmCharCount(newAccountId); + sWorld->UpdateRealmCharCount(newAccount.GetID()); - sCharacterCache->UpdateCharacterAccountId(targetGuid, newAccountId); + sCharacterCache->UpdateCharacterAccountId(*player, newAccount.GetID()); - handler->PSendSysMessage(LANG_CHANGEACCOUNT_SUCCESS, targetName.c_str(), accountName.c_str()); + handler->PSendSysMessage(LANG_CHANGEACCOUNT_SUCCESS, player->GetName().c_str(), newAccount.GetName().c_str()); - std::string logString = Trinity::StringFormat("changed ownership of player %s (%s) from account %u to account %u", targetName.c_str(), targetGuid.ToString().c_str(), oldAccountId, newAccountId); + std::string logString = Trinity::StringFormat("changed ownership of player %s (%s) from account %u to account %u", player->GetName().c_str(), player->GetGUID().ToString().c_str(), oldAccountId, newAccount.GetID()); if (WorldSession* session = handler->GetSession()) { if (Player* player = session->GetPlayer()) @@ -634,12 +513,18 @@ public: return true; } - static bool HandleCharacterReputationCommand(ChatHandler* handler, char const* args) + static bool HandleCharacterReputationCommand(ChatHandler* handler, Optional<PlayerIdentifier> player) { - Player* target; - if (!handler->extractPlayerTarget((char*)args, &target)) + if (!player) + player = PlayerIdentifier::FromTargetOrSelf(handler); + if (!player || !player->IsConnected()) + { + handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); + handler->SetSentErrorMessage(true); return false; + } + Player const* target = player->GetConnectedPlayer(); LocaleConstant loc = handler->GetSessionDbcLocale(); FactionStateList const& targetFSL = target->GetReputationMgr().GetStateList(); @@ -686,16 +571,20 @@ public: * * @param args the search string which either contains a player GUID or a part fo the character-name */ - static bool HandleCharacterDeletedListCommand(ChatHandler* handler, char const* args) + static bool HandleCharacterDeletedListCommand(ChatHandler* handler, Optional<std::string_view> needleStr) { + std::string needle; + if (needleStr) + needle.assign(*needleStr); DeletedInfoList foundList; - if (!GetDeletedCharacterInfoList(foundList, args)) + if (!GetDeletedCharacterInfoList(foundList, needle)) return false; // if no characters have been found, output a warning if (foundList.empty()) { handler->SendSysMessage(LANG_CHARACTER_DELETED_LIST_EMPTY); + handler->SetSentErrorMessage(true); return false; } @@ -715,59 +604,52 @@ public: * * @param args the search string which either contains a player GUID or a part of the character-name */ - static bool HandleCharacterDeletedRestoreCommand(ChatHandler* handler, char const* args) + static bool HandleCharacterDeletedRestoreCommand(ChatHandler* handler, std::string needle, Optional<std::string_view> newCharName, Optional<AccountIdentifier> newAccount) { - // It is required to submit at least one argument - if (!*args) - return false; - - std::string searchString; - std::string newCharName; - uint32 newAccount = 0; - - // GCC by some strange reason fail build code without temporary variable - std::istringstream params(args); - params >> searchString >> newCharName >> newAccount; - DeletedInfoList foundList; - if (!GetDeletedCharacterInfoList(foundList, searchString)) + if (!GetDeletedCharacterInfoList(foundList, needle)) return false; if (foundList.empty()) { handler->SendSysMessage(LANG_CHARACTER_DELETED_LIST_EMPTY); + handler->SetSentErrorMessage(true); return false; } handler->SendSysMessage(LANG_CHARACTER_DELETED_RESTORE); HandleCharacterDeletedListHelper(foundList, handler); - if (newCharName.empty()) + if (!newCharName) { // Drop nonexisting account cases for (DeletedInfoList::iterator itr = foundList.begin(); itr != foundList.end(); ++itr) HandleCharacterDeletedRestoreHelper(*itr, handler); + return true; } - else if (foundList.size() == 1 && normalizePlayerName(newCharName)) + + if (foundList.size() == 1) { + std::string newName{ *newCharName }; DeletedInfo delInfo = foundList.front(); // update name - delInfo.name = newCharName; + delInfo.name = newName; // if new account provided update deleted info - if (newAccount && newAccount != delInfo.accountId) + if (newAccount) { - delInfo.accountId = newAccount; - AccountMgr::GetName(newAccount, delInfo.accountName); + delInfo.accountId = newAccount->GetID(); + delInfo.accountName = newAccount->GetName(); } HandleCharacterDeletedRestoreHelper(delInfo, handler); + return true; } - else - handler->SendSysMessage(LANG_CHARACTER_DELETED_ERR_RENAME); - return true; + handler->SendSysMessage(LANG_CHARACTER_DELETED_ERR_RENAME); + handler->SetSentErrorMessage(true); + return false; } /** @@ -780,19 +662,16 @@ public: * * @param args the search string which either contains a player GUID or a part fo the character-name */ - static bool HandleCharacterDeletedDeleteCommand(ChatHandler* handler, char const* args) + static bool HandleCharacterDeletedDeleteCommand(ChatHandler* handler, std::string needle) { - // It is required to submit at least one argument - if (!*args) - return false; - DeletedInfoList foundList; - if (!GetDeletedCharacterInfoList(foundList, args)) + if (!GetDeletedCharacterInfoList(foundList, needle)) return false; if (foundList.empty()) { handler->SendSysMessage(LANG_CHARACTER_DELETED_LIST_EMPTY); + handler->SetSentErrorMessage(true); return false; } @@ -817,160 +696,93 @@ public: * * @param args the search string which either contains a player GUID or a part fo the character-name */ - static bool HandleCharacterDeletedOldCommand(ChatHandler* /*handler*/, char const* args) + static bool HandleCharacterDeletedOldCommand(ChatHandler* /*handler*/, Optional<uint16> days) { - int32 keepDays = sWorld->getIntConfig(CONFIG_CHARDELETE_KEEP_DAYS); + int32 keepDays = static_cast<int32>(sWorld->getIntConfig(CONFIG_CHARDELETE_KEEP_DAYS)); - char* daysStr = strtok((char*)args, " "); - if (daysStr) - { - if (!isNumeric(daysStr)) - return false; - - keepDays = atoi(daysStr); - if (keepDays < 0) - return false; - } - // config option value 0 -> disabled and can't be used - else if (keepDays <= 0) + if (days) + keepDays = static_cast<int32>(*days); + else if (keepDays <= 0) // config option value 0 -> disabled and can't be used return false; - Player::DeleteOldCharacters(uint32(keepDays)); + Player::DeleteOldCharacters(static_cast<uint32>(keepDays)); return true; } - static bool HandleCharacterEraseCommand(ChatHandler* handler, char const* args) + static bool HandleCharacterEraseCommand(ChatHandler* handler, PlayerIdentifier player) { - if (!*args) - return false; - - char* characterName_str = strtok((char*)args, " "); - if (!characterName_str) - return false; - - std::string characterName = characterName_str; - if (!normalizePlayerName(characterName)) - return false; - - ObjectGuid characterGuid; uint32 accountId; - - Player* player = ObjectAccessor::FindPlayerByName(characterName); - if (player) + if (player.IsConnected()) { - characterGuid = player->GetGUID(); accountId = player->GetSession()->GetAccountId(); player->GetSession()->KickPlayer("HandleCharacterEraseCommand GM Command deleting character"); } else - { - characterGuid = sCharacterCache->GetCharacterGuidByName(characterName); - if (!characterGuid) - { - handler->PSendSysMessage(LANG_NO_PLAYER, characterName.c_str()); - handler->SetSentErrorMessage(true); - return false; - } - accountId = sCharacterCache->GetCharacterAccountIdByGuid(characterGuid); - } + accountId = sCharacterCache->GetCharacterAccountIdByGuid(player); std::string accountName; AccountMgr::GetName(accountId, accountName); - Player::DeleteFromDB(characterGuid, accountId, true, true); - handler->PSendSysMessage(LANG_CHARACTER_DELETED, characterName.c_str(), characterGuid.ToString().c_str(), accountName.c_str(), accountId); + Player::DeleteFromDB(player, accountId, true, true); + handler->PSendSysMessage(LANG_CHARACTER_DELETED, player.GetName().c_str(), player.GetGUID().ToString().c_str(), accountName.c_str(), accountId); return true; } - static bool HandleLevelUpCommand(ChatHandler* handler, char const* args) + static bool HandleLevelUpCommand(ChatHandler* handler, Optional<PlayerIdentifier> player, Optional<int16> level) { - char* nameStr; - char* levelStr; - handler->extractOptFirstArg((char*)args, &nameStr, &levelStr); - - // exception opt second arg: .character level $name - if (levelStr && isalpha(levelStr[0])) - { - nameStr = levelStr; - levelStr = nullptr; // current level will be used - } - - Player* target; - ObjectGuid targetGuid; - std::string targetName; - if (!handler->extractPlayerTarget(nameStr, &target, &targetGuid, &targetName)) + if (!player) + player = PlayerIdentifier::FromTargetOrSelf(handler); + if (!player) return false; - int32 oldlevel = target ? target->GetLevel() : sCharacterCache->GetCharacterLevelByGuid(targetGuid); - int32 addlevel = levelStr ? atoi(levelStr) : 1; - int32 newlevel = oldlevel + addlevel; + uint8 oldlevel = static_cast<uint8>(player->IsConnected() ? player->GetConnectedPlayer()->GetLevel() : sCharacterCache->GetCharacterLevelByGuid(*player)); + int16 newlevel = static_cast<int16>(oldlevel) + level.value_or(1); if (newlevel < 1) newlevel = 1; - if (newlevel > STRONG_MAX_LEVEL) // hardcoded maximum level - newlevel = STRONG_MAX_LEVEL; + if (newlevel > static_cast<int16>(STRONG_MAX_LEVEL)) + newlevel = static_cast<int16>(STRONG_MAX_LEVEL); - HandleCharacterLevel(target, targetGuid, oldlevel, newlevel, handler); - - if (!handler->GetSession() || handler->GetSession()->GetPlayer() != target) // including chr == NULL + if (Player* target = player->GetConnectedPlayer()) { - std::string nameLink = handler->playerLink(targetName); - handler->PSendSysMessage(LANG_YOU_CHANGE_LVL, nameLink.c_str(), newlevel); - } - - return true; - } - - static bool HandlePDumpLoadCommand(ChatHandler* handler, char const* args) - { - if (!*args) - return false; - - char* fileStr = strtok((char*)args, " "); - if (!fileStr) - return false; - - char* accountStr = strtok(nullptr, " "); - if (!accountStr) - return false; - - std::string accountName = accountStr; - if (!Utf8ToUpperOnlyLatin(accountName)) - { - handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); - handler->SetSentErrorMessage(true); - return false; - } + target->GiveLevel(static_cast<uint8>(newlevel)); + target->InitTalentForLevel(); + target->SetXP(0); - uint32 accountId = AccountMgr::GetId(accountName); - if (!accountId) - { - accountId = atoi(accountStr); // use original string - if (!accountId) + if (handler->needReportToTarget(target)) { - handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); - handler->SetSentErrorMessage(true); - return false; + if (oldlevel == newlevel) + ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_LEVEL_PROGRESS_RESET, handler->GetNameLink().c_str()); + else if (oldlevel < static_cast<uint8>(newlevel)) + ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_LEVEL_UP, handler->GetNameLink().c_str(), newlevel); + else // if (oldlevel > newlevel) + ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_LEVEL_DOWN, handler->GetNameLink().c_str(), newlevel); } } - - if (!AccountMgr::GetName(accountId, accountName)) + else { - handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); - handler->SetSentErrorMessage(true); - return false; + // Update level and reset XP, everything else will be updated at login + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_LEVEL); + stmt->setUInt8(0, static_cast<uint8>(newlevel)); + stmt->setUInt64(1, player->GetGUID().GetCounter()); + CharacterDatabase.Execute(stmt); } - char* guidStr = nullptr; - char* nameStr = strtok(nullptr, " "); + if (!handler->GetSession() || (handler->GetSession()->GetPlayer() != player->GetConnectedPlayer())) // including chr == NULL + handler->PSendSysMessage(LANG_YOU_CHANGE_LVL, handler->playerLink(player->GetName()).c_str(), newlevel); + + return true; + } + static bool HandlePDumpLoadCommand(ChatHandler* handler, std::string fileName, AccountIdentifier account, Optional<std::string_view> characterName, Optional<ObjectGuid::LowType> characterGUID) + { std::string name; - if (nameStr) + if (characterName) { - name = nameStr; + name.assign(*characterName); // normalize the name if specified and check if it exists if (!normalizePlayerName(name)) { @@ -985,45 +797,33 @@ public: handler->SetSentErrorMessage(true); return false; } - - guidStr = strtok(nullptr, " "); } - ObjectGuid::LowType guid = UI64LIT(0); - - if (guidStr) + if (characterGUID) { - guid = strtoull(guidStr, nullptr, 10); - if (!guid) + if (sCharacterCache->GetCharacterCacheByGuid(ObjectGuid::Create<HighGuid::Player>(*characterGUID))) { - handler->PSendSysMessage(LANG_INVALID_CHARACTER_GUID); - handler->SetSentErrorMessage(true); - return false; - } - - if (sCharacterCache->GetCharacterAccountIdByGuid(ObjectGuid::Create<HighGuid::Player>(guid))) - { - handler->PSendSysMessage(LANG_CHARACTER_GUID_IN_USE, std::to_string(guid).c_str()); + handler->PSendSysMessage(LANG_CHARACTER_GUID_IN_USE, *characterGUID); handler->SetSentErrorMessage(true); return false; } } - switch (PlayerDumpReader().LoadDump(fileStr, accountId, name, guid)) + switch (PlayerDumpReader().LoadDump(fileName, account, name, characterGUID.value_or(0))) { case DUMP_SUCCESS: handler->PSendSysMessage(LANG_COMMAND_IMPORT_SUCCESS); break; case DUMP_FILE_OPEN_ERROR: - handler->PSendSysMessage(LANG_FILE_OPEN_FAIL, fileStr); + handler->PSendSysMessage(LANG_FILE_OPEN_FAIL, fileName.c_str()); handler->SetSentErrorMessage(true); return false; case DUMP_FILE_BROKEN: - handler->PSendSysMessage(LANG_DUMP_BROKEN, fileStr); + handler->PSendSysMessage(LANG_DUMP_BROKEN, fileName.c_str()); handler->SetSentErrorMessage(true); return false; case DUMP_TOO_MANY_CHARS: - handler->PSendSysMessage(LANG_ACCOUNT_CHARACTER_LIST_FULL, accountName.c_str(), accountId); + handler->PSendSysMessage(LANG_ACCOUNT_CHARACTER_LIST_FULL, account.GetName().c_str(), account.GetID()); handler->SetSentErrorMessage(true); return false; default: @@ -1035,48 +835,15 @@ public: return true; } - static bool HandlePDumpWriteCommand(ChatHandler* handler, char const* args) + static bool HandlePDumpWriteCommand(ChatHandler* handler, std::string fileName, PlayerIdentifier player) { - if (!*args) - return false; - - char* fileStr = strtok((char*)args, " "); - char* playerStr = strtok(nullptr, " "); - - if (!fileStr || !playerStr) - return false; - - ObjectGuid guid; - // character name can't start from number - if (isNumeric(playerStr)) - guid = ObjectGuid::Create<HighGuid::Player>(strtoull(playerStr, nullptr, 10)); - else - { - std::string name = handler->extractPlayerNameFromLink(playerStr); - if (name.empty()) - { - handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); - handler->SetSentErrorMessage(true); - return false; - } - - guid = sCharacterCache->GetCharacterGuidByName(name); - } - - if (!sCharacterCache->GetCharacterAccountIdByGuid(guid)) - { - handler->PSendSysMessage(LANG_PLAYER_NOT_FOUND); - handler->SetSentErrorMessage(true); - return false; - } - - switch (PlayerDumpWriter().WriteDump(fileStr, guid.GetCounter())) + switch (PlayerDumpWriter().WriteDump(fileName, player.GetGUID().GetCounter())) { case DUMP_SUCCESS: handler->PSendSysMessage(LANG_COMMAND_EXPORT_SUCCESS); break; case DUMP_FILE_OPEN_ERROR: - handler->PSendSysMessage(LANG_FILE_OPEN_FAIL, fileStr); + handler->PSendSysMessage(LANG_FILE_OPEN_FAIL, fileName.c_str()); handler->SetSentErrorMessage(true); return false; case DUMP_CHARACTER_DELETED: |