aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/bnetserver/Server/Session.cpp11
-rw-r--r--src/server/bnetserver/Server/Session.h6
-rw-r--r--src/server/database/Database/DatabaseWorkerPool.cpp9
-rw-r--r--src/server/database/Database/DatabaseWorkerPool.h9
-rw-r--r--src/server/database/Database/QueryCallback.cpp173
-rw-r--r--src/server/database/Database/QueryCallback.h218
-rw-r--r--src/server/database/Database/QueryCallbackProcessor.cpp15
-rw-r--r--src/server/database/Database/QueryCallbackProcessor.h6
-rw-r--r--src/server/game/Accounts/RBAC.cpp3
-rw-r--r--src/server/game/Accounts/RBAC.h2
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp440
-rw-r--r--src/server/game/Handlers/NPCHandler.cpp18
-rw-r--r--src/server/game/Handlers/SocialHandler.cpp9
-rw-r--r--src/server/game/Server/WorldSession.cpp127
-rw-r--r--src/server/game/Server/WorldSession.h36
-rw-r--r--src/server/game/Server/WorldSocket.cpp20
-rw-r--r--src/server/game/Server/WorldSocket.h4
-rw-r--r--src/server/game/World/World.cpp20
-rw-r--r--src/server/game/World/World.h4
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;