diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/database/Database/Implementation/CharacterDatabase.cpp | 1 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/CharacterDatabase.h | 1 | ||||
-rw-r--r-- | src/server/game/Accounts/RBAC.h | 2 | ||||
-rw-r--r-- | src/server/game/Miscellaneous/Language.h | 3 | ||||
-rw-r--r-- | src/server/game/World/World.cpp | 9 | ||||
-rw-r--r-- | src/server/game/World/World.h | 1 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_character.cpp | 81 |
7 files changed, 96 insertions, 2 deletions
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index d0227fde660..53e8ecde2f9 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -196,6 +196,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_GIFT, "DELETE FROM character_gifts WHERE item_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_GIFT_BY_ITEM, "SELECT entry, flags FROM character_gifts WHERE item_guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_ACCOUNT_BY_NAME, "SELECT account FROM characters WHERE name = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_UPD_ACCOUNT_BY_GUID, "UPDATE characters SET account = ? WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_DEL_ACCOUNT_INSTANCE_LOCK_TIMES, "DELETE FROM account_instance_times WHERE accountId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_ACCOUNT_INSTANCE_LOCK_TIMES, "INSERT INTO account_instance_times (accountId, instanceId, releaseTime) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_MATCH_MAKER_RATING, "SELECT matchMakerRating FROM character_arena_stats WHERE guid = ? AND slot = ?", CONNECTION_SYNCH); diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h index c4c081ab73a..2c31b819593 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.h +++ b/src/server/database/Database/Implementation/CharacterDatabase.h @@ -165,6 +165,7 @@ enum CharacterDatabaseStatements : uint32 CHAR_DEL_GIFT, CHAR_SEL_CHARACTER_GIFT_BY_ITEM, CHAR_SEL_ACCOUNT_BY_NAME, + CHAR_UPD_ACCOUNT_BY_GUID, CHAR_DEL_ACCOUNT_INSTANCE_LOCK_TIMES, CHAR_INS_ACCOUNT_INSTANCE_LOCK_TIMES, CHAR_SEL_MATCH_MAKER_RATING, diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 0c1cb84d270..018f4e0c73f 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -603,7 +603,7 @@ enum RBACPermissions RBAC_PERM_COMMAND_RELOAD_SPELL_LOOT_TEMPLATE = 695, RBAC_PERM_COMMAND_RELOAD_SPELL_LINKED_SPELL = 696, RBAC_PERM_COMMAND_RELOAD_SPELL_PET_AURAS = 697, - // 698 - reuse + RBAC_PERM_COMMAND_CHARACTER_CHANGEACCOUNT = 698, RBAC_PERM_COMMAND_RELOAD_SPELL_PROC = 699, RBAC_PERM_COMMAND_RELOAD_SPELL_SCRIPTS = 700, RBAC_PERM_COMMAND_RELOAD_SPELL_TARGET_POSITION = 701, diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 039c3b81604..820edc8adb9 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -927,7 +927,8 @@ enum TrinityStrings LANG_ACCOUNT_BNET_NOT_LINKED = 1189, LANG_DISALLOW_TICKETS_CONFIG = 1190, LANG_BAN_EXISTS = 1191, - // Room for more level 3 1192-1198 not used + LANG_CHANGEACCOUNT_SUCCESS = 1192, + // Room for more level 3 1193-1198 not used // Debug commands LANG_DEBUG_AREATRIGGER_LEFT = 1999, diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 23a62783c83..bafc5207656 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -3616,6 +3616,15 @@ void World::UpdateCharacterInfoLevel(ObjectGuid const& guid, uint8 level) itr->second.Level = level; } +void World::UpdateCharacterInfoAccount(ObjectGuid const& guid, uint32 accountId) +{ + auto itr = _characterInfoStore.find(guid); + if (itr == _characterInfoStore.end()) + return; + + itr->second.AccountId = accountId; +} + void World::UpdateCharacterInfoDeleted(ObjectGuid const& guid, bool deleted, std::string const* name /*= nullptr*/) { CharacterInfoContainer::iterator itr = _characterInfoStore.find(guid); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 16850da37ae..e7eb8c84d4c 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -794,6 +794,7 @@ class TC_GAME_API World bool HasCharacterInfo(ObjectGuid const& guid) { return _characterInfoStore.find(guid) != _characterInfoStore.end(); } void UpdateCharacterInfo(ObjectGuid const& guid, std::string const& name, uint8 gender = GENDER_NONE, uint8 race = RACE_NONE); void UpdateCharacterInfoLevel(ObjectGuid const& guid, uint8 level); + void UpdateCharacterInfoAccount(ObjectGuid const& guid, uint32 accountId); void UpdateCharacterInfoDeleted(ObjectGuid const& guid, bool deleted, std::string const* name = nullptr); uint32 GetCleaningFlags() const { return m_CleaningFlags; } diff --git a/src/server/scripts/Commands/cs_character.cpp b/src/server/scripts/Commands/cs_character.cpp index 9107c0c2ebb..f62ae5f45ca 100644 --- a/src/server/scripts/Commands/cs_character.cpp +++ b/src/server/scripts/Commands/cs_character.cpp @@ -61,6 +61,7 @@ public: { "customize", rbac::RBAC_PERM_COMMAND_CHARACTER_CUSTOMIZE, true, &HandleCharacterCustomizeCommand, "", }, { "changefaction", rbac::RBAC_PERM_COMMAND_CHARACTER_CHANGEFACTION, true, &HandleCharacterChangeFactionCommand, "", }, { "changerace", rbac::RBAC_PERM_COMMAND_CHARACTER_CHANGERACE, true, &HandleCharacterChangeRaceCommand, "", }, + { "changeaccount", rbac::RBAC_PERM_COMMAND_CHARACTER_CHANGEACCOUNT, true, &HandleCharacterChangeAccountCommand, "", }, { "deleted", rbac::RBAC_PERM_COMMAND_CHARACTER_DELETED, true, NULL, "", characterDeletedCommandTable }, { "erase", rbac::RBAC_PERM_COMMAND_CHARACTER_ERASE, true, &HandleCharacterEraseCommand, "", }, { "level", rbac::RBAC_PERM_COMMAND_CHARACTER_LEVEL, true, &HandleCharacterLevelCommand, "", }, @@ -551,6 +552,86 @@ public: return true; } + static bool HandleCharacterChangeAccountCommand(ChatHandler* handler, char const* args) + { + char* playerNameStr; + char* accountNameStr; + handler->extractOptFirstArg(const_cast<char*>(args), &playerNameStr, &accountNameStr); + if (!accountNameStr) + return false; + + ObjectGuid targetGuid; + std::string targetName; + if (!handler->extractPlayerTarget(playerNameStr, nullptr, &targetGuid, &targetName)) + return false; + + CharacterInfo const* characterInfo = sWorld->GetCharacterInfo(targetGuid); + if (!characterInfo) + { + handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); + handler->SetSentErrorMessage(true); + return false; + } + + 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; + } + + PreparedStatement* 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) + return true; + + if (uint32 charCount = AccountMgr::GetCharactersCount(newAccountId)) + { + if (charCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM)) + { + handler->PSendSysMessage(LANG_ACCOUNT_CHARACTER_LIST_FULL, accountName.c_str(), newAccountId); + handler->SetSentErrorMessage(true); + return false; + } + } + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ACCOUNT_BY_GUID); + stmt->setUInt32(0, newAccountId); + stmt->setUInt32(1, targetGuid.GetCounter()); + CharacterDatabase.DirectExecute(stmt); + + sWorld->UpdateRealmCharCount(oldAccountId); + sWorld->UpdateRealmCharCount(newAccountId); + + sWorld->UpdateCharacterInfoAccount(targetGuid, newAccountId); + + handler->PSendSysMessage(LANG_CHANGEACCOUNT_SUCCESS, targetName.c_str(), accountName.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); + if (WorldSession* session = handler->GetSession()) + { + if (Player* player = session->GetPlayer()) + sLog->outCommand(session->GetAccountId(), "GM %s (Account: %u) %s", player->GetName().c_str(), session->GetAccountId(), logString.c_str()); + } + else + sLog->outCommand(0, "%s %s", handler->GetTrinityString(LANG_CONSOLE), logString.c_str()); + return true; + } + static bool HandleCharacterReputationCommand(ChatHandler* handler, char const* args) { Player* target; |