diff --git a/src/common/Utilities/AsyncCallbackProcessor.h b/src/common/Utilities/AsyncCallbackProcessor.h
new file mode 100644
index 00000000000..76781f49425
--- /dev/null
+++ b/src/common/Utilities/AsyncCallbackProcessor.h
@@ -0,0 +1,63 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+
+#ifndef AsyncCallbackProcessor_h__
+#define AsyncCallbackProcessor_h__
+
+#include "Define.h"
+#include
+#include
+
+//template
+//concept AsyncCallback = requires(T t) { { t.InvokeIfReady() } -> std::convertible_to };
+
+template // requires AsyncCallback
+class AsyncCallbackProcessor
+{
+public:
+ AsyncCallbackProcessor() = default;
+ ~AsyncCallbackProcessor() = default;
+
+ T& AddCallback(T&& query)
+ {
+ _callbacks.emplace_back(std::move(query));
+ return _callbacks.back();
+ }
+
+ void ProcessReadyCallbacks()
+ {
+ if (_callbacks.empty())
+ return;
+
+ std::vector updateCallbacks{ std::move(_callbacks) };
+
+ updateCallbacks.erase(std::remove_if(updateCallbacks.begin(), updateCallbacks.end(), [](T& callback)
+ {
+ return callback.InvokeIfReady();
+ }), updateCallbacks.end());
+
+ _callbacks.insert(_callbacks.end(), std::make_move_iterator(updateCallbacks.begin()), std::make_move_iterator(updateCallbacks.end()));
+ }
+
+private:
+ AsyncCallbackProcessor(AsyncCallbackProcessor const&) = delete;
+ AsyncCallbackProcessor& operator=(AsyncCallbackProcessor const&) = delete;
+
+ std::vector _callbacks;
+};
+
+#endif // AsyncCallbackProcessor_h__
diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp
index 8a619a80263..d2a8dae7e26 100644
--- a/src/server/bnetserver/Server/Session.cpp
+++ b/src/server/bnetserver/Server/Session.cpp
@@ -199,7 +199,7 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const&
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO);
stmt->setString(0, login);
- _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::HandleLogonRequestCallback, this, std::placeholders::_1)));
+ _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::HandleLogonRequestCallback, this, std::placeholders::_1)));
}
void Battlenet::Session::HandleLogonRequestCallback(PreparedQueryResult result)
@@ -338,7 +338,7 @@ void Battlenet::Session::HandleResumeRequest(Authentication::ResumeRequest const
stmt->setString(0, login);
stmt->setString(1, resumeRequest.GameAccountName);
- _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::HandleResumeRequestCallback, this, std::placeholders::_1)));
+ _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::HandleResumeRequestCallback, this, std::placeholders::_1)));
}
void Battlenet::Session::HandleResumeRequestCallback(PreparedQueryResult result)
@@ -437,7 +437,7 @@ void Battlenet::Session::HandleListSubscribeRequest(WoWRealm::ListSubscribeReque
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS);
stmt->setUInt32(0, _gameAccountInfo->Id);
- _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::HandleListSubscribeRequestCallback, this, std::placeholders::_1)));
+ _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::HandleListSubscribeRequestCallback, this, std::placeholders::_1)));
}
void Battlenet::Session::HandleListSubscribeRequestCallback(PreparedQueryResult result)
@@ -609,7 +609,7 @@ void Battlenet::Session::Start()
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO);
stmt->setString(0, ip_address);
- _queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::CheckIpCallback, this, std::placeholders::_1)));
+ _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::CheckIpCallback, this, std::placeholders::_1)));
}
void Battlenet::Session::CheckIpCallback(PreparedQueryResult result)
@@ -671,7 +671,7 @@ bool Battlenet::Session::Update()
if (!BattlenetSocket::Update())
return false;
- _queryProcessor.ProcessReadyQueries();
+ _queryProcessor.ProcessReadyCallbacks();
return true;
}
diff --git a/src/server/bnetserver/Server/Session.h b/src/server/bnetserver/Server/Session.h
index f42c15948c5..e489208ee6c 100644
--- a/src/server/bnetserver/Server/Session.h
+++ b/src/server/bnetserver/Server/Session.h
@@ -18,12 +18,12 @@
#ifndef Session_h__
#define Session_h__
+#include "AsyncCallbackProcessor.h"
#include "Packets.h"
#include "BattlenetPacketCrypt.h"
#include "Socket.h"
#include "BigNumber.h"
#include "QueryResult.h"
-#include "QueryCallbackProcessor.h"
#include "MPSCQueue.h"
#include
#include
diff --git a/src/server/database/Database/DatabaseEnvFwd.h b/src/server/database/Database/DatabaseEnvFwd.h
index b743c88506d..e981be5c026 100644
--- a/src/server/database/Database/DatabaseEnvFwd.h
+++ b/src/server/database/Database/DatabaseEnvFwd.h
@@ -24,9 +24,9 @@
class Field;
class ResultSet;
-typedef std::shared_ptr QueryResult;
-typedef std::future QueryResultFuture;
-typedef std::promise QueryResultPromise;
+using QueryResult = std::shared_ptr;
+using QueryResultFuture = std::future;
+using QueryResultPromise = std::promise;
class CharacterDatabaseConnection;
class HotfixDatabaseConnection;
@@ -44,17 +44,27 @@ using LoginDatabasePreparedStatement = PreparedStatement;
class PreparedResultSet;
-typedef std::shared_ptr PreparedQueryResult;
-typedef std::future PreparedQueryResultFuture;
-typedef std::promise PreparedQueryResultPromise;
+using PreparedQueryResult = std::shared_ptr;
+using PreparedQueryResultFuture = std::future;
+using PreparedQueryResultPromise = std::promise;
class QueryCallback;
+template
+class AsyncCallbackProcessor;
+
+using QueryCallbackProcessor = AsyncCallbackProcessor;
+
class TransactionBase;
+using TransactionFuture = std::future;
+using TransactionPromise = std::promise;
+
template
class Transaction;
+class TransactionCallback;
+
template
using SQLTransaction = std::shared_ptr>;
@@ -64,8 +74,8 @@ using LoginDatabaseTransaction = SQLTransaction;
using WorldDatabaseTransaction = SQLTransaction;
class SQLQueryHolderBase;
-typedef std::future QueryResultHolderFuture;
-typedef std::promise QueryResultHolderPromise;
+using QueryResultHolderFuture = std::future;
+using QueryResultHolderPromise = std::promise;
template
class SQLQueryHolder;
diff --git a/src/server/database/Database/DatabaseWorkerPool.cpp b/src/server/database/Database/DatabaseWorkerPool.cpp
index d909949c12c..f701a7c527b 100644
--- a/src/server/database/Database/DatabaseWorkerPool.cpp
+++ b/src/server/database/Database/DatabaseWorkerPool.cpp
@@ -261,6 +261,32 @@ void DatabaseWorkerPool::CommitTransaction(SQLTransaction transaction)
Enqueue(new TransactionTask(transaction));
}
+template
+TransactionCallback DatabaseWorkerPool::AsyncCommitTransaction(SQLTransaction transaction)
+{
+#ifdef TRINITY_DEBUG
+ //! Only analyze transaction weaknesses in Debug mode.
+ //! Ideally we catch the faults in Debug mode and then correct them,
+ //! so there's no need to waste these CPU cycles in Release mode.
+ switch (transaction->GetSize())
+ {
+ case 0:
+ TC_LOG_DEBUG("sql.driver", "Transaction contains 0 queries. Not executing.");
+ return;
+ case 1:
+ TC_LOG_DEBUG("sql.driver", "Warning: Transaction only holds 1 query, consider removing Transaction context in code.");
+ break;
+ default:
+ break;
+ }
+#endif // TRINITY_DEBUG
+
+ TransactionWithResultTask* task = new TransactionWithResultTask(transaction);
+ TransactionFuture result = task->GetFuture();
+ Enqueue(task);
+ return TransactionCallback(std::move(result));
+}
+
template
void DatabaseWorkerPool::DirectCommitTransaction(SQLTransaction& transaction)
{
diff --git a/src/server/database/Database/DatabaseWorkerPool.h b/src/server/database/Database/DatabaseWorkerPool.h
index 8824dc38d85..f72817c3a8f 100644
--- a/src/server/database/Database/DatabaseWorkerPool.h
+++ b/src/server/database/Database/DatabaseWorkerPool.h
@@ -173,6 +173,10 @@ class DatabaseWorkerPool
//! were appended to the transaction will be respected during execution.
void CommitTransaction(SQLTransaction transaction);
+ //! Enqueues a collection of one-way SQL operations (can be both adhoc and prepared). The order in which these operations
+ //! were appended to the transaction will be respected during execution.
+ TransactionCallback AsyncCommitTransaction(SQLTransaction transaction);
+
//! Directly executes a collection of one-way SQL operations (can be both adhoc and prepared). The order in which these operations
//! were appended to the transaction will be respected during execution.
void DirectCommitTransaction(SQLTransaction& transaction);
diff --git a/src/server/database/Database/QueryCallback.cpp b/src/server/database/Database/QueryCallback.cpp
index 65b52ff7627..02365a76fe7 100644
--- a/src/server/database/Database/QueryCallback.cpp
+++ b/src/server/database/Database/QueryCallback.cpp
@@ -175,7 +175,7 @@ void QueryCallback::SetNextQuery(QueryCallback&& next)
MoveFrom(this, std::move(next));
}
-QueryCallback::Status QueryCallback::InvokeIfReady()
+bool QueryCallback::InvokeIfReady()
{
QueryCallbackData& callback = _callbacks.front();
auto checkStateAndReturnCompletion = [this]()
@@ -185,15 +185,15 @@ QueryCallback::Status QueryCallback::InvokeIfReady()
if (_callbacks.empty())
{
ASSERT(!hasNext);
- return Completed;
+ return true;
}
// abort chain
if (!hasNext)
- return Completed;
+ return true;
ASSERT(_isPrepared == _callbacks.front()._isPrepared);
- return NextStep;
+ return false;
};
if (!_isPrepared)
@@ -217,5 +217,5 @@ QueryCallback::Status QueryCallback::InvokeIfReady()
}
}
- return NotReady;
+ return false;
}
diff --git a/src/server/database/Database/QueryCallback.h b/src/server/database/Database/QueryCallback.h
index 1d7e835e999..6cc315964b7 100644
--- a/src/server/database/Database/QueryCallback.h
+++ b/src/server/database/Database/QueryCallback.h
@@ -44,14 +44,8 @@ public:
// Moves std::future from next to this object
void SetNextQuery(QueryCallback&& next);
- enum Status
- {
- NotReady,
- NextStep,
- Completed
- };
-
- Status InvokeIfReady();
+ // returns true when completed
+ bool InvokeIfReady();
private:
QueryCallback(QueryCallback const& right) = delete;
diff --git a/src/server/database/Database/QueryCallbackProcessor.cpp b/src/server/database/Database/QueryCallbackProcessor.cpp
deleted file mode 100644
index 546a6d17c04..00000000000
--- a/src/server/database/Database/QueryCallbackProcessor.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see .
- */
-
-#include "QueryCallbackProcessor.h"
-#include "QueryCallback.h"
-#include
-
-QueryCallbackProcessor::QueryCallbackProcessor()
-{
-}
-
-QueryCallbackProcessor::~QueryCallbackProcessor()
-{
-}
-
-void QueryCallbackProcessor::AddQuery(QueryCallback&& query)
-{
- _callbacks.emplace_back(std::move(query));
-}
-
-void QueryCallbackProcessor::ProcessReadyQueries()
-{
- if (_callbacks.empty())
- return;
-
- std::vector updateCallbacks{ std::move(_callbacks) };
-
- updateCallbacks.erase(std::remove_if(updateCallbacks.begin(), updateCallbacks.end(), [](QueryCallback& callback)
- {
- 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
deleted file mode 100644
index 85596e90092..00000000000
--- a/src/server/database/Database/QueryCallbackProcessor.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see .
- */
-
-#ifndef QueryCallbackProcessor_h__
-#define QueryCallbackProcessor_h__
-
-#include "Define.h"
-#include
-
-class QueryCallback;
-
-class TC_DATABASE_API QueryCallbackProcessor
-{
-public:
- QueryCallbackProcessor();
- ~QueryCallbackProcessor();
-
- void AddQuery(QueryCallback&& query);
- void ProcessReadyQueries();
-
-private:
- QueryCallbackProcessor(QueryCallbackProcessor const&) = delete;
- QueryCallbackProcessor& operator=(QueryCallbackProcessor const&) = delete;
-
- std::vector _callbacks;
-};
-
-#endif // QueryCallbackProcessor_h__
diff --git a/src/server/database/Database/Transaction.cpp b/src/server/database/Database/Transaction.cpp
index e114808ddf0..afa107f31c7 100644
--- a/src/server/database/Database/Transaction.cpp
+++ b/src/server/database/Database/Transaction.cpp
@@ -70,7 +70,7 @@ void TransactionBase::Cleanup()
bool TransactionTask::Execute()
{
- int errorCode = m_conn->ExecuteTransaction(m_trans);
+ int errorCode = TryExecute();
if (!errorCode)
return true;
@@ -85,7 +85,7 @@ bool TransactionTask::Execute()
for (uint32 loopDuration = 0, startMSTime = getMSTime(); loopDuration <= DEADLOCK_MAX_RETRY_TIME_MS; loopDuration = GetMSTimeDiffToNow(startMSTime))
{
- if (!m_conn->ExecuteTransaction(m_trans))
+ if (!TryExecute())
return true;
TC_LOG_WARN("sql.sql", "Deadlocked SQL Transaction, retrying. Loop timer: %u ms, Thread Id: %s", loopDuration, threadId.c_str());
@@ -95,7 +95,60 @@ bool TransactionTask::Execute()
}
// Clean up now.
- m_trans->Cleanup();
+ CleanupOnFailure();
return false;
}
+
+int TransactionTask::TryExecute()
+{
+ return m_conn->ExecuteTransaction(m_trans);
+}
+
+void TransactionTask::CleanupOnFailure()
+{
+ m_trans->Cleanup();
+}
+
+bool TransactionWithResultTask::Execute()
+{
+ int errorCode = TryExecute();
+ if (!errorCode)
+ {
+ m_result.set_value(true);
+ return true;
+ }
+
+ if (errorCode == ER_LOCK_DEADLOCK)
+ {
+ // Make sure only 1 async thread retries a transaction so they don't keep dead-locking each other
+ std::lock_guard lock(_deadlockLock);
+ uint8 loopBreaker = 5; // Handle MySQL Errno 1213 without extending deadlock to the core itself
+ for (uint8 i = 0; i < loopBreaker; ++i)
+ {
+ if (!TryExecute())
+ {
+ m_result.set_value(true);
+ return true;
+ }
+ }
+ }
+
+ // Clean up now.
+ CleanupOnFailure();
+ m_result.set_value(false);
+
+ return false;
+}
+
+bool TransactionCallback::InvokeIfReady()
+{
+ if (m_future.valid() && m_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
+ {
+ m_callback(m_future.get());
+ return true;
+ }
+
+ return false;
+}
+
diff --git a/src/server/database/Database/Transaction.h b/src/server/database/Database/Transaction.h
index dac9880d53b..a8e3f511f3d 100644
--- a/src/server/database/Database/Transaction.h
+++ b/src/server/database/Database/Transaction.h
@@ -22,6 +22,7 @@
#include "DatabaseEnvFwd.h"
#include "SQLOperation.h"
#include "StringFormat.h"
+#include
#include
#include
@@ -73,6 +74,7 @@ class TC_DATABASE_API TransactionTask : public SQLOperation
{
template friend class DatabaseWorkerPool;
friend class DatabaseWorker;
+ friend class TransactionCallback;
public:
TransactionTask(std::shared_ptr trans) : m_trans(trans) { }
@@ -80,9 +82,43 @@ class TC_DATABASE_API TransactionTask : public SQLOperation
protected:
bool Execute() override;
+ int TryExecute();
+ void CleanupOnFailure();
std::shared_ptr m_trans;
static std::mutex _deadlockLock;
};
+class TC_DATABASE_API TransactionWithResultTask : public TransactionTask
+{
+public:
+ TransactionWithResultTask(std::shared_ptr trans) : TransactionTask(trans) { }
+
+ TransactionFuture GetFuture() { return m_result.get_future(); }
+
+protected:
+ bool Execute() override;
+
+ TransactionPromise m_result;
+};
+
+class TC_DATABASE_API TransactionCallback
+{
+public:
+ TransactionCallback(TransactionFuture&& future) : m_future(std::move(future)) { }
+ TransactionCallback(TransactionCallback&&) = default;
+
+ TransactionCallback& operator=(TransactionCallback&&) = default;
+
+ void AfterComplete(std::function callback) &
+ {
+ m_callback = std::move(callback);
+ }
+
+ bool InvokeIfReady();
+
+ TransactionFuture m_future;
+ std::function m_callback;
+};
+
#endif
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 4f7b8836f3b..c1290dde422 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -27172,7 +27172,7 @@ void Player::ActivateSpec(uint8 spec)
stmt->setUInt8(1, GetActiveSpec());
WorldSession* mySess = GetSession();
- mySess->GetQueryProcessor().AddQuery(CharacterDatabase.AsyncQuery(stmt)
+ mySess->GetQueryProcessor().AddCallback(CharacterDatabase.AsyncQuery(stmt)
.WithPreparedCallback([mySess](PreparedQueryResult result)
{
// safe callback, we can't pass this pointer directly
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index e0c8002c522..ee2da03a323 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -308,7 +308,7 @@ void WorldSession::HandleCharEnumOpcode(WorldPackets::Character::EnumCharacters&
stmt->setUInt32(0, GetAccountId());
- _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleCharEnum, this, std::placeholders::_1)));
+ _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleCharEnum, this, std::placeholders::_1)));
}
void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData)
@@ -445,7 +445,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData)
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME);
stmt->setString(0, createInfo->Name);
- _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt)
+ _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt)
.WithChainingPreparedCallback([this](QueryCallback& queryCallback, PreparedQueryResult result)
{
if (result)
@@ -1282,7 +1282,7 @@ void WorldSession::HandleCharRenameOpcode(WorldPacket& recvData)
stmt->setUInt32(1, GetAccountId());
stmt->setString(2, renameInfo->Name);
- _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt)
+ _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt)
.WithPreparedCallback(std::bind(&WorldSession::HandleCharRenameCallback, this, renameInfo, std::placeholders::_1)));
}
@@ -1527,7 +1527,7 @@ void WorldSession::HandleCharCustomize(WorldPacket& recvData)
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_CUSTOMIZE_INFO);
stmt->setUInt32(0, customizeInfo->Guid.GetCounter());
- _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt)
+ _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt)
.WithPreparedCallback(std::bind(&WorldSession::HandleCharCustomizeCallback, this, customizeInfo, std::placeholders::_1)));
}
@@ -1783,7 +1783,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData)
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_RACE_OR_FACTION_CHANGE_INFOS);
stmt->setUInt32(0, factionChangeInfo->Guid.GetCounter());
- _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt)
+ _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt)
.WithPreparedCallback(std::bind(&WorldSession::HandleCharFactionOrRaceChangeCallback, this, factionChangeInfo, std::placeholders::_1)));
}
diff --git a/src/server/game/Handlers/GuildHandler.cpp b/src/server/game/Handlers/GuildHandler.cpp
index eedbe7a575a..965983002eb 100644
--- a/src/server/game/Handlers/GuildHandler.cpp
+++ b/src/server/game/Handlers/GuildHandler.cpp
@@ -886,7 +886,7 @@ void WorldSession::HandleGuildRenameRequest(WorldPacket& recvPacket)
stmt->setUInt32(1, pGuild->GetId());
stmt->setString(0, newName);
- _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleGuildRenameCallback, this, newName, std::placeholders::_1)));
+ _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSession::HandleGuildRenameCallback, this, newName, std::placeholders::_1)));
WorldPacket data(SMSG_GUILD_FLAGGED_FOR_RENAME,1);
diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp
index a23b155bd4a..7923e4d837e 100644
--- a/src/server/game/Handlers/SpellHandler.cpp
+++ b/src/server/game/Handlers/SpellHandler.cpp
@@ -268,7 +268,7 @@ void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket)
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GIFT_BY_ITEM);
stmt->setUInt32(0, item->GetGUID().GetCounter());
- _queryProcessor.AddQuery(CharacterDatabase.AsyncQuery(stmt)
+ _queryProcessor.AddCallback(CharacterDatabase.AsyncQuery(stmt)
.WithPreparedCallback(std::bind(&WorldSession::HandleOpenWrappedItemCallback, this, item->GetPos(), item->GetGUID(), std::placeholders::_1)));
}
else
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index 21f10a2aa87..a1af493ded4 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -244,7 +244,7 @@ void WorldSession::SendPacket(WorldPacket const* packet, bool forced /*= false*/
{
if (packet->GetConnection() != CONNECTION_TYPE_INSTANCE && IsInstanceOnlyOpcode(packet->GetOpcode()))
{
- TC_LOG_ERROR("network.opcode", "Prevented sending of instance only opcode %u with connection type %u to %s", packet->GetOpcode(), packet->GetConnection(), GetPlayerInfo().c_str());
+ TC_LOG_ERROR("network.opcode", "Prevented sending of instance only opcode %u with connection type %u to %s", packet->GetOpcode(), uint32(packet->GetConnection()), GetPlayerInfo().c_str());
return;
}
@@ -253,7 +253,7 @@ void WorldSession::SendPacket(WorldPacket const* packet, bool forced /*= false*/
if (!m_Socket[conIdx])
{
- TC_LOG_ERROR("network.opcode", "Prevented sending of %s to non existent socket %u to %s", GetOpcodeNameForLogging(static_cast(packet->GetOpcode())).c_str(), conIdx, GetPlayerInfo().c_str());
+ TC_LOG_ERROR("network.opcode", "Prevented sending of %s to non existent socket %u to %s", GetOpcodeNameForLogging(static_cast(packet->GetOpcode())).c_str(), uint32(conIdx), GetPlayerInfo().c_str());
return;
}
@@ -1122,7 +1122,8 @@ void WorldSession::SetPlayer(Player* player)
void WorldSession::ProcessQueryCallbacks()
{
- _queryProcessor.ProcessReadyQueries();
+ _queryProcessor.ProcessReadyCallbacks();
+ _transactionCallbacks.ProcessReadyCallbacks();
if (_realmAccountLoginCallback.valid() && _realmAccountLoginCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
InitializeSessionCallback(static_cast(_realmAccountLoginCallback.get()));
@@ -1132,6 +1133,11 @@ void WorldSession::ProcessQueryCallbacks()
HandlePlayerLogin(reinterpret_cast(_charLoginCallback.get()));
}
+TransactionCallback& WorldSession::AddTransactionCallback(TransactionCallback&& callback)
+{
+ return _transactionCallbacks.AddCallback(std::move(callback));
+}
+
void WorldSession::InitWarden(BigNumber* k, std::string const& os)
{
if (os == "Win")
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index 284c2030370..5c29dc40c05 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -23,11 +23,11 @@
#define __WORLDSESSION_H
#include "Common.h"
+#include "AsyncCallbackProcessor.h"
#include "DatabaseEnvFwd.h"
#include "LockedQueue.h"
#include "ObjectGuid.h"
#include "Packet.h"
-#include "QueryCallbackProcessor.h"
#include "SharedDefines.h"
#include