diff options
author | Shauren <shauren.trinity@gmail.com> | 2017-01-13 21:38:03 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2017-01-13 21:38:03 +0100 |
commit | 8e2634b2b49eb814b8cc425a060b2f160dbb49b7 (patch) | |
tree | 9fc926ba9f77539c3eb847e37f3f9d7061f9d47a /src/server | |
parent | 0f432edc4b48a8692e41fc30aef7751d295a7176 (diff) |
Core/DBLayer: Convert async queries to new query callbacks and remove old callback handling
Diffstat (limited to 'src/server')
19 files changed, 383 insertions, 747 deletions
diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index 44c6122b2c6..7fe1c4ef865 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -19,6 +19,7 @@ #include "BattlenetRpcErrorCodes.h" #include "ByteConverter.h" #include "Database/DatabaseEnv.h" +#include "QueryCallback.h" #include "LoginRESTService.h" #include "ProtobufJSON.h" #include "RealmList.h" @@ -91,8 +92,7 @@ void Battlenet::Session::Start() stmt->setString(0, ip_address); stmt->setUInt32(1, inet_addr(ip_address.c_str())); - _queryCallback = std::bind(&Battlenet::Session::CheckIpCallback, this, std::placeholders::_1); - _queryFuture = LoginDatabase.AsyncQuery(stmt); + _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::CheckIpCallback, this, std::placeholders::_1))); } void Battlenet::Session::CheckIpCallback(PreparedQueryResult result) @@ -127,12 +127,7 @@ bool Battlenet::Session::Update() if (!BattlenetSocket::Update()) return false; - if (_queryFuture.valid() && _queryFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) - { - auto callback = std::move(_queryCallback); - _queryCallback = nullptr; - callback(_queryFuture.get()); - } + _queryProcessor.ProcessReadyQueries(); return true; } diff --git a/src/server/bnetserver/Server/Session.h b/src/server/bnetserver/Server/Session.h index 7a8ab6ea55f..99a0ec088a1 100644 --- a/src/server/bnetserver/Server/Session.h +++ b/src/server/bnetserver/Server/Session.h @@ -23,7 +23,8 @@ #include "SslSocket.h" #include "Socket.h" #include "BigNumber.h" -#include "QueryCallback.h" +#include "QueryResult.h" +#include "QueryCallbackProcessor.h" #include <boost/asio/ip/tcp.hpp> #include <boost/asio/ssl.hpp> #include <google/protobuf/message.h> @@ -188,8 +189,7 @@ namespace Battlenet bool _authed; - PreparedQueryResultFuture _queryFuture; - std::function<void(PreparedQueryResult)> _queryCallback; + QueryCallbackProcessor _queryProcessor; std::unordered_map<uint32, std::function<void(MessageBuffer)>> _responseCallbacks; uint32 _requestToken; diff --git a/src/server/database/Database/DatabaseWorkerPool.cpp b/src/server/database/Database/DatabaseWorkerPool.cpp index 0a3865009b0..e680ed834a3 100644 --- a/src/server/database/Database/DatabaseWorkerPool.cpp +++ b/src/server/database/Database/DatabaseWorkerPool.cpp @@ -17,6 +17,7 @@ #include "DatabaseWorkerPool.h" #include "DatabaseEnv.h" +#include "QueryCallback.h" #define MIN_MYSQL_SERVER_VERSION 50100u #define MIN_MYSQL_CLIENT_VERSION 50100u @@ -146,23 +147,23 @@ PreparedQueryResult DatabaseWorkerPool<T>::Query(PreparedStatement* stmt) } template <class T> -QueryResultFuture DatabaseWorkerPool<T>::AsyncQuery(const char* sql) +QueryCallback DatabaseWorkerPool<T>::AsyncQuery(const char* sql) { BasicStatementTask* task = new BasicStatementTask(sql, true); // Store future result before enqueueing - task might get already processed and deleted before returning from this method QueryResultFuture result = task->GetFuture(); Enqueue(task); - return result; + return QueryCallback(std::move(result)); } template <class T> -PreparedQueryResultFuture DatabaseWorkerPool<T>::AsyncQuery(PreparedStatement* stmt) +QueryCallback DatabaseWorkerPool<T>::AsyncQuery(PreparedStatement* stmt) { PreparedStatementTask* task = new PreparedStatementTask(stmt, true); // Store future result before enqueueing - task might get already processed and deleted before returning from this method PreparedQueryResultFuture result = task->GetFuture(); Enqueue(task); - return result; + return QueryCallback(std::move(result)); } template <class T> diff --git a/src/server/database/Database/DatabaseWorkerPool.h b/src/server/database/Database/DatabaseWorkerPool.h index a082a9b6b0e..b195d2d6a28 100644 --- a/src/server/database/Database/DatabaseWorkerPool.h +++ b/src/server/database/Database/DatabaseWorkerPool.h @@ -19,7 +19,6 @@ #define _DATABASEWORKERPOOL_H #include "Common.h" -#include "QueryCallback.h" #include "MySQLConnection.h" #include "Transaction.h" #include "DatabaseWorker.h" @@ -34,6 +33,8 @@ #include <memory> #include <array> +class QueryCallback; + class PingOperation : public SQLOperation { //! Operation for idle delaythreads @@ -192,12 +193,12 @@ class DatabaseWorkerPool //! Enqueues a query in string format that will set the value of the QueryResultFuture return object as soon as the query is executed. //! The return value is then processed in ProcessQueryCallback methods. - QueryResultFuture AsyncQuery(const char* sql); + QueryCallback AsyncQuery(const char* sql); //! Enqueues a query in string format -with variable args- that will set the value of the QueryResultFuture return object as soon as the query is executed. //! The return value is then processed in ProcessQueryCallback methods. template<typename Format, typename... Args> - QueryResultFuture AsyncPQuery(Format&& sql, Args&&... args) + QueryCallback AsyncPQuery(Format&& sql, Args&&... args) { return AsyncQuery(Trinity::StringFormat(std::forward<Format>(sql), std::forward<Args>(args)...).c_str()); } @@ -205,7 +206,7 @@ class DatabaseWorkerPool //! Enqueues a query in prepared format that will set the value of the PreparedQueryResultFuture return object as soon as the query is executed. //! The return value is then processed in ProcessQueryCallback methods. //! Statement must be prepared with CONNECTION_ASYNC flag. - PreparedQueryResultFuture AsyncQuery(PreparedStatement* stmt); + QueryCallback AsyncQuery(PreparedStatement* stmt); //! Enqueues a vector of SQL operations (can be both adhoc and prepared) that will set the value of the QueryResultHolderFuture //! return object as soon as the query is executed. diff --git a/src/server/database/Database/QueryCallback.cpp b/src/server/database/Database/QueryCallback.cpp index f88ad7a6e47..8850f87b20a 100644 --- a/src/server/database/Database/QueryCallback.cpp +++ b/src/server/database/Database/QueryCallback.cpp @@ -18,115 +18,186 @@ #include "QueryCallback.h" template<typename T> +inline void Construct(T& t) +{ + new (&t) T(); +} + +template<typename T> inline void Destroy(T& t) { t.~T(); } template<typename T> -void DestroyActiveMember(T& obj) +void ConstructActiveMember(T* obj) +{ + if (!obj->_isPrepared) + Construct(obj->_string); + else + Construct(obj->_prepared); +} + +template<typename T> +void DestroyActiveMember(T* obj) { - if (!obj._isPrepared) - Destroy(obj._string); + if (!obj->_isPrepared) + Destroy(obj->_string); else - Destroy(obj._prepared); + Destroy(obj->_prepared); } template<typename T> -void MoveFrom(T& to, T&& from) +void MoveFrom(T* to, T&& from) { - DestroyActiveMember(to); - to._isPrepared = from._isPrepared; - if (!to._isPrepared) - to._string = std::move(from._string); + ASSERT(to->_isPrepared == from._isPrepared); + + if (!to->_isPrepared) + to->_string = std::move(from._string); else - to._prepared = std::move(from._prepared); + to->_prepared = std::move(from._prepared); } -struct QueryCallbackNew::QueryCallbackData +struct QueryCallback::QueryCallbackData { public: - friend class QueryCallbackNew; + friend class QueryCallback; - QueryCallbackData(std::function<void(QueryResult)>&& callback) : _string(std::move(callback)), _isPrepared(false) { } - QueryCallbackData(std::function<void(PreparedQueryResult)>&& callback) : _prepared(std::move(callback)), _isPrepared(true) { } - QueryCallbackData(QueryCallbackData&& right) { MoveFrom(*this, std::move(right)); } - QueryCallbackData& operator=(QueryCallbackData&& right) { MoveFrom(*this, std::move(right)); return *this; } - ~QueryCallbackData() { DestroyActiveMember(*this); } + QueryCallbackData(std::function<void(QueryCallback&, QueryResult)>&& callback) : _string(std::move(callback)), _isPrepared(false) { TC_LOG_ERROR(LOGGER_ROOT, "QueryCallbackData [%p]: Constructing from string query", (void*)this); } + QueryCallbackData(std::function<void(QueryCallback&, PreparedQueryResult)>&& callback) : _prepared(std::move(callback)), _isPrepared(true) { TC_LOG_ERROR(LOGGER_ROOT, "QueryCallbackData [%p]: Constructing from prepared query", (void*)this); } + QueryCallbackData(QueryCallbackData&& right) + { + _isPrepared = right._isPrepared; + ConstructActiveMember(this); + MoveFrom(this, std::move(right)); + } + QueryCallbackData& operator=(QueryCallbackData&& right) + { + if (this != &right) + { + if (_isPrepared != right._isPrepared) + { + DestroyActiveMember(this); + _isPrepared = right._isPrepared; + ConstructActiveMember(this); + } + MoveFrom(this, std::move(right)); + } + return *this; + } + ~QueryCallbackData() { DestroyActiveMember(this); } private: QueryCallbackData(QueryCallbackData const&) = delete; QueryCallbackData& operator=(QueryCallbackData const&) = delete; - template<typename T> friend void MoveFrom(T& to, T&& from); - template<typename T> friend void DestroyActiveMember(T& obj); + template<typename T> friend void ConstructActiveMember(T* obj); + template<typename T> friend void DestroyActiveMember(T* obj); + template<typename T> friend void MoveFrom(T* to, T&& from); union { - std::function<void(QueryResult)> _string; - std::function<void(PreparedQueryResult)> _prepared; + std::function<void(QueryCallback&, QueryResult)> _string; + std::function<void(QueryCallback&, PreparedQueryResult)> _prepared; }; bool _isPrepared; }; -QueryCallbackNew::QueryCallbackNew(std::future<QueryResult>&& result) : _string(std::move(result)), _isPrepared(false) +QueryCallback::QueryCallback(std::future<QueryResult>&& result) : _string(std::move(result)), _isPrepared(false) { } -QueryCallbackNew::QueryCallbackNew(std::future<PreparedQueryResult>&& result) : _prepared(std::move(result)), _isPrepared(true) +QueryCallback::QueryCallback(std::future<PreparedQueryResult>&& result) : _prepared(std::move(result)), _isPrepared(true) { } -QueryCallbackNew::QueryCallbackNew(QueryCallbackNew&& right) +QueryCallback::QueryCallback(QueryCallback&& right) { - MoveFrom(*this, std::move(right)); + _isPrepared = right._isPrepared; + ConstructActiveMember(this); + MoveFrom(this, std::move(right)); _callbacks = std::move(right._callbacks); } -QueryCallbackNew& QueryCallbackNew::operator=(QueryCallbackNew&& right) +QueryCallback& QueryCallback::operator=(QueryCallback&& right) { - MoveFrom(*this, std::move(right)); - _callbacks = std::move(right._callbacks); + if (this != &right) + { + if (_isPrepared != right._isPrepared) + { + DestroyActiveMember(this); + _isPrepared = right._isPrepared; + ConstructActiveMember(this); + } + MoveFrom(this, std::move(right)); + _callbacks = std::move(right._callbacks); + } return *this; } -QueryCallbackNew::~QueryCallbackNew() +QueryCallback::~QueryCallback() { - DestroyActiveMember(*this); + DestroyActiveMember(this); } -QueryCallbackNew&& QueryCallbackNew::WithCallback(std::function<void(QueryResult)>&& callback) +QueryCallback&& QueryCallback::WithCallback(std::function<void(QueryResult)>&& callback) +{ + return WithChainingCallback([callback](QueryCallback& /*this*/, QueryResult result) { callback(std::move(result)); }); +} + +QueryCallback&& QueryCallback::WithPreparedCallback(std::function<void(PreparedQueryResult)>&& callback) +{ + return WithChainingPreparedCallback([callback](QueryCallback& /*this*/, PreparedQueryResult result) { callback(std::move(result)); }); +} + +QueryCallback&& QueryCallback::WithChainingCallback(std::function<void(QueryCallback&, QueryResult)>&& callback) { ASSERT(!_callbacks.empty() || !_isPrepared, "Attempted to set callback function for string query on a prepared async query"); _callbacks.emplace(std::move(callback)); return std::move(*this); } -QueryCallbackNew&& QueryCallbackNew::WithPreparedCallback(std::function<void(PreparedQueryResult)>&& callback) +QueryCallback&& QueryCallback::WithChainingPreparedCallback(std::function<void(QueryCallback&, PreparedQueryResult)>&& callback) { ASSERT(!_callbacks.empty() || _isPrepared, "Attempted to set callback function for prepared query on a string async query"); _callbacks.emplace(std::move(callback)); return std::move(*this); } -QueryCallbackNew::Status QueryCallbackNew::InvokeIfReady() +void QueryCallback::SetNextQuery(QueryCallback&& next) +{ + MoveFrom(this, std::move(next)); +} + +QueryCallback::Status QueryCallback::InvokeIfReady() { QueryCallbackData& callback = _callbacks.front(); + auto checkStateAndReturnCompletion = [this]() + { + _callbacks.pop(); + bool hasNext = !_isPrepared ? _string.valid() : _prepared.valid(); + if (_callbacks.empty()) + { + ASSERT(!hasNext); + return Completed; + } + + // abort chain + if (!hasNext) + return Completed; + + ASSERT(_isPrepared == _callbacks.front()._isPrepared); + return NextStep; + }; + if (!_isPrepared) { if (_string.valid() && _string.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { - std::function<void(QueryResult)> cb(std::move(callback._string)); - cb(_string.get()); - _callbacks.pop(); - if (_callbacks.empty()) - { - ASSERT(!_isPrepared ? !_string.valid() : !_prepared.valid()); - return Completed; - } - - ASSERT(_isPrepared == _callbacks.front()._isPrepared); - return NextStep; + std::future<QueryResult> f(std::move(_string)); + std::function<void(QueryCallback&, QueryResult)> cb(std::move(callback._string)); + cb(*this, f.get()); + return checkStateAndReturnCompletion(); } } else @@ -134,17 +205,9 @@ QueryCallbackNew::Status QueryCallbackNew::InvokeIfReady() if (_prepared.valid() && _prepared.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { std::future<PreparedQueryResult> f(std::move(_prepared)); - std::function<void(PreparedQueryResult)> cb(std::move(callback._prepared)); - cb(_prepared.get()); - _callbacks.pop(); - if (_callbacks.empty()) - { - ASSERT(!_isPrepared ? !_string.valid() : !_prepared.valid()); - return Completed; - } - - ASSERT(_isPrepared == _callbacks.front()._isPrepared); - return NextStep; + std::function<void(QueryCallback&, PreparedQueryResult)> cb(std::move(callback._prepared)); + cb(*this, f.get()); + return checkStateAndReturnCompletion(); } } diff --git a/src/server/database/Database/QueryCallback.h b/src/server/database/Database/QueryCallback.h index 6c4a8a81b4e..f9c93000da7 100644 --- a/src/server/database/Database/QueryCallback.h +++ b/src/server/database/Database/QueryCallback.h @@ -18,27 +18,26 @@ #ifndef _QUERY_CALLBACK_H #define _QUERY_CALLBACK_H -#include <future> #include "QueryResult.h" +#include <future> -typedef std::future<QueryResult> QueryResultFuture; -typedef std::promise<QueryResult> QueryResultPromise; -typedef std::future<PreparedQueryResult> PreparedQueryResultFuture; -typedef std::promise<PreparedQueryResult> PreparedQueryResultPromise; - -#define CALLBACK_STAGE_INVALID uint8(-1) - -class TC_DATABASE_API QueryCallbackNew +class TC_DATABASE_API QueryCallback { public: - explicit QueryCallbackNew(std::future<QueryResult>&& result); - explicit QueryCallbackNew(std::future<PreparedQueryResult>&& result); - QueryCallbackNew(QueryCallbackNew&& right); - QueryCallbackNew& operator=(QueryCallbackNew&& right); - ~QueryCallbackNew(); + explicit QueryCallback(std::future<QueryResult>&& result); + explicit QueryCallback(std::future<PreparedQueryResult>&& result); + QueryCallback(QueryCallback&& right); + QueryCallback& operator=(QueryCallback&& right); + ~QueryCallback(); + + QueryCallback&& WithCallback(std::function<void(QueryResult)>&& callback); + QueryCallback&& WithPreparedCallback(std::function<void(PreparedQueryResult)>&& callback); + + QueryCallback&& WithChainingCallback(std::function<void(QueryCallback&, QueryResult)>&& callback); + QueryCallback&& WithChainingPreparedCallback(std::function<void(QueryCallback&, PreparedQueryResult)>&& callback); - QueryCallbackNew&& WithCallback(std::function<void(QueryResult)>&& callback); - QueryCallbackNew&& WithPreparedCallback(std::function<void(PreparedQueryResult)>&& callback); + // Moves std::future from next to this object + void SetNextQuery(QueryCallback&& next); enum Status { @@ -50,11 +49,12 @@ public: Status InvokeIfReady(); private: - QueryCallbackNew(QueryCallbackNew const& right) = delete; - QueryCallbackNew& operator=(QueryCallbackNew const& right) = delete; + QueryCallback(QueryCallback const& right) = delete; + QueryCallback& operator=(QueryCallback const& right) = delete; - template<typename T> friend void MoveFrom(T& to, T&& from); - template<typename T> friend void DestroyActiveMember(T& obj); + template<typename T> friend void ConstructActiveMember(T* obj); + template<typename T> friend void DestroyActiveMember(T* obj); + template<typename T> friend void MoveFrom(T* to, T&& from); union { @@ -67,182 +67,4 @@ private: std::queue<QueryCallbackData, std::list<QueryCallbackData>> _callbacks; }; -template <typename Result, typename ParamType, bool chain = false> -class QueryCallback -{ - public: - QueryCallback() : _param(), _stage(chain ? 0 : CALLBACK_STAGE_INVALID) { } - - //! The parameter of this function should be a resultset returned from either .AsyncQuery or .AsyncPQuery - void SetFutureResult(std::future<Result> value) - { - _result = std::move(value); - } - - std::future<Result>& GetFutureResult() - { - return _result; - } - - bool IsReady() - { - return _result.valid() && _result.wait_for(std::chrono::seconds(0)) == std::future_status::ready; - } - - void GetResult(Result& res) - { - res = _result.get(); - } - - void FreeResult() - { - // Nothing to do here, the constructor of std::future will take care of the cleanup - } - - void SetParam(ParamType value) - { - _param = value; - } - - ParamType GetParam() - { - return _param; - } - - //! Resets the stage of the callback chain - void ResetStage() - { - if (!chain) - return; - - _stage = 0; - } - - //! Advances the callback chain to the next stage, so upper level code can act on its results accordingly - void NextStage() - { - if (!chain) - return; - - ++_stage; - } - - //! Returns the callback stage (or CALLBACK_STAGE_INVALID if invalid) - uint8 GetStage() - { - return _stage; - } - - //! Resets all underlying variables (param, result and stage) - void Reset() - { - SetParam(ParamType()); - FreeResult(); - ResetStage(); - } - - private: - std::future<Result> _result; - ParamType _param; - uint8 _stage; - - QueryCallback(QueryCallback const& right) = delete; - QueryCallback& operator=(QueryCallback const& right) = delete; -}; - -template <typename Result, typename ParamType1, typename ParamType2, bool chain = false> -class QueryCallback_2 -{ - public: - QueryCallback_2() : _stage(chain ? 0 : CALLBACK_STAGE_INVALID) { } - - //! The parameter of this function should be a resultset returned from either .AsyncQuery or .AsyncPQuery - void SetFutureResult(std::future<Result> value) - { - _result = std::move(value); - } - - std::future<Result>& GetFutureResult() - { - return _result; - } - - bool IsReady() - { - return _result.valid() && _result.wait_for(std::chrono::seconds(0)) == std::future_status::ready; - } - - void GetResult(Result& res) - { - res = _result.get(); - } - - void FreeResult() - { - // Nothing to do here, the constructor of std::future will take care of the cleanup - } - - void SetFirstParam(ParamType1 value) - { - _param_1 = value; - } - - void SetSecondParam(ParamType2 value) - { - _param_2 = value; - } - - ParamType1 GetFirstParam() - { - return _param_1; - } - - ParamType2 GetSecondParam() - { - return _param_2; - } - - //! Resets the stage of the callback chain - void ResetStage() - { - if (!chain) - return; - - _stage = 0; - } - - //! Advances the callback chain to the next stage, so upper level code can act on its results accordingly - void NextStage() - { - if (!chain) - return; - - ++_stage; - } - - //! Returns the callback stage (or CALLBACK_STAGE_INVALID if invalid) - uint8 GetStage() - { - return _stage; - } - - //! Resets all underlying variables (param, result and stage) - void Reset() - { - SetFirstParam(NULL); - SetSecondParam(NULL); - FreeResult(); - ResetStage(); - } - - private: - std::future<Result> _result; - ParamType1 _param_1; - ParamType2 _param_2; - uint8 _stage; - - QueryCallback_2(QueryCallback_2 const& right) = delete; - QueryCallback_2& operator=(QueryCallback_2 const& right) = delete; -}; - #endif // _QUERY_CALLBACK_H diff --git a/src/server/database/Database/QueryCallbackProcessor.cpp b/src/server/database/Database/QueryCallbackProcessor.cpp index 0eaa1c2352c..9f8b8fc4ad9 100644 --- a/src/server/database/Database/QueryCallbackProcessor.cpp +++ b/src/server/database/Database/QueryCallbackProcessor.cpp @@ -27,15 +27,22 @@ QueryCallbackProcessor::~QueryCallbackProcessor() { } -void QueryCallbackProcessor::AddQuery(QueryCallbackNew&& query) +void QueryCallbackProcessor::AddQuery(QueryCallback&& query) { _callbacks.emplace_back(std::move(query)); } void QueryCallbackProcessor::ProcessReadyQueries() { - _callbacks.erase(std::remove_if(_callbacks.begin(), _callbacks.end(), [](QueryCallbackNew& callback) + if (_callbacks.empty()) + return; + + std::vector<QueryCallback> updateCallbacks{ std::move(_callbacks) }; + + updateCallbacks.erase(std::remove_if(updateCallbacks.begin(), updateCallbacks.end(), [](QueryCallback& callback) { - return callback.InvokeIfReady() == QueryCallbackNew::Completed; - }), _callbacks.end()); + return callback.InvokeIfReady() == QueryCallback::Completed; + }), updateCallbacks.end()); + + _callbacks.insert(_callbacks.end(), std::make_move_iterator(updateCallbacks.begin()), std::make_move_iterator(updateCallbacks.end())); } diff --git a/src/server/database/Database/QueryCallbackProcessor.h b/src/server/database/Database/QueryCallbackProcessor.h index 08ae3d15693..0b06fd8fc27 100644 --- a/src/server/database/Database/QueryCallbackProcessor.h +++ b/src/server/database/Database/QueryCallbackProcessor.h @@ -21,7 +21,7 @@ #include "Define.h" #include <vector> -class QueryCallbackNew; +class QueryCallback; class TC_DATABASE_API QueryCallbackProcessor { @@ -29,14 +29,14 @@ public: QueryCallbackProcessor(); ~QueryCallbackProcessor(); - void AddQuery(QueryCallbackNew&& query); + void AddQuery(QueryCallback&& query); void ProcessReadyQueries(); private: QueryCallbackProcessor(QueryCallbackProcessor const&) = delete; QueryCallbackProcessor& operator=(QueryCallbackProcessor const&) = delete; - std::vector<QueryCallbackNew> _callbacks; + std::vector<QueryCallback> _callbacks; }; #endif // QueryCallbackProcessor_h__ diff --git a/src/server/game/Accounts/RBAC.cpp b/src/server/game/Accounts/RBAC.cpp index 378a66aa989..951223a9257 100644 --- a/src/server/game/Accounts/RBAC.cpp +++ b/src/server/game/Accounts/RBAC.cpp @@ -18,6 +18,7 @@ #include "RBAC.h" #include "AccountMgr.h" #include "Log.h" +#include "QueryCallback.h" namespace rbac { @@ -182,7 +183,7 @@ void RBACData::LoadFromDB() LoadFromDBCallback(LoginDatabase.Query(stmt)); } -PreparedQueryResultFuture RBACData::LoadFromDBAsync() +QueryCallback RBACData::LoadFromDBAsync() { ClearData(); diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 597f2a9fd24..a053a9e86bf 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -923,7 +923,7 @@ class TC_GAME_API RBACData /// Loads all permissions assigned to current account void LoadFromDB(); - PreparedQueryResultFuture LoadFromDBAsync(); + QueryCallback LoadFromDBAsync(); void LoadFromDBCallback(PreparedQueryResult result); /// Sets security level 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) diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index 0283bb826f2..69e31d9f59f 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -19,6 +19,7 @@ #include "Common.h" #include "Language.h" #include "DatabaseEnv.h" +#include "QueryCallback.h" #include "WorldPacket.h" #include "WorldSession.h" #include "Opcodes.h" @@ -485,11 +486,10 @@ void WorldSession::SendStablePet(ObjectGuid guid) stmt->setUInt8(1, PET_SAVE_FIRST_STABLE_SLOT); stmt->setUInt8(2, PET_SAVE_LAST_STABLE_SLOT); - _sendStabledPetCallback.SetParam(guid); - _sendStabledPetCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); + _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::SendStablePetCallback, this, guid, std::placeholders::_1))); } -void WorldSession::SendStablePetCallback(PreparedQueryResult result, ObjectGuid guid) +void WorldSession::SendStablePetCallback(ObjectGuid guid, PreparedQueryResult result) { if (!GetPlayer()) return; @@ -585,7 +585,7 @@ void WorldSession::HandleStablePet(WorldPacket& recvData) stmt->setUInt8(1, PET_SAVE_FIRST_STABLE_SLOT); stmt->setUInt8(2, PET_SAVE_LAST_STABLE_SLOT); - _stablePetCallback = CharacterDatabase.AsyncQuery(stmt); + _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleStablePetCallback, this, std::placeholders::_1))); } void WorldSession::HandleStablePetCallback(PreparedQueryResult result) @@ -645,11 +645,10 @@ void WorldSession::HandleUnstablePet(WorldPacket& recvData) stmt->setUInt8(2, PET_SAVE_FIRST_STABLE_SLOT); stmt->setUInt8(3, PET_SAVE_LAST_STABLE_SLOT); - _unstablePetCallback.SetParam(petnumber); - _unstablePetCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); + _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleUnstablePetCallback, this, petnumber, std::placeholders::_1))); } -void WorldSession::HandleUnstablePetCallback(PreparedQueryResult result, uint32 petId) +void WorldSession::HandleUnstablePetCallback(uint32 petId, PreparedQueryResult result) { if (!GetPlayer()) return; @@ -770,11 +769,10 @@ void WorldSession::HandleStableSwapPet(WorldPacket& recvData) stmt->setUInt64(0, _player->GetGUID().GetCounter()); stmt->setUInt32(1, petId); - _stableSwapCallback.SetParam(petId); - _stableSwapCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); + _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleStableSwapPetCallback, this, petId, std::placeholders::_1))); } -void WorldSession::HandleStableSwapPetCallback(PreparedQueryResult result, uint32 petId) +void WorldSession::HandleStableSwapPetCallback(uint32 petId, PreparedQueryResult result) { if (!GetPlayer()) return; diff --git a/src/server/game/Handlers/SocialHandler.cpp b/src/server/game/Handlers/SocialHandler.cpp index 0c87093bb90..3989e76e56a 100644 --- a/src/server/game/Handlers/SocialHandler.cpp +++ b/src/server/game/Handlers/SocialHandler.cpp @@ -18,6 +18,7 @@ #include "WorldSession.h" #include "Player.h" +#include "QueryCallback.h" #include "SocialMgr.h" #include "SocialPackets.h" #include "ObjectMgr.h" @@ -39,11 +40,11 @@ void WorldSession::HandleAddFriendOpcode(WorldPackets::Social::AddFriend& packet PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUID_RACE_ACC_BY_NAME); stmt->setString(0, packet.Name); - _addFriendCallback.SetParam(std::move(packet.Notes)); - _addFriendCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); + _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt) + .WithPreparedCallback(std::bind(&WorldSession::HandleAddFriendOpcodeCallBack, this, std::move(packet.Notes), std::placeholders::_1))); } -void WorldSession::HandleAddFriendOpcodeCallBack(PreparedQueryResult result, std::string const& friendNote) +void WorldSession::HandleAddFriendOpcodeCallBack(std::string const& friendNote, PreparedQueryResult result) { if (!GetPlayer()) return; @@ -110,7 +111,7 @@ void WorldSession::HandleAddIgnoreOpcode(WorldPackets::Social::AddIgnore& packet PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUID_BY_NAME); stmt->setString(0, packet.Name); - _addIgnoreCallback = CharacterDatabase.AsyncQuery(stmt); + _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleAddIgnoreOpcodeCallBack, this, std::placeholders::_1))); } void WorldSession::HandleAddIgnoreOpcodeCallBack(PreparedQueryResult result) diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 070f75f3392..c9daf2a274f 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -24,6 +24,7 @@ #include "Config.h" #include "Common.h" #include "DatabaseEnv.h" +#include "QueryCallback.h" #include "AccountMgr.h" #include "Log.h" #include "Opcodes.h" @@ -151,8 +152,6 @@ WorldSession::WorldSession(uint32 id, std::string&& name, uint32 battlenetAccoun m_Socket[CONNECTION_TYPE_REALM] = sock; _instanceConnectKey.Raw = UI64LIT(0); - - InitializeQueryCallbackParameters(); } /// WorldSession destructor @@ -863,135 +862,17 @@ void WorldSession::SetPlayer(Player* player) m_GUIDLow = _player->GetGUID().GetCounter(); } -void WorldSession::InitializeQueryCallbackParameters() -{ - // Callback parameters that have pointers in them should be properly - // initialized to nullptr here. -} - void WorldSession::ProcessQueryCallbacks() { - PreparedQueryResult result; + _queryProcessor.ProcessReadyQueries(); if (_realmAccountLoginCallback.valid() && _realmAccountLoginCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready && _accountLoginCallback.valid() && _accountLoginCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready) InitializeSessionCallback(_realmAccountLoginCallback.get(), _accountLoginCallback.get()); - //! HandleCharEnumOpcode and HandleCharUndeleteEnumOpcode - if (_charEnumCallback.IsReady()) - { - _charEnumCallback.GetResult(result); - - if (_charEnumCallback.GetParam()) - HandleCharUndeleteEnum(result); - else - HandleCharEnum(result); - - _charEnumCallback.FreeResult(); - } - - //! HandleCharCreateOpcode - if (_charCreateCallback.IsReady()) - { - _charCreateCallback.GetResult(result); - HandleCharCreateCallback(result, _charCreateCallback.GetParam().get()); - } - - //! HandleCharCustomizeOpcode - if (_charCustomizeCallback.IsReady()) - { - _charCustomizeCallback.GetResult(result); - HandleCharCustomizeCallback(result, _charCustomizeCallback.GetParam().get()); - _charCustomizeCallback.Reset(); - } - - //! HandleCharRaceOrFactionChangeOpcode - if (_charFactionChangeCallback.IsReady()) - { - _charFactionChangeCallback.GetResult(result); - HandleCharRaceOrFactionChangeCallback(result, _charFactionChangeCallback.GetParam().get()); - _charFactionChangeCallback.Reset(); - } - //! HandlePlayerLoginOpcode if (_charLoginCallback.valid() && _charLoginCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready) - { - SQLQueryHolder* param = _charLoginCallback.get(); - HandlePlayerLogin((LoginQueryHolder*)param); - } - - //! HandleAddFriendOpcode - if (_addFriendCallback.IsReady()) - { - std::string param = _addFriendCallback.GetParam(); - _addFriendCallback.GetResult(result); - HandleAddFriendOpcodeCallBack(result, param); - _addFriendCallback.FreeResult(); - } - - //- HandleCharRenameOpcode - if (_charRenameCallback.IsReady()) - { - _charRenameCallback.GetResult(result); - HandleCharRenameCallBack(result, _charRenameCallback.GetParam().get()); - _charRenameCallback.Reset(); - } - - /// HandleUndeleteCooldownStatusOpcode - /// wait until no char undelete is in progress - if (!_charUndeleteCallback.GetStage() && _undeleteCooldownStatusCallback.IsReady()) - { - _undeleteCooldownStatusCallback.GetResult(result); - HandleUndeleteCooldownStatusCallback(result); - } - - /// HandleCharUndeleteOpcode - if (_charUndeleteCallback.IsReady()) - { - _charUndeleteCallback.GetResult(result); - HandleCharUndeleteCallback(result, _charUndeleteCallback.GetParam().get()); - } - - //- HandleCharAddIgnoreOpcode - if (_addIgnoreCallback.valid() && _addIgnoreCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready) - { - result = _addIgnoreCallback.get(); - HandleAddIgnoreOpcodeCallBack(result); - } - - //- SendStabledPet - if (_sendStabledPetCallback.IsReady()) - { - ObjectGuid param = _sendStabledPetCallback.GetParam(); - _sendStabledPetCallback.GetResult(result); - SendStablePetCallback(result, param); - _sendStabledPetCallback.FreeResult(); - } - - //- HandleStablePet - if (_stablePetCallback.valid() && _stablePetCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready) - { - result = _stablePetCallback.get(); - HandleStablePetCallback(result); - } - - //- HandleUnstablePet - if (_unstablePetCallback.IsReady()) - { - uint32 param = _unstablePetCallback.GetParam(); - _unstablePetCallback.GetResult(result); - HandleUnstablePetCallback(result, param); - _unstablePetCallback.FreeResult(); - } - - //- HandleStableSwapPet - if (_stableSwapCallback.IsReady()) - { - uint32 param = _stableSwapCallback.GetParam(); - _stableSwapCallback.GetResult(result); - HandleStableSwapPetCallback(result, param); - _stableSwapCallback.FreeResult(); - } + HandlePlayerLogin(reinterpret_cast<LoginQueryHolder*>(_charLoginCallback.get())); } void WorldSession::InitWarden(BigNumber* k) @@ -1023,7 +904,7 @@ void WorldSession::LoadPermissions() _RBACData->LoadFromDB(); } -PreparedQueryResultFuture WorldSession::LoadPermissionsAsync() +QueryCallback WorldSession::LoadPermissionsAsync() { uint32 id = GetAccountId(); uint8 secLevel = GetSecurity(); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index bdd0e44bcf7..dd5c32133c3 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -938,7 +938,7 @@ class TC_GAME_API WorldSession rbac::RBACData* GetRBACData(); bool HasPermission(uint32 permissionId); void LoadPermissions(); - PreparedQueryResultFuture LoadPermissionsAsync(); + QueryCallback LoadPermissionsAsync(); void InvalidateRBACData(); // Used to force LoadPermissions at next HasPermission check AccountTypes GetSecurity() const { return _security; } @@ -1013,7 +1013,7 @@ class TC_GAME_API WorldSession // Pet void SendQueryPetNameResponse(ObjectGuid guid); void SendStablePet(ObjectGuid guid); - void SendStablePetCallback(PreparedQueryResult result, ObjectGuid guid); + void SendStablePetCallback(ObjectGuid guid, PreparedQueryResult result); void SendPetStableResult(uint8 guid); bool CheckStableMaster(ObjectGuid guid); @@ -1129,29 +1129,27 @@ class TC_GAME_API WorldSession void HandleCharUndeleteEnumOpcode(WorldPackets::Character::EnumCharacters& /*enumCharacters*/); void HandleCharDeleteOpcode(WorldPackets::Character::CharDelete& charDelete); void HandleCharCreateOpcode(WorldPackets::Character::CreateCharacter& charCreate); - void HandleCharCreateCallback(PreparedQueryResult result, WorldPackets::Character::CharacterCreateInfo* createInfo); void HandlePlayerLoginOpcode(WorldPackets::Character::PlayerLogin& playerLogin); void SendConnectToInstance(WorldPackets::Auth::ConnectToSerial serial); void HandleContinuePlayerLogin(); void AbortLogin(WorldPackets::Character::LoginFailureReason reason); void HandleLoadScreenOpcode(WorldPackets::Character::LoadingScreenNotify& loadingScreenNotify); - void HandlePlayerLogin(LoginQueryHolder * holder); + void HandlePlayerLogin(LoginQueryHolder* holder); void HandleCharRenameOpcode(WorldPackets::Character::CharacterRenameRequest& request); - void HandleCharRenameCallBack(PreparedQueryResult result, WorldPackets::Character::CharacterRenameInfo* renameInfo); + void HandleCharRenameCallBack(std::shared_ptr<WorldPackets::Character::CharacterRenameInfo> renameInfo, PreparedQueryResult result); void HandleSetPlayerDeclinedNames(WorldPackets::Character::SetPlayerDeclinedNames& packet); void HandleAlterAppearance(WorldPackets::Character::AlterApperance& packet); void HandleCharCustomizeOpcode(WorldPackets::Character::CharCustomize& packet); - void HandleCharCustomizeCallback(PreparedQueryResult result, WorldPackets::Character::CharCustomizeInfo* customizeInfo); + void HandleCharCustomizeCallback(std::shared_ptr<WorldPackets::Character::CharCustomizeInfo> customizeInfo, PreparedQueryResult result); void HandleCharRaceOrFactionChangeOpcode(WorldPackets::Character::CharRaceOrFactionChange& packet); - void HandleCharRaceOrFactionChangeCallback(PreparedQueryResult result, WorldPackets::Character::CharRaceOrFactionChangeInfo* factionChangeInfo); + void HandleCharRaceOrFactionChangeCallback(std::shared_ptr<WorldPackets::Character::CharRaceOrFactionChangeInfo> factionChangeInfo, PreparedQueryResult result); void HandleRandomizeCharNameOpcode(WorldPackets::Character::GenerateRandomCharacterName& packet); void HandleReorderCharacters(WorldPackets::Character::ReorderCharacters& reorderChars); void HandleOpeningCinematic(WorldPackets::Misc::OpeningCinematic& packet); void HandleGetUndeleteCooldownStatus(WorldPackets::Character::GetUndeleteCharacterCooldownStatus& /*getCooldown*/); void HandleUndeleteCooldownStatusCallback(PreparedQueryResult result); void HandleCharUndeleteOpcode(WorldPackets::Character::UndeleteCharacter& undeleteInfo); - void HandleCharUndeleteCallback(PreparedQueryResult result, WorldPackets::Character::CharacterUndeleteInfo* undeleteInfo); void SendCharCreate(ResponseCodes result); void SendCharDelete(ResponseCodes result); @@ -1223,7 +1221,7 @@ class TC_GAME_API WorldSession // Social void HandleContactListOpcode(WorldPackets::Social::SendContactList& packet); void HandleAddFriendOpcode(WorldPackets::Social::AddFriend& packet); - void HandleAddFriendOpcodeCallBack(PreparedQueryResult result, std::string const& friendNote); + void HandleAddFriendOpcodeCallBack(std::string const& friendNote, PreparedQueryResult result); void HandleDelFriendOpcode(WorldPackets::Social::DelFriend& packet); void HandleAddIgnoreOpcode(WorldPackets::Social::AddIgnore& packet); void HandleAddIgnoreOpcodeCallBack(PreparedQueryResult result); @@ -1369,11 +1367,11 @@ class TC_GAME_API WorldSession void HandleStablePet(WorldPacket& recvPacket); void HandleStablePetCallback(PreparedQueryResult result); void HandleUnstablePet(WorldPacket& recvPacket); - void HandleUnstablePetCallback(PreparedQueryResult result, uint32 petId); + void HandleUnstablePetCallback(uint32 petId, PreparedQueryResult result); void HandleBuyStableSlot(WorldPacket& recvPacket); void HandleStableRevivePet(WorldPacket& recvPacket); void HandleStableSwapPet(WorldPacket& recvPacket); - void HandleStableSwapPetCallback(PreparedQueryResult result, uint32 petId); + void HandleStableSwapPetCallback(uint32 petId, PreparedQueryResult result); void SendTrainerBuyFailed(ObjectGuid trainerGUID, uint32 spellID, int32 trainerFailedReason); void HandleCanDuel(WorldPackets::Duel::CanDuel& packet); @@ -1763,26 +1761,14 @@ class TC_GAME_API WorldSession uint64 GetConnectToInstanceKey() const { return _instanceConnectKey.Raw; } private: - void InitializeQueryCallbackParameters(); void ProcessQueryCallbacks(); QueryResultHolderFuture _realmAccountLoginCallback; QueryResultHolderFuture _accountLoginCallback; - PreparedQueryResultFuture _addIgnoreCallback; - PreparedQueryResultFuture _stablePetCallback; - QueryCallback<PreparedQueryResult, bool> _charEnumCallback; - QueryCallback<PreparedQueryResult, std::string> _addFriendCallback; - QueryCallback<PreparedQueryResult, uint32> _unstablePetCallback; - QueryCallback<PreparedQueryResult, uint32> _stableSwapCallback; - QueryCallback<PreparedQueryResult, ObjectGuid> _sendStabledPetCallback; - QueryCallback<PreparedQueryResult, std::shared_ptr<WorldPackets::Character::CharacterCreateInfo>, true> _charCreateCallback; - QueryCallback<PreparedQueryResult, std::shared_ptr<WorldPackets::Character::CharacterRenameInfo>> _charRenameCallback; - QueryCallback<PreparedQueryResult, std::shared_ptr<WorldPackets::Character::CharCustomizeInfo>> _charCustomizeCallback; - QueryCallback<PreparedQueryResult, std::shared_ptr<WorldPackets::Character::CharRaceOrFactionChangeInfo>> _charFactionChangeCallback; - QueryCallback<PreparedQueryResult, bool, true> _undeleteCooldownStatusCallback; - QueryCallback<PreparedQueryResult, std::shared_ptr<WorldPackets::Character::CharacterUndeleteInfo>, true> _charUndeleteCallback; QueryResultHolderFuture _charLoginCallback; + QueryCallbackProcessor _queryProcessor; + friend class World; protected: class DosProtection diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 0230ab6d59b..bd5b84f24e3 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -24,6 +24,7 @@ #include "HmacHash.h" #include "Opcodes.h" #include "PacketLog.h" +#include "QueryCallback.h" #include "ScriptMgr.h" #include "SessionKeyGeneration.h" #include "SHA256.h" @@ -91,8 +92,7 @@ void WorldSocket::Start() stmt->setString(0, ip_address); stmt->setUInt32(1, inet_addr(ip_address.c_str())); - _queryCallback = std::bind(&WorldSocket::CheckIpCallback, this, std::placeholders::_1); - _queryFuture = LoginDatabase.AsyncQuery(stmt); + _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::CheckIpCallback, this, std::placeholders::_1))); } void WorldSocket::CheckIpCallback(PreparedQueryResult result) @@ -233,12 +233,7 @@ bool WorldSocket::Update() if (!BaseSocket::Update()) return false; - if (_queryFuture.valid() && _queryFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) - { - auto callback = _queryCallback; - _queryCallback = nullptr; - callback(_queryFuture.get()); - } + _queryProcessor.ProcessReadyQueries(); return true; } @@ -652,8 +647,7 @@ void WorldSocket::HandleAuthSession(std::shared_ptr<WorldPackets::Auth::AuthSess stmt->setInt32(0, int32(realm.Id.Realm)); stmt->setString(1, authSession->RealmJoinTicket); - _queryCallback = std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1); - _queryFuture = LoginDatabase.AsyncQuery(stmt); + _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1))); } void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth::AuthSession> authSession, PreparedQueryResult result) @@ -818,8 +812,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth:: if (wardenActive) _worldSession->InitWarden(&_sessionKey); - _queryCallback = std::bind(&WorldSocket::LoadSessionPermissionsCallback, this, std::placeholders::_1); - _queryFuture = _worldSession->LoadPermissionsAsync(); + _queryProcessor.AddQuery(_worldSession->LoadPermissionsAsync().WithPreparedCallback(std::bind(&WorldSocket::LoadSessionPermissionsCallback, this, std::placeholders::_1))); AsyncRead(); } @@ -848,8 +841,7 @@ void WorldSocket::HandleAuthContinuedSession(std::shared_ptr<WorldPackets::Auth: PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_CONTINUED_SESSION); stmt->setUInt32(0, accountId); - _queryCallback = std::bind(&WorldSocket::HandleAuthContinuedSessionCallback, this, authSession, std::placeholders::_1); - _queryFuture = LoginDatabase.AsyncQuery(stmt); + _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::HandleAuthContinuedSessionCallback, this, authSession, std::placeholders::_1))); } void WorldSocket::HandleAuthContinuedSessionCallback(std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession, PreparedQueryResult result) diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index f257848fac1..1a3e4e71b25 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -20,6 +20,7 @@ #define __WORLDSOCKET_H__ #include "Common.h" +#include "QueryCallbackProcessor.h" #include "WorldPacketCrypt.h" #include "Socket.h" #include "Util.h" @@ -144,8 +145,7 @@ private: z_stream_s* _compressionStream; - PreparedQueryResultFuture _queryFuture; - std::function<void(PreparedQueryResult&&)> _queryCallback; + QueryCallbackProcessor _queryProcessor; std::string _ipCountry; }; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 85fb1db40ac..c2da938cfa8 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -43,6 +43,7 @@ #include "GameEventMgr.h" #include "GameTables.h" #include "GarrisonMgr.h" +#include "GitRevision.h" #include "GridNotifiersImpl.h" #include "GroupMgr.h" #include "GuildFinderMgr.h" @@ -58,7 +59,7 @@ #include "OutdoorPvPMgr.h" #include "Player.h" #include "PoolMgr.h" -#include "GitRevision.h" +#include "QueryCallback.h" #include "ScenarioMgr.h" #include "ScriptMgr.h" #include "ScriptReloadMgr.h" @@ -3055,7 +3056,7 @@ void World::UpdateRealmCharCount(uint32 accountId) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_COUNT); stmt->setUInt32(0, accountId); - m_realmCharCallbacks.push_back(CharacterDatabase.AsyncQuery(stmt)); + _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&World::_UpdateRealmCharCount, this, std::placeholders::_1))); } void World::_UpdateRealmCharCount(PreparedQueryResult resultCharCount) @@ -3459,20 +3460,7 @@ uint32 World::getWorldState(uint32 index) const void World::ProcessQueryCallbacks() { - PreparedQueryResult result; - - for (std::deque<PreparedQueryResultFuture>::iterator itr = m_realmCharCallbacks.begin(); itr != m_realmCharCallbacks.end(); ) - { - if ((*itr).wait_for(std::chrono::seconds(0)) != std::future_status::ready) - { - ++itr; - continue; - } - - result = (*itr).get(); - _UpdateRealmCharCount(result); - itr = m_realmCharCallbacks.erase(itr); - } + _queryProcessor.ProcessReadyQueries(); } /** diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index fa780b81b54..53378f5ff93 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -29,7 +29,7 @@ #include "Timer.h" #include "SharedDefines.h" #include "QueryResult.h" -#include "QueryCallback.h" +#include "QueryCallbackProcessor.h" #include "Realm/Realm.h" #include <atomic> @@ -913,7 +913,7 @@ class TC_GAME_API World void LoadCharacterInfoStore(); void ProcessQueryCallbacks(); - std::deque<PreparedQueryResultFuture> m_realmCharCallbacks; + QueryCallbackProcessor _queryProcessor; }; TC_GAME_API extern Realm realm; |