diff options
Diffstat (limited to 'src/server/game/Handlers/CharacterHandler.cpp')
-rw-r--r-- | src/server/game/Handlers/CharacterHandler.cpp | 440 |
1 files changed, 170 insertions, 270 deletions
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 644365b9177..04477528a04 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -42,6 +42,7 @@ #include "Pet.h" #include "PlayerDump.h" #include "Player.h" +#include "QueryCallback.h" #include "QueryPackets.h" #include "ReputationMgr.h" #include "GitRevision.h" @@ -350,8 +351,7 @@ void WorldSession::HandleCharEnumOpcode(WorldPackets::Character::EnumCharacters& stmt->setUInt8(0, PET_SAVE_AS_CURRENT); stmt->setUInt32(1, GetAccountId()); - _charEnumCallback.SetParam(false); - _charEnumCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); + _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleCharEnum, this, std::placeholders::_1))); } void WorldSession::HandleCharUndeleteEnum(PreparedQueryResult result) @@ -393,8 +393,7 @@ void WorldSession::HandleCharUndeleteEnumOpcode(WorldPackets::Character::EnumCha stmt->setUInt8(0, PET_SAVE_AS_CURRENT); stmt->setUInt32(1, GetAccountId()); - _charEnumCallback.SetParam(true); - _charEnumCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); + _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleCharUndeleteEnum, this, std::placeholders::_1))); } void WorldSession::HandleCharCreateOpcode(WorldPackets::Character::CreateCharacter& charCreate) @@ -519,101 +518,60 @@ void WorldSession::HandleCharCreateOpcode(WorldPackets::Character::CreateCharact } } + std::shared_ptr<WorldPackets::Character::CharacterCreateInfo> createInfo = charCreate.CreateInfo; PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); stmt->setString(0, charCreate.CreateInfo->Name); - _charCreateCallback.SetParam(charCreate.CreateInfo); - _charCreateCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); -} - -void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, WorldPackets::Character::CharacterCreateInfo* createInfo) -{ - /** This is a series of callbacks executed consecutively as a result from the database becomes available. - This is much more efficient than synchronous requests on packet handler, and much less DoS prone. - It also prevents data synchronisation errors. - */ - switch (_charCreateCallback.GetStage()) + _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt) + .WithChainingPreparedCallback([this](QueryCallback& queryCallback, PreparedQueryResult result) { - case 0: + if (result) { - if (result) - { - SendCharCreate(CHAR_CREATE_NAME_IN_USE); - _charCreateCallback.Reset(); - return; - } - - ASSERT(_charCreateCallback.GetParam().get() == createInfo); + SendCharCreate(CHAR_CREATE_NAME_IN_USE); + return; + } - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SUM_REALM_CHARACTERS); - stmt->setUInt32(0, GetAccountId()); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SUM_REALM_CHARACTERS); + stmt->setUInt32(0, GetAccountId()); + queryCallback.SetNextQuery(LoginDatabase.AsyncQuery(stmt)); + }) + .WithChainingPreparedCallback([this](QueryCallback& queryCallback, PreparedQueryResult result) + { + uint64 acctCharCount = 0; + if (result) + { + Field* fields = result->Fetch(); + acctCharCount = uint64(fields[0].GetDouble()); + } - _charCreateCallback.FreeResult(); - _charCreateCallback.SetFutureResult(LoginDatabase.AsyncQuery(stmt)); - _charCreateCallback.NextStage(); - break; + if (acctCharCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_ACCOUNT)) + { + SendCharCreate(CHAR_CREATE_ACCOUNT_LIMIT); + return; } - case 1: + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS); + stmt->setUInt32(0, GetAccountId()); + queryCallback.SetNextQuery(LoginDatabase.AsyncQuery(stmt)); + }) + .WithChainingPreparedCallback([this, createInfo](QueryCallback& queryCallback, PreparedQueryResult result) + { + if (result) { - uint64 acctCharCount = 0; - if (result) - { - Field* fields = result->Fetch(); - acctCharCount = uint64(fields[0].GetDouble()); - } + Field* fields = result->Fetch(); + createInfo->CharCount = uint8(fields[0].GetUInt64()); // SQL's COUNT() returns uint64 but it will always be less than uint8.Max - if (acctCharCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_ACCOUNT)) + if (createInfo->CharCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM)) { - SendCharCreate(CHAR_CREATE_ACCOUNT_LIMIT); - _charCreateCallback.Reset(); + SendCharCreate(CHAR_CREATE_SERVER_LIMIT); return; } - - ASSERT(_charCreateCallback.GetParam().get() == createInfo); - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS); - stmt->setUInt32(0, GetAccountId()); - - _charCreateCallback.FreeResult(); - _charCreateCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); - _charCreateCallback.NextStage(); - break; } - case 2: - { - if (result) - { - Field* fields = result->Fetch(); - createInfo->CharCount = uint8(fields[0].GetUInt64()); // SQL's COUNT() returns uint64 but it will always be less than uint8.Max - if (createInfo->CharCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM)) - { - SendCharCreate(CHAR_CREATE_SERVER_LIMIT); - _charCreateCallback.Reset(); - return; - } - } - - bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || HasPermission(rbac::RBAC_PERM_TWO_SIDE_CHARACTER_CREATION); - uint32 skipCinematics = sWorld->getIntConfig(CONFIG_SKIP_CINEMATICS); - - _charCreateCallback.FreeResult(); - - if (!allowTwoSideAccounts || skipCinematics == 1 || createInfo->Class == CLASS_DEATH_KNIGHT || createInfo->Class == CLASS_DEMON_HUNTER) - { - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_CREATE_INFO); - stmt->setUInt32(0, GetAccountId()); - stmt->setUInt32(1, (skipCinematics == 1 || createInfo->Class == CLASS_DEATH_KNIGHT || createInfo->Class == CLASS_DEMON_HUNTER) ? 12 : 1); - _charCreateCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); - _charCreateCallback.NextStage(); - return; - } + bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || HasPermission(rbac::RBAC_PERM_TWO_SIDE_CHARACTER_CREATION); + uint32 skipCinematics = sWorld->getIntConfig(CONFIG_SKIP_CINEMATICS); - _charCreateCallback.NextStage(); - HandleCharCreateCallback(PreparedQueryResult(NULL), createInfo); // Will jump to case 3 - break; - } - case 3: + std::function<void(PreparedQueryResult)> finalizeCharacterCreation = [this, createInfo](PreparedQueryResult result) { bool haveSameRace = false; uint32 heroicReqLevel = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER); @@ -632,7 +590,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, WorldPac uint32 freeDemonHunterSlots = sWorld->getIntConfig(CONFIG_DEMON_HUNTERS_PER_REALM); Field* field = result->Fetch(); - uint8 accRace = field[1].GetUInt8(); + uint8 accRace = field[1].GetUInt8(); if (checkHeroicReqs) { @@ -645,7 +603,6 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, WorldPac if (freeHeroicSlots == 0) { SendCharCreate(CHAR_CREATE_UNIQUE_CLASS_LIMIT); - _charCreateCallback.Reset(); return; } } @@ -669,7 +626,6 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, WorldPac if (freeDemonHunterSlots == 0) { SendCharCreate(CHAR_CREATE_FAILED); - _charCreateCallback.Reset(); return; } } @@ -693,7 +649,6 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, WorldPac if (accTeam != team) { SendCharCreate(CHAR_CREATE_PVP_TEAMS_VIOLATION); - _charCreateCallback.Reset(); return; } } @@ -722,7 +677,6 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, WorldPac if (freeHeroicSlots == 0) { SendCharCreate(CHAR_CREATE_UNIQUE_CLASS_LIMIT); - _charCreateCallback.Reset(); return; } } @@ -746,7 +700,6 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, WorldPac if (freeDemonHunterSlots == 0) { SendCharCreate(CHAR_CREATE_FAILED); - _charCreateCallback.Reset(); return; } } @@ -764,26 +717,23 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, WorldPac if (checkHeroicReqs && !hasHeroicReqLevel) { SendCharCreate(CHAR_CREATE_LEVEL_REQUIREMENT); - _charCreateCallback.Reset(); return; } if (checkDemonHunterReqs && !hasDemonHunterReqLevel) { SendCharCreate(CHAR_CREATE_LEVEL_REQUIREMENT); - _charCreateCallback.Reset(); return; } Player newChar(this); newChar.GetMotionMaster()->Initialize(); - if (!newChar.Create(sObjectMgr->GetGenerator<HighGuid::Player>().Generate(), createInfo)) + if (!newChar.Create(sObjectMgr->GetGenerator<HighGuid::Player>().Generate(), createInfo.get())) { // Player not create (race/class/etc problem?) newChar.CleanupsBeforeDelete(); SendCharCreate(CHAR_CREATE_ERROR); - _charCreateCallback.Reset(); return; } @@ -792,7 +742,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, WorldPac newChar.SetAtLoginFlag(AT_LOGIN_FIRST); // First login - // Player created, save it now + // Player created, save it now newChar.SaveToDB(true); createInfo->CharCount += 1; @@ -837,10 +787,19 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, WorldPac sWorld->AddCharacterInfo(newChar.GetGUID(), GetAccountId(), newChar.GetName(), newChar.GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER), newChar.getRace(), newChar.getClass(), newChar.getLevel(), false); newChar.CleanupsBeforeDelete(); - _charCreateCallback.Reset(); - break; + }; + + if (allowTwoSideAccounts && !skipCinematics && createInfo->Class != CLASS_DEATH_KNIGHT && createInfo->Class != CLASS_DEMON_HUNTER) + { + finalizeCharacterCreation(PreparedQueryResult(nullptr)); + return; } - } + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_CREATE_INFO); + stmt->setUInt32(0, GetAccountId()); + stmt->setUInt32(1, (skipCinematics == 1 || createInfo->Class == CLASS_DEATH_KNIGHT || createInfo->Class == CLASS_DEMON_HUNTER) ? 12 : 1); + queryCallback.WithPreparedCallback(std::move(finalizeCharacterCreation)).SetNextQuery(CharacterDatabase.AsyncQuery(stmt)); + })); } void WorldSession::HandleCharDeleteOpcode(WorldPackets::Character::CharDelete& charDelete) @@ -1371,17 +1330,15 @@ void WorldSession::HandleCharRenameOpcode(WorldPackets::Character::CharacterRena stmt->setUInt64(0, request.RenameInfo->Guid.GetCounter()); stmt->setString(1, request.RenameInfo->NewName); - _charRenameCallback.SetParam(request.RenameInfo); - _charRenameCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); + _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt) + .WithPreparedCallback(std::bind(&WorldSession::HandleCharRenameCallBack, this, request.RenameInfo, std::placeholders::_1))); } -void WorldSession::HandleCharRenameCallBack(PreparedQueryResult result, WorldPackets::Character::CharacterRenameInfo* renameInfo) +void WorldSession::HandleCharRenameCallBack(std::shared_ptr<WorldPackets::Character::CharacterRenameInfo> renameInfo, PreparedQueryResult result) { - ASSERT(_charRenameCallback.GetParam().get() == renameInfo); - if (!result) { - SendCharRename(CHAR_CREATE_ERROR, renameInfo); + SendCharRename(CHAR_CREATE_ERROR, renameInfo.get()); return; } @@ -1392,7 +1349,7 @@ void WorldSession::HandleCharRenameCallBack(PreparedQueryResult result, WorldPac if (!(atLoginFlags & AT_LOGIN_RENAME)) { - SendCharRename(CHAR_CREATE_ERROR, renameInfo); + SendCharRename(CHAR_CREATE_ERROR, renameInfo.get()); return; } @@ -1420,7 +1377,7 @@ void WorldSession::HandleCharRenameCallBack(PreparedQueryResult result, WorldPac TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (%s) Changed name to: %s", GetAccountId(), GetRemoteAddress().c_str(), oldName.c_str(), renameInfo->Guid.ToString().c_str(), renameInfo->NewName.c_str()); - SendCharRename(RESPONSE_SUCCESS, renameInfo); + SendCharRename(RESPONSE_SUCCESS, renameInfo.get()); sWorld->UpdateCharacterInfo(renameInfo->Guid, renameInfo->NewName); } @@ -1582,17 +1539,15 @@ void WorldSession::HandleCharCustomizeOpcode(WorldPackets::Character::CharCustom PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_CUSTOMIZE_INFO); stmt->setUInt64(0, packet.CustomizeInfo->CharGUID.GetCounter()); - _charCustomizeCallback.SetParam(packet.CustomizeInfo); - _charCustomizeCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); + _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt) + .WithPreparedCallback(std::bind(&WorldSession::HandleCharCustomizeCallback, this, packet.CustomizeInfo, std::placeholders::_1))); } -void WorldSession::HandleCharCustomizeCallback(PreparedQueryResult result, WorldPackets::Character::CharCustomizeInfo* customizeInfo) +void WorldSession::HandleCharCustomizeCallback(std::shared_ptr<WorldPackets::Character::CharCustomizeInfo> customizeInfo, PreparedQueryResult result) { - ASSERT(_charCustomizeCallback.GetParam().get() == customizeInfo); - if (!result) { - SendCharCustomize(CHAR_CREATE_ERROR, customizeInfo); + SendCharCustomize(CHAR_CREATE_ERROR, customizeInfo.get()); return; } @@ -1607,13 +1562,13 @@ void WorldSession::HandleCharCustomizeCallback(PreparedQueryResult result, World if (!Player::ValidateAppearance(plrRace, plrClass, plrGender, customizeInfo->HairStyleID, customizeInfo->HairColorID, customizeInfo->FaceID, customizeInfo->FacialHairStyleID, customizeInfo->SkinID, customizeInfo->CustomDisplay)) { - SendCharCustomize(CHAR_CREATE_ERROR, customizeInfo); + SendCharCustomize(CHAR_CREATE_ERROR, customizeInfo.get()); return; } if (!(atLoginFlags & AT_LOGIN_CUSTOMIZE)) { - SendCharCustomize(CHAR_CREATE_ERROR, customizeInfo); + SendCharCustomize(CHAR_CREATE_ERROR, customizeInfo.get()); return; } @@ -1622,21 +1577,21 @@ void WorldSession::HandleCharCustomizeCallback(PreparedQueryResult result, World // prevent character rename to invalid name if (!normalizePlayerName(customizeInfo->CharName)) { - SendCharCustomize(CHAR_NAME_NO_NAME, customizeInfo); + SendCharCustomize(CHAR_NAME_NO_NAME, customizeInfo.get()); return; } ResponseCodes res = ObjectMgr::CheckPlayerName(customizeInfo->CharName, GetSessionDbcLocale(), true); if (res != CHAR_NAME_SUCCESS) { - SendCharCustomize(res, customizeInfo); + SendCharCustomize(res, customizeInfo.get()); return; } // check name limitations if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(customizeInfo->CharName)) { - SendCharCustomize(CHAR_NAME_RESERVED, customizeInfo); + SendCharCustomize(CHAR_NAME_RESERVED, customizeInfo.get()); return; } @@ -1647,7 +1602,7 @@ void WorldSession::HandleCharCustomizeCallback(PreparedQueryResult result, World { if (newGuid != customizeInfo->CharGUID) { - SendCharCustomize(CHAR_CREATE_NAME_IN_USE, customizeInfo); + SendCharCustomize(CHAR_CREATE_NAME_IN_USE, customizeInfo.get()); return; } } @@ -1694,7 +1649,7 @@ void WorldSession::HandleCharCustomizeCallback(PreparedQueryResult result, World sWorld->UpdateCharacterInfo(customizeInfo->CharGUID, customizeInfo->CharName, customizeInfo->SexID); - SendCharCustomize(RESPONSE_SUCCESS, customizeInfo); + SendCharCustomize(RESPONSE_SUCCESS, customizeInfo.get()); TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s), Character[%s] (%s) Customized to: %s", GetAccountId(), GetRemoteAddress().c_str(), oldName.c_str(), customizeInfo->CharGUID.ToString().c_str(), customizeInfo->CharName.c_str()); @@ -1855,17 +1810,15 @@ void WorldSession::HandleCharRaceOrFactionChangeOpcode(WorldPackets::Character:: PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_RACE_OR_FACTION_CHANGE_INFOS); stmt->setUInt64(0, packet.RaceOrFactionChangeInfo->Guid.GetCounter()); - _charFactionChangeCallback.SetParam(packet.RaceOrFactionChangeInfo); - _charFactionChangeCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); + _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt) + .WithPreparedCallback(std::bind(&WorldSession::HandleCharRaceOrFactionChangeCallback, this, packet.RaceOrFactionChangeInfo, std::placeholders::_1))); } -void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult result, WorldPackets::Character::CharRaceOrFactionChangeInfo* factionChangeInfo) +void WorldSession::HandleCharRaceOrFactionChangeCallback(std::shared_ptr<WorldPackets::Character::CharRaceOrFactionChangeInfo> factionChangeInfo, PreparedQueryResult result) { - ASSERT(_charFactionChangeCallback.GetParam().get() == factionChangeInfo); - if (!result) { - SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo); + SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get()); return; } @@ -1873,7 +1826,7 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res CharacterInfo const* characterInfo = sWorld->GetCharacterInfo(factionChangeInfo->Guid); if (!characterInfo) { - SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo); + SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get()); return; } @@ -1883,7 +1836,7 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res if (!sObjectMgr->GetPlayerInfo(factionChangeInfo->RaceID, playerClass)) { - SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo); + SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get()); return; } @@ -1894,20 +1847,20 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res uint16 usedLoginFlag = (factionChangeInfo->FactionChange ? AT_LOGIN_CHANGE_FACTION : AT_LOGIN_CHANGE_RACE); if (!(atLoginFlags & usedLoginFlag)) { - SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo); + SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get()); return; } TeamId newTeamId = Player::TeamIdForRace(factionChangeInfo->RaceID); if (newTeamId == TEAM_NEUTRAL) { - SendCharFactionChange(CHAR_CREATE_RESTRICTED_RACECLASS, factionChangeInfo); + SendCharFactionChange(CHAR_CREATE_RESTRICTED_RACECLASS, factionChangeInfo.get()); return; } if (factionChangeInfo->FactionChange == (Player::TeamIdForRace(oldRace) == newTeamId)) { - SendCharFactionChange(factionChangeInfo->FactionChange ? CHAR_CREATE_CHARACTER_SWAP_FACTION : CHAR_CREATE_CHARACTER_RACE_ONLY, factionChangeInfo); + SendCharFactionChange(factionChangeInfo->FactionChange ? CHAR_CREATE_CHARACTER_SWAP_FACTION : CHAR_CREATE_CHARACTER_RACE_ONLY, factionChangeInfo.get()); return; } @@ -1916,7 +1869,7 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res uint32 raceMaskDisabled = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK); if ((1 << (factionChangeInfo->RaceID - 1)) & raceMaskDisabled) { - SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo); + SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get()); return; } } @@ -1924,21 +1877,21 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res // prevent character rename to invalid name if (!normalizePlayerName(factionChangeInfo->Name)) { - SendCharFactionChange(CHAR_NAME_NO_NAME, factionChangeInfo); + SendCharFactionChange(CHAR_NAME_NO_NAME, factionChangeInfo.get()); return; } ResponseCodes res = ObjectMgr::CheckPlayerName(factionChangeInfo->Name, GetSessionDbcLocale(), true); if (res != CHAR_NAME_SUCCESS) { - SendCharFactionChange(res, factionChangeInfo); + SendCharFactionChange(res, factionChangeInfo.get()); return; } // check name limitations if (!HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(factionChangeInfo->Name)) { - SendCharFactionChange(CHAR_NAME_RESERVED, factionChangeInfo); + SendCharFactionChange(CHAR_NAME_RESERVED, factionChangeInfo.get()); return; } @@ -1948,14 +1901,14 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res { if (newGuid != factionChangeInfo->Guid) { - SendCharFactionChange(CHAR_CREATE_NAME_IN_USE, factionChangeInfo); + SendCharFactionChange(CHAR_CREATE_NAME_IN_USE, factionChangeInfo.get()); return; } } if (sArenaTeamMgr->GetArenaTeamByCaptain(factionChangeInfo->Guid)) { - SendCharFactionChange(CHAR_CREATE_CHARACTER_ARENA_LEADER, factionChangeInfo); + SendCharFactionChange(CHAR_CREATE_CHARACTER_ARENA_LEADER, factionChangeInfo.get()); return; } @@ -2306,7 +2259,7 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res if (tokens.size() != ktcount) { - SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo); + SendCharFactionChange(CHAR_CREATE_ERROR, factionChangeInfo.get()); return; } @@ -2370,7 +2323,7 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res TC_LOG_DEBUG("entities.player", "%s (IP: %s) changed race from %u to %u", GetPlayerInfo().c_str(), GetRemoteAddress().c_str(), oldRace, factionChangeInfo->RaceID); - SendCharFactionChange(RESPONSE_SUCCESS, factionChangeInfo); + SendCharFactionChange(RESPONSE_SUCCESS, factionChangeInfo.get()); } void WorldSession::HandleRandomizeCharNameOpcode(WorldPackets::Character::GenerateRandomCharacterName& packet) @@ -2427,176 +2380,123 @@ void WorldSession::HandleOpeningCinematic(WorldPackets::Misc::OpeningCinematic& void WorldSession::HandleGetUndeleteCooldownStatus(WorldPackets::Character::GetUndeleteCharacterCooldownStatus& /*getCooldown*/) { - /// empty result to force wait - PreparedQueryResultPromise result; - result.set_value(PreparedQueryResult(nullptr)); - _undeleteCooldownStatusCallback.SetFutureResult(result.get_future()); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LAST_CHAR_UNDELETE); + stmt->setUInt32(0, GetBattlenetAccountId()); + + _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleUndeleteCooldownStatusCallback, this, std::placeholders::_1))); } void WorldSession::HandleUndeleteCooldownStatusCallback(PreparedQueryResult result) { - switch (_undeleteCooldownStatusCallback.GetStage()) + uint32 cooldown = 0; + uint32 maxCooldown = sWorld->getIntConfig(CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_COOLDOWN); + if (result) { - case 0: - { - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LAST_CHAR_UNDELETE); - stmt->setUInt32(0, GetBattlenetAccountId()); - - _undeleteCooldownStatusCallback.FreeResult(); - _undeleteCooldownStatusCallback.SetFutureResult(LoginDatabase.AsyncQuery(stmt)); - _undeleteCooldownStatusCallback.NextStage(); - break; - } - case 1: - { - uint32 cooldown = 0; - uint32 maxCooldown = sWorld->getIntConfig(CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_COOLDOWN); - if (result) - { - uint32 lastUndelete = result->Fetch()[0].GetUInt32(); - uint32 now = uint32(time(nullptr)); - if (lastUndelete + maxCooldown > now) - cooldown = std::max<uint32>(0, lastUndelete + maxCooldown - now); - } - - SendUndeleteCooldownStatusResponse(cooldown, maxCooldown); - _undeleteCooldownStatusCallback.Reset(); - break; - } + uint32 lastUndelete = result->Fetch()[0].GetUInt32(); + uint32 now = uint32(time(nullptr)); + if (lastUndelete + maxCooldown > now) + cooldown = std::max<uint32>(0, lastUndelete + maxCooldown - now); } + SendUndeleteCooldownStatusResponse(cooldown, maxCooldown); } -void WorldSession::HandleCharUndeleteOpcode(WorldPackets::Character::UndeleteCharacter& undeleteInfo) +void WorldSession::HandleCharUndeleteOpcode(WorldPackets::Character::UndeleteCharacter& undeleteCharacter) { if (!sWorld->getBoolConfig(CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_ENABLED)) { - SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_DISABLED, undeleteInfo.UndeleteInfo.get()); + SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_DISABLED, undeleteCharacter.UndeleteInfo.get()); return; } PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LAST_CHAR_UNDELETE); stmt->setUInt32(0, GetBattlenetAccountId()); - _charUndeleteCallback.SetParam(undeleteInfo.UndeleteInfo); - _charUndeleteCallback.SetFutureResult(LoginDatabase.AsyncQuery(stmt)); - _charUndeleteCallback.NextStage(); -} - -void WorldSession::HandleCharUndeleteCallback(PreparedQueryResult result, WorldPackets::Character::CharacterUndeleteInfo* undeleteInfo) -{ - /** This is a series of callbacks executed consecutively as a result from the database becomes available. - * This is much more efficient than synchronous requests on packet handler. - * It also prevents data synchronisation errors. - */ - - ASSERT(_charUndeleteCallback.GetParam().get() == undeleteInfo); - - switch (_charUndeleteCallback.GetStage()) + std::shared_ptr<WorldPackets::Character::CharacterUndeleteInfo> undeleteInfo = undeleteCharacter.UndeleteInfo; + _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt) + .WithChainingPreparedCallback([this, undeleteInfo](QueryCallback& queryCallback, PreparedQueryResult result) { - case 1: - { - if (result) - { - uint32 lastUndelete = result->Fetch()[0].GetUInt32(); - uint32 maxCooldown = sWorld->getIntConfig(CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_COOLDOWN); - if (lastUndelete && (lastUndelete + maxCooldown > time(nullptr))) - { - SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_COOLDOWN, undeleteInfo); - _charUndeleteCallback.Reset(); - return; - } - } - - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_DEL_INFO_BY_GUID); - stmt->setUInt64(0, undeleteInfo->CharacterGuid.GetCounter()); - - _charUndeleteCallback.FreeResult(); - _charUndeleteCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); - _charUndeleteCallback.NextStage(); - break; - } - case 2: + if (result) { - if (!result) + uint32 lastUndelete = result->Fetch()[0].GetUInt32(); + uint32 maxCooldown = sWorld->getIntConfig(CONFIG_FEATURE_SYSTEM_CHARACTER_UNDELETE_COOLDOWN); + if (lastUndelete && (lastUndelete + maxCooldown > time(nullptr))) { - SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_CHAR_CREATE, undeleteInfo); - _charUndeleteCallback.Reset(); + SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_COOLDOWN, undeleteInfo.get()); return; } + } - Field* fields = result->Fetch(); - undeleteInfo->Name = fields[1].GetString(); - uint32 account = fields[2].GetUInt32(); - - if (account != GetAccountId()) - { - SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_UNKNOWN, undeleteInfo); - _charUndeleteCallback.Reset(); - return; - } + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_DEL_INFO_BY_GUID); + stmt->setUInt64(0, undeleteInfo->CharacterGuid.GetCounter()); + queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt)); + }) + .WithChainingPreparedCallback([this, undeleteInfo](QueryCallback& queryCallback, PreparedQueryResult result) + { + if (!result) + { + SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_CHAR_CREATE, undeleteInfo.get()); + return; + } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); - stmt->setString(0, undeleteInfo->Name); + Field* fields = result->Fetch(); + undeleteInfo->Name = fields[1].GetString(); + uint32 account = fields[2].GetUInt32(); - _charUndeleteCallback.FreeResult(); - _charUndeleteCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); - _charUndeleteCallback.NextStage(); - break; - } - case 3: + if (account != GetAccountId()) { - if (result) - { - SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_NAME_TAKEN_BY_THIS_ACCOUNT, undeleteInfo); - _charUndeleteCallback.Reset(); - return; - } + SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_UNKNOWN, undeleteInfo.get()); + return; + } - /// @todo: add more safety checks - /// * max char count per account - /// * max heroic char count - /// * team violation + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); + stmt->setString(0, undeleteInfo->Name); + queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt)); + }) + .WithChainingPreparedCallback([this, undeleteInfo](QueryCallback& queryCallback, PreparedQueryResult result) + { + if (result) + { + SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_NAME_TAKEN_BY_THIS_ACCOUNT, undeleteInfo.get()); + return; + } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS); - stmt->setUInt32(0, GetAccountId()); + /// @todo: add more safety checks + /// * max char count per account + /// * max heroic char count + /// * team violation - _charUndeleteCallback.FreeResult(); - _charUndeleteCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); - _charUndeleteCallback.NextStage(); - break; - } - case 4: + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS); + stmt->setUInt32(0, GetAccountId()); + queryCallback.SetNextQuery(CharacterDatabase.AsyncQuery(stmt)); + }) + .WithPreparedCallback([this, undeleteInfo](PreparedQueryResult result) + { + if (result) { - if (result) - { - Field* fields = result->Fetch(); + Field* fields = result->Fetch(); - if (fields[0].GetUInt64() >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM)) // SQL's COUNT() returns uint64 but it will always be less than uint8.Max - { - SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_CHAR_CREATE, undeleteInfo); - _charUndeleteCallback.Reset(); - return; - } + if (fields[0].GetUInt64() >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM)) // SQL's COUNT() returns uint64 but it will always be less than uint8.Max + { + SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_ERROR_CHAR_CREATE, undeleteInfo.get()); + return; } + } - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_RESTORE_DELETE_INFO); - stmt->setString(0, undeleteInfo->Name); - stmt->setUInt32(1, GetAccountId()); - stmt->setUInt64(2, undeleteInfo->CharacterGuid.GetCounter()); - CharacterDatabase.Execute(stmt); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_RESTORE_DELETE_INFO); + stmt->setString(0, undeleteInfo->Name); + stmt->setUInt32(1, GetAccountId()); + stmt->setUInt64(2, undeleteInfo->CharacterGuid.GetCounter()); + CharacterDatabase.Execute(stmt); - stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_CHAR_UNDELETE); - stmt->setUInt32(0, GetBattlenetAccountId()); - LoginDatabase.Execute(stmt); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_CHAR_UNDELETE); + stmt->setUInt32(0, GetBattlenetAccountId()); + LoginDatabase.Execute(stmt); - sWorld->UpdateCharacterInfoDeleted(undeleteInfo->CharacterGuid, false, &undeleteInfo->Name); + sWorld->UpdateCharacterInfoDeleted(undeleteInfo->CharacterGuid, false, &undeleteInfo->Name); - SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_OK, undeleteInfo); - _charUndeleteCallback.Reset(); - break; - } - } + SendUndeleteCharacterResponse(CHARACTER_UNDELETE_RESULT_OK, undeleteInfo.get()); + })); } void WorldSession::SendCharCreate(ResponseCodes result) |